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