github.com/tul/gopher-lua@v0.0.0-20181008131706-f6fcaab0c612/auxlib.go (about)

     1  package lua
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"strings"
     9  )
    10  
    11  /* checkType {{{ */
    12  
    13  func (ls *LState) CheckAny(n int) LValue {
    14  	if n > ls.GetTop() {
    15  		ls.ArgError(n, "value expected")
    16  	}
    17  	return ls.Get(n)
    18  }
    19  
    20  func (ls *LState) CheckInt(n int) int {
    21  	v := ls.Get(n)
    22  	if intv, ok := v.(LNumber); ok {
    23  		return int(intv)
    24  	}
    25  	ls.TypeError(n, LTNumber)
    26  	return 0
    27  }
    28  
    29  func (ls *LState) CheckInt64(n int) int64 {
    30  	v := ls.Get(n)
    31  	if intv, ok := v.(LNumber); ok {
    32  		return int64(intv)
    33  	}
    34  	ls.TypeError(n, LTNumber)
    35  	return 0
    36  }
    37  
    38  func (ls *LState) CheckNumber(n int) LNumber {
    39  	v := ls.Get(n)
    40  	if lv, ok := v.(LNumber); ok {
    41  		return lv
    42  	}
    43  	ls.TypeError(n, LTNumber)
    44  	return 0
    45  }
    46  
    47  func (ls *LState) CheckString(n int) string {
    48  	v := ls.Get(n)
    49  	if lv, ok := v.(LString); ok {
    50  		return string(lv)
    51  	}
    52  	ls.TypeError(n, LTString)
    53  	return ""
    54  }
    55  
    56  func (ls *LState) CheckBool(n int) bool {
    57  	v := ls.Get(n)
    58  	if lv, ok := v.(LBool); ok {
    59  		return bool(lv)
    60  	}
    61  	ls.TypeError(n, LTBool)
    62  	return false
    63  }
    64  
    65  func (ls *LState) CheckTable(n int) *LTable {
    66  	v := ls.Get(n)
    67  	if lv, ok := v.(*LTable); ok {
    68  		return lv
    69  	}
    70  	ls.TypeError(n, LTTable)
    71  	return nil
    72  }
    73  
    74  func (ls *LState) CheckFunction(n int) *LFunction {
    75  	v := ls.Get(n)
    76  	if lv, ok := v.(*LFunction); ok {
    77  		return lv
    78  	}
    79  	ls.TypeError(n, LTFunction)
    80  	return nil
    81  }
    82  
    83  func (ls *LState) CheckUserData(n int) *LUserData {
    84  	v := ls.Get(n)
    85  	if lv, ok := v.(*LUserData); ok {
    86  		return lv
    87  	}
    88  	ls.TypeError(n, LTUserData)
    89  	return nil
    90  }
    91  
    92  func (ls *LState) CheckThread(n int) *LState {
    93  	v := ls.Get(n)
    94  	if lv, ok := v.(*LState); ok {
    95  		return lv
    96  	}
    97  	ls.TypeError(n, LTThread)
    98  	return nil
    99  }
   100  
   101  func (ls *LState) CheckType(n int, typ LValueType) {
   102  	v := ls.Get(n)
   103  	if v.Type() != typ {
   104  		ls.TypeError(n, typ)
   105  	}
   106  }
   107  
   108  func (ls *LState) CheckTypes(n int, typs ...LValueType) {
   109  	vt := ls.Get(n).Type()
   110  	for _, typ := range typs {
   111  		if vt == typ {
   112  			return
   113  		}
   114  	}
   115  	buf := []string{}
   116  	for _, typ := range typs {
   117  		buf = append(buf, typ.String())
   118  	}
   119  	ls.ArgError(n, strings.Join(buf, " or ")+" expected, got "+ls.Get(n).Type().String())
   120  }
   121  
   122  func (ls *LState) CheckOption(n int, options []string) int {
   123  	str := ls.CheckString(n)
   124  	for i, v := range options {
   125  		if v == str {
   126  			return i
   127  		}
   128  	}
   129  	ls.ArgError(n, fmt.Sprintf("invalid option: %s (must be one of %s)", str, strings.Join(options, ",")))
   130  	return 0
   131  }
   132  
   133  /* }}} */
   134  
   135  /* optType {{{ */
   136  
   137  func (ls *LState) OptInt(n int, d int) int {
   138  	v := ls.Get(n)
   139  	if v == LNil {
   140  		return d
   141  	}
   142  	if intv, ok := v.(LNumber); ok {
   143  		return int(intv)
   144  	}
   145  	ls.TypeError(n, LTNumber)
   146  	return 0
   147  }
   148  
   149  func (ls *LState) OptInt64(n int, d int64) int64 {
   150  	v := ls.Get(n)
   151  	if v == LNil {
   152  		return d
   153  	}
   154  	if intv, ok := v.(LNumber); ok {
   155  		return int64(intv)
   156  	}
   157  	ls.TypeError(n, LTNumber)
   158  	return 0
   159  }
   160  
   161  func (ls *LState) OptNumber(n int, d LNumber) LNumber {
   162  	v := ls.Get(n)
   163  	if v == LNil {
   164  		return d
   165  	}
   166  	if lv, ok := v.(LNumber); ok {
   167  		return lv
   168  	}
   169  	ls.TypeError(n, LTNumber)
   170  	return 0
   171  }
   172  
   173  func (ls *LState) OptString(n int, d string) string {
   174  	v := ls.Get(n)
   175  	if v == LNil {
   176  		return d
   177  	}
   178  	if lv, ok := v.(LString); ok {
   179  		return string(lv)
   180  	}
   181  	ls.TypeError(n, LTString)
   182  	return ""
   183  }
   184  
   185  func (ls *LState) OptBool(n int, d bool) bool {
   186  	v := ls.Get(n)
   187  	if v == LNil {
   188  		return d
   189  	}
   190  	if lv, ok := v.(LBool); ok {
   191  		return bool(lv)
   192  	}
   193  	ls.TypeError(n, LTBool)
   194  	return false
   195  }
   196  
   197  func (ls *LState) OptTable(n int, d *LTable) *LTable {
   198  	v := ls.Get(n)
   199  	if v == LNil {
   200  		return d
   201  	}
   202  	if lv, ok := v.(*LTable); ok {
   203  		return lv
   204  	}
   205  	ls.TypeError(n, LTTable)
   206  	return nil
   207  }
   208  
   209  func (ls *LState) OptFunction(n int, d *LFunction) *LFunction {
   210  	v := ls.Get(n)
   211  	if v == LNil {
   212  		return d
   213  	}
   214  	if lv, ok := v.(*LFunction); ok {
   215  		return lv
   216  	}
   217  	ls.TypeError(n, LTFunction)
   218  	return nil
   219  }
   220  
   221  func (ls *LState) OptUserData(n int, d *LUserData) *LUserData {
   222  	v := ls.Get(n)
   223  	if v == LNil {
   224  		return d
   225  	}
   226  	if lv, ok := v.(*LUserData); ok {
   227  		return lv
   228  	}
   229  	ls.TypeError(n, LTUserData)
   230  	return nil
   231  }
   232  
   233  /* }}} */
   234  
   235  /* error operations {{{ */
   236  
   237  func (ls *LState) ArgError(n int, message string) {
   238  	ls.RaiseError("bad argument #%v to %v (%v)", n, ls.rawFrameFuncName(ls.currentFrame), message)
   239  }
   240  
   241  func (ls *LState) TypeError(n int, typ LValueType) {
   242  	ls.RaiseError("bad argument #%v to %v (%v expected, got %v)", n, ls.rawFrameFuncName(ls.currentFrame), typ.String(), ls.Get(n).Type().String())
   243  }
   244  
   245  /* }}} */
   246  
   247  /* debug operations {{{ */
   248  
   249  func (ls *LState) Where(level int) string {
   250  	return ls.where(level, false)
   251  }
   252  
   253  /* }}} */
   254  
   255  /* table operations {{{ */
   256  
   257  func (ls *LState) FindTable(obj *LTable, n string, size int) LValue {
   258  	names := strings.Split(n, ".")
   259  	curobj := obj
   260  	for _, name := range names {
   261  		if curobj.Type() != LTTable {
   262  			return LNil
   263  		}
   264  		nextobj := ls.RawGet(curobj, LString(name))
   265  		if nextobj == LNil {
   266  			tb := ls.CreateTable(0, size)
   267  			ls.RawSet(curobj, LString(name), tb)
   268  			curobj = tb
   269  		} else if nextobj.Type() != LTTable {
   270  			return LNil
   271  		} else {
   272  			curobj = nextobj.(*LTable)
   273  		}
   274  	}
   275  	return curobj
   276  }
   277  
   278  /* }}} */
   279  
   280  /* register operations {{{ */
   281  
   282  func (ls *LState) RegisterModule(name string, funcs map[string]LGFunction) LValue {
   283  	tb := ls.FindTable(ls.Get(RegistryIndex).(*LTable), "_LOADED", 1)
   284  	mod := ls.GetField(tb, name)
   285  	if mod.Type() != LTTable {
   286  		newmod := ls.FindTable(ls.Get(GlobalsIndex).(*LTable), name, len(funcs))
   287  		if newmodtb, ok := newmod.(*LTable); !ok {
   288  			ls.RaiseError("name conflict for module(%v)", name)
   289  		} else {
   290  			for fname, fn := range funcs {
   291  				newmodtb.RawSetString(fname, ls.NewFunction(fn))
   292  			}
   293  			ls.SetField(tb, name, newmodtb)
   294  			return newmodtb
   295  		}
   296  	}
   297  	return mod
   298  }
   299  
   300  func (ls *LState) SetFuncs(tb *LTable, funcs map[string]LGFunction, upvalues ...LValue) *LTable {
   301  	for fname, fn := range funcs {
   302  		tb.RawSetString(fname, ls.NewClosure(fn, upvalues...))
   303  	}
   304  	return tb
   305  }
   306  
   307  /* }}} */
   308  
   309  /* metatable operations {{{ */
   310  
   311  func (ls *LState) NewTypeMetatable(typ string) *LTable {
   312  	regtable := ls.Get(RegistryIndex)
   313  	mt := ls.GetField(regtable, typ)
   314  	if tb, ok := mt.(*LTable); ok {
   315  		return tb
   316  	}
   317  	mtnew := ls.NewTable()
   318  	ls.SetField(regtable, typ, mtnew)
   319  	return mtnew
   320  }
   321  
   322  func (ls *LState) GetMetaField(obj LValue, event string) LValue {
   323  	return ls.metaOp1(obj, event)
   324  }
   325  
   326  func (ls *LState) GetTypeMetatable(typ string) LValue {
   327  	return ls.GetField(ls.Get(RegistryIndex), typ)
   328  }
   329  
   330  func (ls *LState) CallMeta(obj LValue, event string) LValue {
   331  	op := ls.metaOp1(obj, event)
   332  	if op.Type() == LTFunction {
   333  		ls.reg.Push(op)
   334  		ls.reg.Push(obj)
   335  		ls.Call(1, 1)
   336  		return ls.reg.Pop()
   337  	}
   338  	return LNil
   339  }
   340  
   341  /* }}} */
   342  
   343  /* load and function call operations {{{ */
   344  
   345  func (ls *LState) LoadFile(path string) (*LFunction, error) {
   346  	var file *os.File
   347  	var err error
   348  	if len(path) == 0 {
   349  		file = os.Stdin
   350  	} else {
   351  		file, err = os.Open(path)
   352  		defer file.Close()
   353  		if err != nil {
   354  			return nil, newApiErrorE(ApiErrorFile, err)
   355  		}
   356  	}
   357  
   358  	reader := bufio.NewReader(file)
   359  	// get the first character.
   360  	c, err := reader.ReadByte()
   361  	if err != nil && err != io.EOF {
   362  		return nil, newApiErrorE(ApiErrorFile, err)
   363  	}
   364  	if c == byte('#') {
   365  		// Unix exec. file?
   366  		// skip first line
   367  		_, err, _ = readBufioLine(reader)
   368  		if err != nil {
   369  			return nil, newApiErrorE(ApiErrorFile, err)
   370  		}
   371  	}
   372  
   373  	if err != io.EOF {
   374  		// if the file is not empty,
   375  		// unread the first character of the file or newline character(readBufioLine's last byte).
   376  		err = reader.UnreadByte()
   377  		if err != nil {
   378  			return nil, newApiErrorE(ApiErrorFile, err)
   379  		}
   380  	}
   381  
   382  	return ls.Load(reader, path)
   383  }
   384  
   385  func (ls *LState) LoadString(source string) (*LFunction, error) {
   386  	return ls.Load(strings.NewReader(source), "<string>")
   387  }
   388  
   389  func (ls *LState) DoFile(path string) error {
   390  	if fn, err := ls.LoadFile(path); err != nil {
   391  		return err
   392  	} else {
   393  		ls.Push(fn)
   394  		return ls.PCall(0, MultRet, nil)
   395  	}
   396  }
   397  
   398  func (ls *LState) DoString(source string) error {
   399  	if fn, err := ls.LoadString(source); err != nil {
   400  		return err
   401  	} else {
   402  		ls.Push(fn)
   403  		return ls.PCall(0, MultRet, nil)
   404  	}
   405  }
   406  
   407  /* }}} */
   408  
   409  /* GopherLua original APIs {{{ */
   410  
   411  // ToStringMeta returns string representation of given LValue.
   412  // This method calls the `__tostring` meta method if defined.
   413  func (ls *LState) ToStringMeta(lv LValue) LValue {
   414  	if fn, ok := ls.metaOp1(lv, "__tostring").assertFunction(); ok {
   415  		ls.Push(fn)
   416  		ls.Push(lv)
   417  		ls.Call(1, 1)
   418  		return ls.reg.Pop()
   419  	} else {
   420  		return LString(lv.String())
   421  	}
   422  }
   423  
   424  // Set a module loader to the package.preload table.
   425  func (ls *LState) PreloadModule(name string, loader LGFunction) {
   426  	preload := ls.GetField(ls.GetField(ls.Get(EnvironIndex), "package"), "preload")
   427  	if _, ok := preload.(*LTable); !ok {
   428  		ls.RaiseError("package.preload must be a table")
   429  	}
   430  	ls.SetField(preload, name, ls.NewFunction(loader))
   431  }
   432  
   433  // Checks whether the given index is an LChannel and returns this channel.
   434  func (ls *LState) CheckChannel(n int) chan LValue {
   435  	v := ls.Get(n)
   436  	if ch, ok := v.(LChannel); ok {
   437  		return (chan LValue)(ch)
   438  	}
   439  	ls.TypeError(n, LTChannel)
   440  	return nil
   441  }
   442  
   443  // If the given index is a LChannel, returns this channel. If this argument is absent or is nil, returns ch. Otherwise, raises an error.
   444  func (ls *LState) OptChannel(n int, ch chan LValue) chan LValue {
   445  	v := ls.Get(n)
   446  	if v == LNil {
   447  		return ch
   448  	}
   449  	if ch, ok := v.(LChannel); ok {
   450  		return (chan LValue)(ch)
   451  	}
   452  	ls.TypeError(n, LTChannel)
   453  	return nil
   454  }
   455  
   456  /* }}} */
   457  
   458  //