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