github.com/xrash/gopher-lua@v0.0.0-20160304065408-e5faab4db06a/baselib.go (about)

     1  package lua
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  /* basic functions {{{ */
    13  
    14  func OpenBase(L *LState) int {
    15  	global := L.Get(GlobalsIndex).(*LTable)
    16  	L.SetGlobal("_G", global)
    17  	L.SetGlobal("_VERSION", LString(PackageName+" "+PackageVersion))
    18  	basemod := L.RegisterModule("_G", baseFuncs)
    19  	global.RawSetString("ipairs", L.NewClosure(baseIpairs, L.NewFunction(ipairsaux)))
    20  	global.RawSetString("pairs", L.NewClosure(basePairs, L.NewFunction(pairsaux)))
    21  	L.Push(basemod)
    22  	return 1
    23  }
    24  
    25  var baseFuncs = map[string]LGFunction{
    26  	"assert":         baseAssert,
    27  	"collectgarbage": baseCollectGarbage,
    28  	"dofile":         baseDoFile,
    29  	"error":          baseError,
    30  	"getfenv":        baseGetFEnv,
    31  	"getmetatable":   baseGetMetatable,
    32  	"load":           baseLoad,
    33  	"loadfile":       baseLoadFile,
    34  	"loadstring":     baseLoadString,
    35  	"next":           baseNext,
    36  	"pcall":          basePCall,
    37  	"print":          basePrint,
    38  	"rawequal":       baseRawEqual,
    39  	"rawget":         baseRawGet,
    40  	"rawset":         baseRawSet,
    41  	"select":         baseSelect,
    42  	"_printregs":     base_PrintRegs,
    43  	"setfenv":        baseSetFEnv,
    44  	"setmetatable":   baseSetMetatable,
    45  	"tonumber":       baseToNumber,
    46  	"tostring":       baseToString,
    47  	"type":           baseType,
    48  	"unpack":         baseUnpack,
    49  	"xpcall":         baseXPCall,
    50  	// loadlib
    51  	"module":  loModule,
    52  	"require": loRequire,
    53  }
    54  
    55  func baseAssert(L *LState) int {
    56  	if !L.ToBool(1) {
    57  		L.RaiseError(L.OptString(2, "assertion failed!"))
    58  		return 0
    59  	}
    60  	return L.GetTop()
    61  }
    62  
    63  func baseCollectGarbage(L *LState) int {
    64  	runtime.GC()
    65  	return 0
    66  }
    67  
    68  func baseDoFile(L *LState) int {
    69  	src := L.ToString(1)
    70  	top := L.GetTop()
    71  	if err := L.DoFile(src); err != nil {
    72  		L.RaiseError(err.Error())
    73  	}
    74  	return L.GetTop() - top
    75  }
    76  
    77  func baseError(L *LState) int {
    78  	obj := L.CheckAny(1)
    79  	level := L.OptInt(2, 1)
    80  	L.Error(obj, level)
    81  	return 0
    82  }
    83  
    84  func baseGetFEnv(L *LState) int {
    85  	var value LValue
    86  	if L.GetTop() == 0 {
    87  		value = LNumber(1)
    88  	} else {
    89  		value = L.Get(1)
    90  	}
    91  
    92  	if fn, ok := value.(*LFunction); ok {
    93  		if !fn.IsG {
    94  			L.Push(fn.Env)
    95  		} else {
    96  			L.Push(L.G.Global)
    97  		}
    98  		return 1
    99  	}
   100  
   101  	if number, ok := value.(LNumber); ok {
   102  		level := int(float64(number))
   103  		if level <= 0 {
   104  			L.Push(L.Env)
   105  		} else {
   106  			cf := L.currentFrame
   107  			for i := 0; i < level && cf != nil; i++ {
   108  				cf = cf.Parent
   109  			}
   110  			if cf == nil || cf.Fn.IsG {
   111  				L.Push(L.G.Global)
   112  			} else {
   113  				L.Push(cf.Fn.Env)
   114  			}
   115  		}
   116  		return 1
   117  	}
   118  
   119  	L.Push(L.G.Global)
   120  	return 1
   121  }
   122  
   123  func baseGetMetatable(L *LState) int {
   124  	L.Push(L.GetMetatable(L.CheckAny(1)))
   125  	return 1
   126  }
   127  
   128  func ipairsaux(L *LState) int {
   129  	tb := L.CheckTable(1)
   130  	i := L.CheckInt(2)
   131  	i++
   132  	v := tb.RawGetInt(i)
   133  	if v == LNil {
   134  		return 0
   135  	} else {
   136  		L.Pop(1)
   137  		L.Push(LNumber(i))
   138  		L.Push(LNumber(i))
   139  		L.Push(v)
   140  		return 2
   141  	}
   142  }
   143  
   144  func baseIpairs(L *LState) int {
   145  	tb := L.CheckTable(1)
   146  	L.Push(L.Get(UpvalueIndex(1)))
   147  	L.Push(tb)
   148  	L.Push(LNumber(0))
   149  	return 3
   150  }
   151  
   152  func loadaux(L *LState, reader io.Reader, chunkname string) int {
   153  	if fn, err := L.Load(reader, chunkname); err != nil {
   154  		L.Push(LNil)
   155  		L.Push(LString(err.Error()))
   156  		return 2
   157  	} else {
   158  		L.Push(fn)
   159  		return 1
   160  	}
   161  }
   162  
   163  func baseLoad(L *LState) int {
   164  	fn := L.CheckFunction(1)
   165  	chunkname := L.OptString(2, "?")
   166  	top := L.GetTop()
   167  	buf := []string{}
   168  	for {
   169  		L.SetTop(top)
   170  		L.Push(fn)
   171  		L.Call(0, 1)
   172  		ret := L.reg.Pop()
   173  		if ret == LNil {
   174  			break
   175  		} else if LVCanConvToString(ret) {
   176  			str := ret.String()
   177  			if len(str) > 0 {
   178  				buf = append(buf, string(str))
   179  			} else {
   180  				break
   181  			}
   182  		} else {
   183  			L.Push(LNil)
   184  			L.Push(LString("reader function must return a string"))
   185  			return 2
   186  		}
   187  	}
   188  	return loadaux(L, strings.NewReader(strings.Join(buf, "")), chunkname)
   189  }
   190  
   191  func baseLoadFile(L *LState) int {
   192  	var reader io.Reader
   193  	var chunkname string
   194  	var err error
   195  	if L.GetTop() < 1 {
   196  		reader = os.Stdin
   197  		chunkname = "<stdin>"
   198  	} else {
   199  		chunkname = L.CheckString(1)
   200  		reader, err = os.Open(chunkname)
   201  		if err != nil {
   202  			L.Push(LNil)
   203  			L.Push(LString(fmt.Sprintf("can not open file: %v", chunkname)))
   204  			return 2
   205  		}
   206  		defer reader.(*os.File).Close()
   207  	}
   208  	return loadaux(L, reader, chunkname)
   209  }
   210  
   211  func baseLoadString(L *LState) int {
   212  	return loadaux(L, strings.NewReader(L.CheckString(1)), L.OptString(2, "<string>"))
   213  }
   214  
   215  func baseNext(L *LState) int {
   216  	tb := L.CheckTable(1)
   217  	index := LNil
   218  	if L.GetTop() >= 2 {
   219  		index = L.Get(2)
   220  	}
   221  	key, value := tb.Next(index)
   222  	if key == LNil {
   223  		L.Push(LNil)
   224  		return 1
   225  	}
   226  	L.Push(key)
   227  	L.Push(value)
   228  	return 2
   229  }
   230  
   231  func pairsaux(L *LState) int {
   232  	tb := L.CheckTable(1)
   233  	key, value := tb.Next(L.Get(2))
   234  	if key == LNil {
   235  		return 0
   236  	} else {
   237  		L.Pop(1)
   238  		L.Push(key)
   239  		L.Push(key)
   240  		L.Push(value)
   241  		return 2
   242  	}
   243  }
   244  
   245  func basePairs(L *LState) int {
   246  	tb := L.CheckTable(1)
   247  	L.Push(L.Get(UpvalueIndex(1)))
   248  	L.Push(tb)
   249  	L.Push(LNil)
   250  	return 3
   251  }
   252  
   253  func basePCall(L *LState) int {
   254  	L.CheckFunction(1)
   255  	nargs := L.GetTop() - 1
   256  	if err := L.PCall(nargs, MultRet, nil); err != nil {
   257  		L.Push(LFalse)
   258  		if aerr, ok := err.(*ApiError); ok {
   259  			L.Push(aerr.Object)
   260  		} else {
   261  			L.Push(LString(err.Error()))
   262  		}
   263  		return 2
   264  	} else {
   265  		L.Insert(LTrue, 1)
   266  		return L.GetTop()
   267  	}
   268  }
   269  
   270  func basePrint(L *LState) int {
   271  	top := L.GetTop()
   272  	for i := 1; i <= top; i++ {
   273  		fmt.Print(L.ToStringMeta(L.Get(i)).String())
   274  		if i != top {
   275  			fmt.Print("\t")
   276  		}
   277  	}
   278  	fmt.Println("")
   279  	return 0
   280  }
   281  
   282  func base_PrintRegs(L *LState) int {
   283  	L.printReg()
   284  	return 0
   285  }
   286  
   287  func baseRawEqual(L *LState) int {
   288  	if L.CheckAny(1) == L.CheckAny(2) {
   289  		L.Push(LTrue)
   290  	} else {
   291  		L.Push(LFalse)
   292  	}
   293  	return 1
   294  }
   295  
   296  func baseRawGet(L *LState) int {
   297  	L.Push(L.RawGet(L.CheckTable(1), L.CheckAny(2)))
   298  	return 1
   299  }
   300  
   301  func baseRawSet(L *LState) int {
   302  	L.RawSet(L.CheckTable(1), L.CheckAny(2), L.CheckAny(3))
   303  	return 0
   304  }
   305  
   306  func baseSelect(L *LState) int {
   307  	L.CheckTypes(1, LTNumber, LTString)
   308  	switch lv := L.Get(1).(type) {
   309  	case LNumber:
   310  		idx := int(lv)
   311  		num := L.reg.Top() - L.indexToReg(int(lv)) - 1
   312  		if idx < 0 {
   313  			num++
   314  		}
   315  		return num
   316  	case LString:
   317  		if string(lv) != "#" {
   318  			L.ArgError(1, "invalid string '"+string(lv)+"'")
   319  		}
   320  		L.Push(LNumber(L.GetTop() - 1))
   321  		return 1
   322  	}
   323  	return 0
   324  }
   325  
   326  func baseSetFEnv(L *LState) int {
   327  	var value LValue
   328  	if L.GetTop() == 0 {
   329  		value = LNumber(1)
   330  	} else {
   331  		value = L.Get(1)
   332  	}
   333  	env := L.CheckTable(2)
   334  
   335  	if fn, ok := value.(*LFunction); ok {
   336  		if fn.IsG {
   337  			L.RaiseError("cannot change the environment of given object")
   338  		} else {
   339  			fn.Env = env
   340  			L.Push(fn)
   341  			return 1
   342  		}
   343  	}
   344  
   345  	if number, ok := value.(LNumber); ok {
   346  		level := int(float64(number))
   347  		if level <= 0 {
   348  			L.Env = env
   349  			return 0
   350  		}
   351  
   352  		cf := L.currentFrame
   353  		for i := 0; i < level && cf != nil; i++ {
   354  			cf = cf.Parent
   355  		}
   356  		if cf == nil || cf.Fn.IsG {
   357  			L.RaiseError("cannot change the environment of given object")
   358  		} else {
   359  			cf.Fn.Env = env
   360  			L.Push(cf.Fn)
   361  			return 1
   362  		}
   363  	}
   364  
   365  	L.RaiseError("cannot change the environment of given object")
   366  	return 0
   367  }
   368  
   369  func baseSetMetatable(L *LState) int {
   370  	L.CheckTypes(2, LTNil, LTTable)
   371  	obj := L.Get(1)
   372  	if obj == LNil {
   373  		L.RaiseError("cannot set metatable to a nil object.")
   374  	}
   375  	mt := L.Get(2)
   376  	if m := L.metatable(obj, true); m != LNil {
   377  		if tb, ok := m.(*LTable); ok && tb.RawGetString("__metatable") != LNil {
   378  			L.RaiseError("cannot change a protected metatable")
   379  		}
   380  	}
   381  	L.SetMetatable(obj, mt)
   382  	L.SetTop(1)
   383  	return 1
   384  }
   385  
   386  func baseToNumber(L *LState) int {
   387  	base := L.OptInt(2, 10)
   388  	switch lv := L.CheckAny(1).(type) {
   389  	case LNumber:
   390  		L.Push(lv)
   391  	case LString:
   392  		str := strings.Trim(string(lv), " \n\t")
   393  		if strings.Index(str, ".") > -1 {
   394  			if v, err := strconv.ParseFloat(str, LNumberBit); err != nil {
   395  				L.Push(LNil)
   396  			} else {
   397  				L.Push(LNumber(v))
   398  			}
   399  		} else {
   400  			if v, err := strconv.ParseInt(str, base, LNumberBit); err != nil {
   401  				L.Push(LNil)
   402  			} else {
   403  				L.Push(LNumber(v))
   404  			}
   405  		}
   406  	default:
   407  		L.Push(LNil)
   408  	}
   409  	return 1
   410  }
   411  
   412  func baseToString(L *LState) int {
   413  	v1 := L.CheckAny(1)
   414  	L.Push(L.ToStringMeta(v1))
   415  	return 1
   416  }
   417  
   418  func baseType(L *LState) int {
   419  	L.Push(LString(L.CheckAny(1).Type().String()))
   420  	return 1
   421  }
   422  
   423  func baseUnpack(L *LState) int {
   424  	tb := L.CheckTable(1)
   425  	start := L.OptInt(2, 1)
   426  	end := L.OptInt(3, tb.Len())
   427  	for i := start; i <= end; i++ {
   428  		L.Push(tb.RawGetInt(i))
   429  	}
   430  	ret := end - start + 1
   431  	if ret < 0 {
   432  		return 0
   433  	}
   434  	return ret
   435  }
   436  
   437  func baseXPCall(L *LState) int {
   438  	fn := L.CheckFunction(1)
   439  	errfunc := L.CheckFunction(2)
   440  
   441  	top := L.GetTop()
   442  	L.Push(fn)
   443  	if err := L.PCall(0, MultRet, errfunc); err != nil {
   444  		L.Push(LFalse)
   445  		if aerr, ok := err.(*ApiError); ok {
   446  			L.Push(aerr.Object)
   447  		} else {
   448  			L.Push(LString(err.Error()))
   449  		}
   450  		return 2
   451  	} else {
   452  		L.Insert(LTrue, top+1)
   453  		return L.GetTop() - top
   454  	}
   455  }
   456  
   457  /* }}} */
   458  
   459  /* load lib {{{ */
   460  
   461  func loModule(L *LState) int {
   462  	name := L.CheckString(1)
   463  	loaded := L.GetField(L.Get(RegistryIndex), "_LOADED")
   464  	tb := L.GetField(loaded, name)
   465  	if _, ok := tb.(*LTable); !ok {
   466  		tb = L.FindTable(L.Get(GlobalsIndex).(*LTable), name, 1)
   467  		if tb == LNil {
   468  			L.RaiseError("name conflict for module: %v", name)
   469  		}
   470  		L.SetField(loaded, name, tb)
   471  	}
   472  	if L.GetField(tb, "_NAME") == LNil {
   473  		L.SetField(tb, "_M", tb)
   474  		L.SetField(tb, "_NAME", LString(name))
   475  		names := strings.Split(name, ".")
   476  		pname := ""
   477  		if len(names) > 1 {
   478  			pname = strings.Join(names[:len(names)-1], ".") + "."
   479  		}
   480  		L.SetField(tb, "_PACKAGE", LString(pname))
   481  	}
   482  
   483  	caller := L.currentFrame.Parent
   484  	if caller == nil {
   485  		L.RaiseError("no calling stack.")
   486  	} else if caller.Fn.IsG {
   487  		L.RaiseError("module() can not be called from GFunctions.")
   488  	}
   489  	L.SetFEnv(caller.Fn, tb)
   490  
   491  	top := L.GetTop()
   492  	for i := 2; i <= top; i++ {
   493  		L.Push(L.Get(i))
   494  		L.Push(tb)
   495  		L.Call(1, 0)
   496  	}
   497  	L.Push(tb)
   498  	return 1
   499  }
   500  
   501  var loopdetection = &LUserData{}
   502  
   503  func loRequire(L *LState) int {
   504  	name := L.CheckString(1)
   505  	loaded := L.GetField(L.Get(RegistryIndex), "_LOADED")
   506  	lv := L.GetField(loaded, name)
   507  	if LVAsBool(lv) {
   508  		if lv == loopdetection {
   509  			L.RaiseError("loop or previous error loading module: %s", name)
   510  		}
   511  		L.Push(lv)
   512  		return 1
   513  	}
   514  	loaders, ok := L.GetField(L.Get(RegistryIndex), "_LOADERS").(*LTable)
   515  	if !ok {
   516  		L.RaiseError("package.loaders must be a table")
   517  	}
   518  	messages := []string{}
   519  	var modasfunc LValue
   520  	for i := 1; ; i++ {
   521  		loader := L.RawGetInt(loaders, i)
   522  		if loader == LNil {
   523  			L.RaiseError("module %s not found:\n\t%s, ", name, strings.Join(messages, "\n\t"))
   524  		}
   525  		L.Push(loader)
   526  		L.Push(LString(name))
   527  		L.Call(1, 1)
   528  		ret := L.reg.Pop()
   529  		switch retv := ret.(type) {
   530  		case *LFunction:
   531  			modasfunc = retv
   532  			goto loopbreak
   533  		case LString:
   534  			messages = append(messages, string(retv))
   535  		}
   536  	}
   537  loopbreak:
   538  	L.SetField(loaded, name, loopdetection)
   539  	L.Push(modasfunc)
   540  	L.Push(LString(name))
   541  	L.Call(1, 1)
   542  	ret := L.reg.Pop()
   543  	modv := L.GetField(loaded, name)
   544  	if ret != LNil && modv == loopdetection {
   545  		L.SetField(loaded, name, ret)
   546  		L.Push(ret)
   547  	} else if modv == loopdetection {
   548  		L.SetField(loaded, name, LTrue)
   549  		L.Push(LTrue)
   550  	} else {
   551  		L.Push(modv)
   552  	}
   553  	return 1
   554  }
   555  
   556  /* }}} */
   557  
   558  //