github.com/yuin/gopher-lua@v1.1.2-0.20231212122839-2348fd042596/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.CheckAny(1)
   262  	v := L.Get(1)
   263  	if v.Type() != LTFunction && L.GetMetaField(v, "__call").Type() != LTFunction {
   264  		L.Push(LFalse)
   265  		L.Push(LString("attempt to call a " + v.Type().String() + " value"))
   266  		return 2
   267  	}
   268  	nargs := L.GetTop() - 1
   269  	if err := L.PCall(nargs, MultRet, nil); err != nil {
   270  		L.Push(LFalse)
   271  		if aerr, ok := err.(*ApiError); ok {
   272  			L.Push(aerr.Object)
   273  		} else {
   274  			L.Push(LString(err.Error()))
   275  		}
   276  		return 2
   277  	} else {
   278  		L.Insert(LTrue, 1)
   279  		return L.GetTop()
   280  	}
   281  }
   282  
   283  func basePrint(L *LState) int {
   284  	top := L.GetTop()
   285  	for i := 1; i <= top; i++ {
   286  		fmt.Print(L.ToStringMeta(L.Get(i)).String())
   287  		if i != top {
   288  			fmt.Print("\t")
   289  		}
   290  	}
   291  	fmt.Println("")
   292  	return 0
   293  }
   294  
   295  func base_PrintRegs(L *LState) int {
   296  	L.printReg()
   297  	return 0
   298  }
   299  
   300  func baseRawEqual(L *LState) int {
   301  	if L.CheckAny(1) == L.CheckAny(2) {
   302  		L.Push(LTrue)
   303  	} else {
   304  		L.Push(LFalse)
   305  	}
   306  	return 1
   307  }
   308  
   309  func baseRawGet(L *LState) int {
   310  	L.Push(L.RawGet(L.CheckTable(1), L.CheckAny(2)))
   311  	return 1
   312  }
   313  
   314  func baseRawSet(L *LState) int {
   315  	L.RawSet(L.CheckTable(1), L.CheckAny(2), L.CheckAny(3))
   316  	return 0
   317  }
   318  
   319  func baseSelect(L *LState) int {
   320  	L.CheckTypes(1, LTNumber, LTString)
   321  	switch lv := L.Get(1).(type) {
   322  	case LNumber:
   323  		idx := int(lv)
   324  		num := L.GetTop()
   325  		if idx < 0 {
   326  			idx = num + idx
   327  		} else if idx > num {
   328  			idx = num
   329  		}
   330  		if 1 > idx {
   331  			L.ArgError(1, "index out of range")
   332  		}
   333  		return num - idx
   334  	case LString:
   335  		if string(lv) != "#" {
   336  			L.ArgError(1, "invalid string '"+string(lv)+"'")
   337  		}
   338  		L.Push(LNumber(L.GetTop() - 1))
   339  		return 1
   340  	}
   341  	return 0
   342  }
   343  
   344  func baseSetFEnv(L *LState) int {
   345  	var value LValue
   346  	if L.GetTop() == 0 {
   347  		value = LNumber(1)
   348  	} else {
   349  		value = L.Get(1)
   350  	}
   351  	env := L.CheckTable(2)
   352  
   353  	if fn, ok := value.(*LFunction); ok {
   354  		if fn.IsG {
   355  			L.RaiseError("cannot change the environment of given object")
   356  		} else {
   357  			fn.Env = env
   358  			L.Push(fn)
   359  			return 1
   360  		}
   361  	}
   362  
   363  	if number, ok := value.(LNumber); ok {
   364  		level := int(float64(number))
   365  		if level <= 0 {
   366  			L.Env = env
   367  			return 0
   368  		}
   369  
   370  		cf := L.currentFrame
   371  		for i := 0; i < level && cf != nil; i++ {
   372  			cf = cf.Parent
   373  		}
   374  		if cf == nil || cf.Fn.IsG {
   375  			L.RaiseError("cannot change the environment of given object")
   376  		} else {
   377  			cf.Fn.Env = env
   378  			L.Push(cf.Fn)
   379  			return 1
   380  		}
   381  	}
   382  
   383  	L.RaiseError("cannot change the environment of given object")
   384  	return 0
   385  }
   386  
   387  func baseSetMetatable(L *LState) int {
   388  	L.CheckTypes(2, LTNil, LTTable)
   389  	obj := L.Get(1)
   390  	if obj == LNil {
   391  		L.RaiseError("cannot set metatable to a nil object.")
   392  	}
   393  	mt := L.Get(2)
   394  	if m := L.metatable(obj, true); m != LNil {
   395  		if tb, ok := m.(*LTable); ok && tb.RawGetString("__metatable") != LNil {
   396  			L.RaiseError("cannot change a protected metatable")
   397  		}
   398  	}
   399  	L.SetMetatable(obj, mt)
   400  	L.SetTop(1)
   401  	return 1
   402  }
   403  
   404  func baseToNumber(L *LState) int {
   405  	base := L.OptInt(2, 10)
   406  	noBase := L.Get(2) == LNil
   407  
   408  	switch lv := L.CheckAny(1).(type) {
   409  	case LNumber:
   410  		L.Push(lv)
   411  	case LString:
   412  		str := strings.Trim(string(lv), " \n\t")
   413  		if strings.Index(str, ".") > -1 {
   414  			if v, err := strconv.ParseFloat(str, LNumberBit); err != nil {
   415  				L.Push(LNil)
   416  			} else {
   417  				L.Push(LNumber(v))
   418  			}
   419  		} else {
   420  			if noBase && strings.HasPrefix(strings.ToLower(str), "0x") {
   421  				base, str = 16, str[2:] // Hex number
   422  			}
   423  			if v, err := strconv.ParseInt(str, base, LNumberBit); err != nil {
   424  				L.Push(LNil)
   425  			} else {
   426  				L.Push(LNumber(v))
   427  			}
   428  		}
   429  	default:
   430  		L.Push(LNil)
   431  	}
   432  	return 1
   433  }
   434  
   435  func baseToString(L *LState) int {
   436  	v1 := L.CheckAny(1)
   437  	L.Push(L.ToStringMeta(v1))
   438  	return 1
   439  }
   440  
   441  func baseType(L *LState) int {
   442  	L.Push(LString(L.CheckAny(1).Type().String()))
   443  	return 1
   444  }
   445  
   446  func baseUnpack(L *LState) int {
   447  	tb := L.CheckTable(1)
   448  	start := L.OptInt(2, 1)
   449  	end := L.OptInt(3, tb.Len())
   450  	for i := start; i <= end; i++ {
   451  		L.Push(tb.RawGetInt(i))
   452  	}
   453  	ret := end - start + 1
   454  	if ret < 0 {
   455  		return 0
   456  	}
   457  	return ret
   458  }
   459  
   460  func baseXPCall(L *LState) int {
   461  	fn := L.CheckFunction(1)
   462  	errfunc := L.CheckFunction(2)
   463  
   464  	top := L.GetTop()
   465  	L.Push(fn)
   466  	if err := L.PCall(0, MultRet, errfunc); err != nil {
   467  		L.Push(LFalse)
   468  		if aerr, ok := err.(*ApiError); ok {
   469  			L.Push(aerr.Object)
   470  		} else {
   471  			L.Push(LString(err.Error()))
   472  		}
   473  		return 2
   474  	} else {
   475  		L.Insert(LTrue, top+1)
   476  		return L.GetTop() - top
   477  	}
   478  }
   479  
   480  /* }}} */
   481  
   482  /* load lib {{{ */
   483  
   484  func loModule(L *LState) int {
   485  	name := L.CheckString(1)
   486  	loaded := L.GetField(L.Get(RegistryIndex), "_LOADED")
   487  	tb := L.GetField(loaded, name)
   488  	if _, ok := tb.(*LTable); !ok {
   489  		tb = L.FindTable(L.Get(GlobalsIndex).(*LTable), name, 1)
   490  		if tb == LNil {
   491  			L.RaiseError("name conflict for module: %v", name)
   492  		}
   493  		L.SetField(loaded, name, tb)
   494  	}
   495  	if L.GetField(tb, "_NAME") == LNil {
   496  		L.SetField(tb, "_M", tb)
   497  		L.SetField(tb, "_NAME", LString(name))
   498  		names := strings.Split(name, ".")
   499  		pname := ""
   500  		if len(names) > 1 {
   501  			pname = strings.Join(names[:len(names)-1], ".") + "."
   502  		}
   503  		L.SetField(tb, "_PACKAGE", LString(pname))
   504  	}
   505  
   506  	caller := L.currentFrame.Parent
   507  	if caller == nil {
   508  		L.RaiseError("no calling stack.")
   509  	} else if caller.Fn.IsG {
   510  		L.RaiseError("module() can not be called from GFunctions.")
   511  	}
   512  	L.SetFEnv(caller.Fn, tb)
   513  
   514  	top := L.GetTop()
   515  	for i := 2; i <= top; i++ {
   516  		L.Push(L.Get(i))
   517  		L.Push(tb)
   518  		L.Call(1, 0)
   519  	}
   520  	L.Push(tb)
   521  	return 1
   522  }
   523  
   524  var loopdetection = &LUserData{}
   525  
   526  func loRequire(L *LState) int {
   527  	name := L.CheckString(1)
   528  	loaded := L.GetField(L.Get(RegistryIndex), "_LOADED")
   529  	lv := L.GetField(loaded, name)
   530  	if LVAsBool(lv) {
   531  		if lv == loopdetection {
   532  			L.RaiseError("loop or previous error loading module: %s", name)
   533  		}
   534  		L.Push(lv)
   535  		return 1
   536  	}
   537  	loaders, ok := L.GetField(L.Get(RegistryIndex), "_LOADERS").(*LTable)
   538  	if !ok {
   539  		L.RaiseError("package.loaders must be a table")
   540  	}
   541  	messages := []string{}
   542  	var modasfunc LValue
   543  	for i := 1; ; i++ {
   544  		loader := L.RawGetInt(loaders, i)
   545  		if loader == LNil {
   546  			L.RaiseError("module %s not found:\n\t%s, ", name, strings.Join(messages, "\n\t"))
   547  		}
   548  		L.Push(loader)
   549  		L.Push(LString(name))
   550  		L.Call(1, 1)
   551  		ret := L.reg.Pop()
   552  		switch retv := ret.(type) {
   553  		case *LFunction:
   554  			modasfunc = retv
   555  			goto loopbreak
   556  		case LString:
   557  			messages = append(messages, string(retv))
   558  		}
   559  	}
   560  loopbreak:
   561  	L.SetField(loaded, name, loopdetection)
   562  	L.Push(modasfunc)
   563  	L.Push(LString(name))
   564  	L.Call(1, 1)
   565  	ret := L.reg.Pop()
   566  	modv := L.GetField(loaded, name)
   567  	if ret != LNil && modv == loopdetection {
   568  		L.SetField(loaded, name, ret)
   569  		L.Push(ret)
   570  	} else if modv == loopdetection {
   571  		L.SetField(loaded, name, LTrue)
   572  		L.Push(LTrue)
   573  	} else {
   574  		L.Push(modv)
   575  	}
   576  	return 1
   577  }
   578  
   579  /* }}} */
   580  
   581  /* hidden features {{{ */
   582  
   583  func baseNewProxy(L *LState) int {
   584  	ud := L.NewUserData()
   585  	L.SetTop(1)
   586  	if L.Get(1) == LTrue {
   587  		L.SetMetatable(ud, L.NewTable())
   588  	} else if d, ok := L.Get(1).(*LUserData); ok {
   589  		L.SetMetatable(ud, L.GetMetatable(d))
   590  	}
   591  	L.Push(ud)
   592  	return 1
   593  }
   594  
   595  /* }}} */
   596  
   597  //