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

     1  package lua
     2  
     3  ////////////////////////////////////////////////////////
     4  // This file was generated by go-inline. DO NOT EDIT. //
     5  ////////////////////////////////////////////////////////
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  )
    12  
    13  func mainLoop(L *LState, baseframe *callFrame) {
    14  	var inst uint32
    15  	var cf *callFrame
    16  
    17  	if L.stack.IsEmpty() {
    18  		return
    19  	}
    20  
    21  	L.currentFrame = L.stack.Last()
    22  	if L.currentFrame.Fn.IsG {
    23  		callGFunction(L, false)
    24  		return
    25  	}
    26  
    27  	for {
    28  		cf = L.currentFrame
    29  		inst = cf.Fn.Proto.Code[cf.Pc]
    30  		cf.Pc++
    31  		if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 {
    32  			return
    33  		}
    34  	}
    35  }
    36  
    37  func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start
    38  	if b == 1 {
    39  		// this section is inlined by go-inline
    40  		// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
    41  		{
    42  			rg := L.reg
    43  			regm := regv
    44  			for i := 0; i < n; i++ {
    45  				rg.array[regm+i] = LNil
    46  			}
    47  			rg.top = regm + n
    48  		}
    49  	} else {
    50  		// this section is inlined by go-inline
    51  		// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
    52  		{
    53  			rg := L.reg
    54  			limit := -1
    55  			for i := 0; i < n; i++ {
    56  				if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
    57  					rg.array[regv+i] = LNil
    58  				} else {
    59  					rg.array[regv+i] = rg.array[tidx]
    60  				}
    61  			}
    62  			rg.top = regv + n
    63  		}
    64  	}
    65  } // +inline-end
    66  
    67  func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) {
    68  	parent := L.Parent
    69  	if parent == nil {
    70  		L.RaiseError("can not yield from outside of a coroutine")
    71  	}
    72  	L.G.CurrentThread = parent
    73  	L.Parent = nil
    74  	if !L.wrapped {
    75  		if haserror {
    76  			parent.Push(LFalse)
    77  		} else {
    78  			parent.Push(LTrue)
    79  		}
    80  	}
    81  	L.XMoveTo(parent, nargs)
    82  	L.stack.Pop()
    83  	offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase
    84  	L.currentFrame = L.stack.Last()
    85  	L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions)
    86  	if kill {
    87  		L.kill()
    88  	}
    89  }
    90  
    91  func callGFunction(L *LState, tailcall bool) bool {
    92  	frame := L.currentFrame
    93  	gfnret := frame.Fn.GFunction(L)
    94  	if tailcall {
    95  		L.stack.Remove(L.stack.Sp() - 2) // remove caller lua function frame
    96  		L.currentFrame = L.stack.Last()
    97  	}
    98  
    99  	if gfnret < 0 {
   100  		switchToParentThread(L, L.GetTop(), false, false)
   101  		return true
   102  	}
   103  
   104  	wantret := frame.NRet
   105  	if wantret == MultRet {
   106  		wantret = gfnret
   107  	}
   108  
   109  	if tailcall && L.Parent != nil && L.stack.Sp() == 1 {
   110  		switchToParentThread(L, wantret, false, true)
   111  		return true
   112  	}
   113  
   114  	// this section is inlined by go-inline
   115  	// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   116  	{
   117  		rg := L.reg
   118  		regv := frame.ReturnBase
   119  		start := L.reg.Top() - gfnret
   120  		limit := -1
   121  		n := wantret
   122  		for i := 0; i < n; i++ {
   123  			if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   124  				rg.array[regv+i] = LNil
   125  			} else {
   126  				rg.array[regv+i] = rg.array[tidx]
   127  			}
   128  		}
   129  		rg.top = regv + n
   130  	}
   131  	L.stack.Pop()
   132  	L.currentFrame = L.stack.Last()
   133  	return false
   134  }
   135  
   136  func threadRun(L *LState) {
   137  	if L.stack.IsEmpty() {
   138  		return
   139  	}
   140  
   141  	defer func() {
   142  		if rcv := recover(); rcv != nil {
   143  			var lv LValue
   144  			if v, ok := rcv.(*ApiError); ok {
   145  				lv = v.Object
   146  			} else {
   147  				lv = LString(fmt.Sprint(rcv))
   148  			}
   149  			if parent := L.Parent; parent != nil {
   150  				if L.wrapped {
   151  					L.Push(lv)
   152  					parent.Panic(L)
   153  				} else {
   154  					L.SetTop(0)
   155  					L.Push(lv)
   156  					switchToParentThread(L, 1, true, true)
   157  				}
   158  			} else {
   159  				panic(rcv)
   160  			}
   161  		}
   162  	}()
   163  	mainLoop(L, nil)
   164  }
   165  
   166  type instFunc func(*LState, uint32, *callFrame) int
   167  
   168  var jumpTable [opCodeMax + 1]instFunc
   169  
   170  func init() {
   171  	jumpTable = [opCodeMax + 1]instFunc{
   172  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE
   173  			reg := L.reg
   174  			cf := L.currentFrame
   175  			lbase := cf.LocalBase
   176  			A := int(inst>>18) & 0xff //GETA
   177  			RA := lbase + A
   178  			B := int(inst & 0x1ff) //GETB
   179  			reg.Set(RA, reg.Get(lbase+B))
   180  			return 0
   181  		},
   182  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN
   183  			reg := L.reg
   184  			cf := L.currentFrame
   185  			lbase := cf.LocalBase
   186  			A := int(inst>>18) & 0xff //GETA
   187  			B := int(inst & 0x1ff)    //GETB
   188  			C := int(inst>>9) & 0x1ff //GETC
   189  			reg.Set(lbase+A, reg.Get(lbase+B))
   190  			code := cf.Fn.Proto.Code
   191  			pc := cf.Pc
   192  			for i := 0; i < C; i++ {
   193  				inst = code[pc]
   194  				pc++
   195  				A = int(inst>>18) & 0xff //GETA
   196  				B = int(inst & 0x1ff)    //GETB
   197  				reg.Set(lbase+A, reg.Get(lbase+B))
   198  			}
   199  			cf.Pc = pc
   200  			return 0
   201  		},
   202  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK
   203  			reg := L.reg
   204  			cf := L.currentFrame
   205  			lbase := cf.LocalBase
   206  			A := int(inst>>18) & 0xff //GETA
   207  			RA := lbase + A
   208  			Bx := int(inst & 0x3ffff) //GETBX
   209  			reg.Set(RA, cf.Fn.Proto.Constants[Bx])
   210  			return 0
   211  		},
   212  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL
   213  			reg := L.reg
   214  			cf := L.currentFrame
   215  			lbase := cf.LocalBase
   216  			A := int(inst>>18) & 0xff //GETA
   217  			RA := lbase + A
   218  			B := int(inst & 0x1ff)    //GETB
   219  			C := int(inst>>9) & 0x1ff //GETC
   220  			if B != 0 {
   221  				reg.Set(RA, LTrue)
   222  			} else {
   223  				reg.Set(RA, LFalse)
   224  			}
   225  			if C != 0 {
   226  				cf.Pc++
   227  			}
   228  			return 0
   229  		},
   230  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL
   231  			reg := L.reg
   232  			cf := L.currentFrame
   233  			lbase := cf.LocalBase
   234  			A := int(inst>>18) & 0xff //GETA
   235  			RA := lbase + A
   236  			B := int(inst & 0x1ff) //GETB
   237  			for i := RA; i <= lbase+B; i++ {
   238  				reg.Set(i, LNil)
   239  			}
   240  			return 0
   241  		},
   242  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL
   243  			reg := L.reg
   244  			cf := L.currentFrame
   245  			lbase := cf.LocalBase
   246  			A := int(inst>>18) & 0xff //GETA
   247  			RA := lbase + A
   248  			B := int(inst & 0x1ff) //GETB
   249  			reg.Set(RA, cf.Fn.Upvalues[B].Value())
   250  			return 0
   251  		},
   252  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL
   253  			reg := L.reg
   254  			cf := L.currentFrame
   255  			lbase := cf.LocalBase
   256  			A := int(inst>>18) & 0xff //GETA
   257  			RA := lbase + A
   258  			Bx := int(inst & 0x3ffff) //GETBX
   259  			//reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx]))
   260  			reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]))
   261  			return 0
   262  		},
   263  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE
   264  			reg := L.reg
   265  			cf := L.currentFrame
   266  			lbase := cf.LocalBase
   267  			A := int(inst>>18) & 0xff //GETA
   268  			RA := lbase + A
   269  			B := int(inst & 0x1ff)    //GETB
   270  			C := int(inst>>9) & 0x1ff //GETC
   271  			reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C)))
   272  			return 0
   273  		},
   274  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS
   275  			reg := L.reg
   276  			cf := L.currentFrame
   277  			lbase := cf.LocalBase
   278  			A := int(inst>>18) & 0xff //GETA
   279  			RA := lbase + A
   280  			B := int(inst & 0x1ff)    //GETB
   281  			C := int(inst>>9) & 0x1ff //GETC
   282  			reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C)))
   283  			return 0
   284  		},
   285  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL
   286  			reg := L.reg
   287  			cf := L.currentFrame
   288  			lbase := cf.LocalBase
   289  			A := int(inst>>18) & 0xff //GETA
   290  			RA := lbase + A
   291  			Bx := int(inst & 0x3ffff) //GETBX
   292  			//L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA))
   293  			L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA))
   294  			return 0
   295  		},
   296  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL
   297  			reg := L.reg
   298  			cf := L.currentFrame
   299  			lbase := cf.LocalBase
   300  			A := int(inst>>18) & 0xff //GETA
   301  			RA := lbase + A
   302  			B := int(inst & 0x1ff) //GETB
   303  			cf.Fn.Upvalues[B].SetValue(reg.Get(RA))
   304  			return 0
   305  		},
   306  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE
   307  			reg := L.reg
   308  			cf := L.currentFrame
   309  			lbase := cf.LocalBase
   310  			A := int(inst>>18) & 0xff //GETA
   311  			RA := lbase + A
   312  			B := int(inst & 0x1ff)    //GETB
   313  			C := int(inst>>9) & 0x1ff //GETC
   314  			L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C))
   315  			return 0
   316  		},
   317  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS
   318  			reg := L.reg
   319  			cf := L.currentFrame
   320  			lbase := cf.LocalBase
   321  			A := int(inst>>18) & 0xff //GETA
   322  			RA := lbase + A
   323  			B := int(inst & 0x1ff)    //GETB
   324  			C := int(inst>>9) & 0x1ff //GETC
   325  			L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C))
   326  			return 0
   327  		},
   328  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE
   329  			reg := L.reg
   330  			cf := L.currentFrame
   331  			lbase := cf.LocalBase
   332  			A := int(inst>>18) & 0xff //GETA
   333  			RA := lbase + A
   334  			B := int(inst & 0x1ff)    //GETB
   335  			C := int(inst>>9) & 0x1ff //GETC
   336  			reg.Set(RA, newLTable(B, C))
   337  			return 0
   338  		},
   339  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF
   340  			reg := L.reg
   341  			cf := L.currentFrame
   342  			lbase := cf.LocalBase
   343  			A := int(inst>>18) & 0xff //GETA
   344  			RA := lbase + A
   345  			B := int(inst & 0x1ff)    //GETB
   346  			C := int(inst>>9) & 0x1ff //GETC
   347  			selfobj := reg.Get(lbase + B)
   348  			reg.Set(RA, L.getFieldString(selfobj, L.rkString(C)))
   349  			reg.Set(RA+1, selfobj)
   350  			return 0
   351  		},
   352  		opArith, // OP_ADD
   353  		opArith, // OP_SUB
   354  		opArith, // OP_MUL
   355  		opArith, // OP_DIV
   356  		opArith, // OP_MOD
   357  		opArith, // OP_POW
   358  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM
   359  			reg := L.reg
   360  			cf := L.currentFrame
   361  			lbase := cf.LocalBase
   362  			A := int(inst>>18) & 0xff //GETA
   363  			RA := lbase + A
   364  			B := int(inst & 0x1ff) //GETB
   365  			unaryv := L.rkValue(B)
   366  			if nm, ok := unaryv.(LNumber); ok {
   367  				reg.SetNumber(RA, -nm)
   368  			} else {
   369  				op := L.metaOp1(unaryv, "__unm")
   370  				if op.Type() == LTFunction {
   371  					reg.Push(op)
   372  					reg.Push(unaryv)
   373  					L.Call(1, 1)
   374  					reg.Set(RA, reg.Pop())
   375  				} else if str, ok1 := unaryv.(LString); ok1 {
   376  					if num, err := parseNumber(string(str)); err == nil {
   377  						reg.Set(RA, -num)
   378  					} else {
   379  						L.RaiseError("__unm undefined")
   380  					}
   381  				} else {
   382  					L.RaiseError("__unm undefined")
   383  				}
   384  			}
   385  			return 0
   386  		},
   387  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT
   388  			reg := L.reg
   389  			cf := L.currentFrame
   390  			lbase := cf.LocalBase
   391  			A := int(inst>>18) & 0xff //GETA
   392  			RA := lbase + A
   393  			B := int(inst & 0x1ff) //GETB
   394  			if LVIsFalse(reg.Get(lbase + B)) {
   395  				reg.Set(RA, LTrue)
   396  			} else {
   397  				reg.Set(RA, LFalse)
   398  			}
   399  			return 0
   400  		},
   401  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN
   402  			reg := L.reg
   403  			cf := L.currentFrame
   404  			lbase := cf.LocalBase
   405  			A := int(inst>>18) & 0xff //GETA
   406  			RA := lbase + A
   407  			B := int(inst & 0x1ff) //GETB
   408  			switch lv := L.rkValue(B).(type) {
   409  			case LString:
   410  				reg.SetNumber(RA, LNumber(len(lv)))
   411  			default:
   412  				op := L.metaOp1(lv, "__len")
   413  				if op.Type() == LTFunction {
   414  					reg.Push(op)
   415  					reg.Push(lv)
   416  					L.Call(1, 1)
   417  					reg.Set(RA, reg.Pop())
   418  				} else if lv.Type() == LTTable {
   419  					reg.SetNumber(RA, LNumber(lv.(*LTable).Len()))
   420  				} else {
   421  					L.RaiseError("__len undefined")
   422  				}
   423  			}
   424  			return 0
   425  		},
   426  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT
   427  			reg := L.reg
   428  			cf := L.currentFrame
   429  			lbase := cf.LocalBase
   430  			A := int(inst>>18) & 0xff //GETA
   431  			RA := lbase + A
   432  			B := int(inst & 0x1ff)    //GETB
   433  			C := int(inst>>9) & 0x1ff //GETC
   434  			RC := lbase + C
   435  			RB := lbase + B
   436  			reg.Set(RA, stringConcat(L, RC-RB+1, RC))
   437  			return 0
   438  		},
   439  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP
   440  			cf := L.currentFrame
   441  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   442  			cf.Pc += Sbx
   443  			return 0
   444  		},
   445  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ
   446  			cf := L.currentFrame
   447  			A := int(inst>>18) & 0xff //GETA
   448  			B := int(inst & 0x1ff)    //GETB
   449  			C := int(inst>>9) & 0x1ff //GETC
   450  			ret := equals(L, L.rkValue(B), L.rkValue(C), false)
   451  			v := 1
   452  			if ret {
   453  				v = 0
   454  			}
   455  			if v == A {
   456  				cf.Pc++
   457  			}
   458  			return 0
   459  		},
   460  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT
   461  			cf := L.currentFrame
   462  			A := int(inst>>18) & 0xff //GETA
   463  			B := int(inst & 0x1ff)    //GETB
   464  			C := int(inst>>9) & 0x1ff //GETC
   465  			ret := lessThan(L, L.rkValue(B), L.rkValue(C))
   466  			v := 1
   467  			if ret {
   468  				v = 0
   469  			}
   470  			if v == A {
   471  				cf.Pc++
   472  			}
   473  			return 0
   474  		},
   475  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE
   476  			cf := L.currentFrame
   477  			A := int(inst>>18) & 0xff //GETA
   478  			B := int(inst & 0x1ff)    //GETB
   479  			C := int(inst>>9) & 0x1ff //GETC
   480  			lhs := L.rkValue(B)
   481  			rhs := L.rkValue(C)
   482  			ret := false
   483  
   484  			if v1, ok1 := lhs.assertFloat64(); ok1 {
   485  				if v2, ok2 := rhs.assertFloat64(); ok2 {
   486  					ret = v1 <= v2
   487  				} else {
   488  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   489  				}
   490  			} else {
   491  				if lhs.Type() != rhs.Type() {
   492  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   493  				}
   494  				switch lhs.Type() {
   495  				case LTString:
   496  					ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0
   497  				default:
   498  					switch objectRational(L, lhs, rhs, "__le") {
   499  					case 1:
   500  						ret = true
   501  					case 0:
   502  						ret = false
   503  					default:
   504  						ret = !objectRationalWithError(L, rhs, lhs, "__lt")
   505  					}
   506  				}
   507  			}
   508  
   509  			v := 1
   510  			if ret {
   511  				v = 0
   512  			}
   513  			if v == A {
   514  				cf.Pc++
   515  			}
   516  			return 0
   517  		},
   518  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST
   519  			reg := L.reg
   520  			cf := L.currentFrame
   521  			lbase := cf.LocalBase
   522  			A := int(inst>>18) & 0xff //GETA
   523  			RA := lbase + A
   524  			C := int(inst>>9) & 0x1ff //GETC
   525  			if LVAsBool(reg.Get(RA)) == (C == 0) {
   526  				cf.Pc++
   527  			}
   528  			return 0
   529  		},
   530  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET
   531  			reg := L.reg
   532  			cf := L.currentFrame
   533  			lbase := cf.LocalBase
   534  			A := int(inst>>18) & 0xff //GETA
   535  			RA := lbase + A
   536  			B := int(inst & 0x1ff)    //GETB
   537  			C := int(inst>>9) & 0x1ff //GETC
   538  			if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) {
   539  				reg.Set(RA, value)
   540  			} else {
   541  				cf.Pc++
   542  			}
   543  			return 0
   544  		},
   545  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL
   546  			reg := L.reg
   547  			cf := L.currentFrame
   548  			lbase := cf.LocalBase
   549  			A := int(inst>>18) & 0xff //GETA
   550  			RA := lbase + A
   551  			B := int(inst & 0x1ff)    //GETB
   552  			C := int(inst>>9) & 0x1ff //GETC
   553  			nargs := B - 1
   554  			if B == 0 {
   555  				nargs = reg.Top() - (RA + 1)
   556  			}
   557  			lv := reg.Get(RA)
   558  			nret := C - 1
   559  			var callable *LFunction
   560  			var meta bool
   561  			if fn, ok := lv.assertFunction(); ok {
   562  				callable = fn
   563  				meta = false
   564  			} else {
   565  				callable, meta = L.metaCall(lv)
   566  			}
   567  			// this section is inlined by go-inline
   568  			// source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go'
   569  			{
   570  				ls := L
   571  				cf := callFrame{Fn: callable, Pc: 0, Base: RA, LocalBase: RA + 1, ReturnBase: RA, NArgs: nargs, NRet: nret, Parent: cf, TailCall: 0}
   572  				fn := lv
   573  				if meta {
   574  					cf.NArgs++
   575  					ls.reg.Insert(fn, cf.LocalBase)
   576  				}
   577  				if cf.Fn == nil {
   578  					ls.RaiseError("attempt to call a non-function object")
   579  				}
   580  				if ls.stack.sp == ls.Options.CallStackSize {
   581  					ls.RaiseError("stack overflow")
   582  				}
   583  				// this section is inlined by go-inline
   584  				// source function is 'func (cs *callFrameStack) Push(v callFrame) ' in '_state.go'
   585  				{
   586  					cs := ls.stack
   587  					v := cf
   588  					cs.array[cs.sp] = v
   589  					cs.array[cs.sp].Idx = cs.sp
   590  					cs.sp++
   591  				}
   592  				newcf := ls.stack.Last()
   593  				// this section is inlined by go-inline
   594  				// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
   595  				{
   596  					cf := newcf
   597  					if cf.Fn.IsG {
   598  						ls.reg.SetTop(cf.LocalBase + cf.NArgs)
   599  					} else {
   600  						proto := cf.Fn.Proto
   601  						nargs := cf.NArgs
   602  						np := int(proto.NumParameters)
   603  						for i := nargs; i < np; i++ {
   604  							ls.reg.array[cf.LocalBase+i] = LNil
   605  							nargs = np
   606  						}
   607  
   608  						if (proto.IsVarArg & VarArgIsVarArg) == 0 {
   609  							if nargs < int(proto.NumUsedRegisters) {
   610  								nargs = int(proto.NumUsedRegisters)
   611  							}
   612  							for i := np; i < nargs; i++ {
   613  								ls.reg.array[cf.LocalBase+i] = LNil
   614  							}
   615  							ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
   616  						} else {
   617  							/* swap vararg positions:
   618  									   closure
   619  									   namedparam1 <- lbase
   620  									   namedparam2
   621  									   vararg1
   622  									   vararg2
   623  
   624  							           TO
   625  
   626  									   closure
   627  									   nil
   628  									   nil
   629  									   vararg1
   630  									   vararg2
   631  									   namedparam1 <- lbase
   632  									   namedparam2
   633  							*/
   634  							nvarargs := nargs - np
   635  							if nvarargs < 0 {
   636  								nvarargs = 0
   637  							}
   638  
   639  							ls.reg.SetTop(cf.LocalBase + nargs + np)
   640  							for i := 0; i < np; i++ {
   641  								//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
   642  								ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
   643  								//ls.reg.Set(cf.LocalBase+i, LNil)
   644  								ls.reg.array[cf.LocalBase+i] = LNil
   645  							}
   646  
   647  							if CompatVarArg {
   648  								ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
   649  								if (proto.IsVarArg & VarArgNeedsArg) != 0 {
   650  									argtb := newLTable(nvarargs, 0)
   651  									for i := 0; i < nvarargs; i++ {
   652  										argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
   653  									}
   654  									argtb.RawSetString("n", LNumber(nvarargs))
   655  									//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
   656  									ls.reg.array[cf.LocalBase+nargs+np] = argtb
   657  								} else {
   658  									ls.reg.array[cf.LocalBase+nargs+np] = LNil
   659  								}
   660  							}
   661  							cf.LocalBase += nargs
   662  							maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
   663  							ls.reg.SetTop(maxreg)
   664  						}
   665  					}
   666  				}
   667  				ls.currentFrame = newcf
   668  			}
   669  			if callable.IsG && callGFunction(L, false) {
   670  				return 1
   671  			}
   672  			return 0
   673  		},
   674  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL
   675  			reg := L.reg
   676  			cf := L.currentFrame
   677  			lbase := cf.LocalBase
   678  			A := int(inst>>18) & 0xff //GETA
   679  			RA := lbase + A
   680  			B := int(inst & 0x1ff) //GETB
   681  			nargs := B - 1
   682  			if B == 0 {
   683  				nargs = reg.Top() - (RA + 1)
   684  			}
   685  			lv := reg.Get(RA)
   686  			var callable *LFunction
   687  			var meta bool
   688  			if fn, ok := lv.assertFunction(); ok {
   689  				callable = fn
   690  				meta = false
   691  			} else {
   692  				callable, meta = L.metaCall(lv)
   693  			}
   694  			// this section is inlined by go-inline
   695  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
   696  			{
   697  				ls := L
   698  				idx := lbase
   699  				if ls.uvcache != nil {
   700  					var prev *Upvalue
   701  					for uv := ls.uvcache; uv != nil; uv = uv.next {
   702  						if uv.index >= idx {
   703  							if prev != nil {
   704  								prev.next = nil
   705  							} else {
   706  								ls.uvcache = nil
   707  							}
   708  							uv.Close()
   709  						}
   710  						prev = uv
   711  					}
   712  				}
   713  			}
   714  			if callable.IsG {
   715  				luaframe := cf
   716  				L.pushCallFrame(callFrame{
   717  					Fn:         callable,
   718  					Pc:         0,
   719  					Base:       RA,
   720  					LocalBase:  RA + 1,
   721  					ReturnBase: cf.ReturnBase,
   722  					NArgs:      nargs,
   723  					NRet:       cf.NRet,
   724  					Parent:     cf,
   725  					TailCall:   0,
   726  				}, lv, meta)
   727  				if callGFunction(L, true) {
   728  					return 1
   729  				}
   730  				if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe {
   731  					return 1
   732  				}
   733  			} else {
   734  				base := cf.Base
   735  				cf.Fn = callable
   736  				cf.Pc = 0
   737  				cf.Base = RA
   738  				cf.LocalBase = RA + 1
   739  				cf.ReturnBase = cf.ReturnBase
   740  				cf.NArgs = nargs
   741  				cf.NRet = cf.NRet
   742  				cf.TailCall++
   743  				lbase := cf.LocalBase
   744  				if meta {
   745  					cf.NArgs++
   746  					L.reg.Insert(lv, cf.LocalBase)
   747  				}
   748  				// this section is inlined by go-inline
   749  				// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
   750  				{
   751  					ls := L
   752  					if cf.Fn.IsG {
   753  						ls.reg.SetTop(cf.LocalBase + cf.NArgs)
   754  					} else {
   755  						proto := cf.Fn.Proto
   756  						nargs := cf.NArgs
   757  						np := int(proto.NumParameters)
   758  						for i := nargs; i < np; i++ {
   759  							ls.reg.array[cf.LocalBase+i] = LNil
   760  							nargs = np
   761  						}
   762  
   763  						if (proto.IsVarArg & VarArgIsVarArg) == 0 {
   764  							if nargs < int(proto.NumUsedRegisters) {
   765  								nargs = int(proto.NumUsedRegisters)
   766  							}
   767  							for i := np; i < nargs; i++ {
   768  								ls.reg.array[cf.LocalBase+i] = LNil
   769  							}
   770  							ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
   771  						} else {
   772  							/* swap vararg positions:
   773  									   closure
   774  									   namedparam1 <- lbase
   775  									   namedparam2
   776  									   vararg1
   777  									   vararg2
   778  
   779  							           TO
   780  
   781  									   closure
   782  									   nil
   783  									   nil
   784  									   vararg1
   785  									   vararg2
   786  									   namedparam1 <- lbase
   787  									   namedparam2
   788  							*/
   789  							nvarargs := nargs - np
   790  							if nvarargs < 0 {
   791  								nvarargs = 0
   792  							}
   793  
   794  							ls.reg.SetTop(cf.LocalBase + nargs + np)
   795  							for i := 0; i < np; i++ {
   796  								//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
   797  								ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
   798  								//ls.reg.Set(cf.LocalBase+i, LNil)
   799  								ls.reg.array[cf.LocalBase+i] = LNil
   800  							}
   801  
   802  							if CompatVarArg {
   803  								ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
   804  								if (proto.IsVarArg & VarArgNeedsArg) != 0 {
   805  									argtb := newLTable(nvarargs, 0)
   806  									for i := 0; i < nvarargs; i++ {
   807  										argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
   808  									}
   809  									argtb.RawSetString("n", LNumber(nvarargs))
   810  									//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
   811  									ls.reg.array[cf.LocalBase+nargs+np] = argtb
   812  								} else {
   813  									ls.reg.array[cf.LocalBase+nargs+np] = LNil
   814  								}
   815  							}
   816  							cf.LocalBase += nargs
   817  							maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
   818  							ls.reg.SetTop(maxreg)
   819  						}
   820  					}
   821  				}
   822  				// this section is inlined by go-inline
   823  				// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   824  				{
   825  					rg := L.reg
   826  					regv := base
   827  					start := RA
   828  					limit := -1
   829  					n := reg.Top() - RA - 1
   830  					for i := 0; i < n; i++ {
   831  						if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   832  							rg.array[regv+i] = LNil
   833  						} else {
   834  							rg.array[regv+i] = rg.array[tidx]
   835  						}
   836  					}
   837  					rg.top = regv + n
   838  				}
   839  				cf.Base = base
   840  				cf.LocalBase = base + (cf.LocalBase - lbase + 1)
   841  			}
   842  			return 0
   843  		},
   844  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN
   845  			reg := L.reg
   846  			cf := L.currentFrame
   847  			lbase := cf.LocalBase
   848  			A := int(inst>>18) & 0xff //GETA
   849  			RA := lbase + A
   850  			B := int(inst & 0x1ff) //GETB
   851  			// this section is inlined by go-inline
   852  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
   853  			{
   854  				ls := L
   855  				idx := lbase
   856  				if ls.uvcache != nil {
   857  					var prev *Upvalue
   858  					for uv := ls.uvcache; uv != nil; uv = uv.next {
   859  						if uv.index >= idx {
   860  							if prev != nil {
   861  								prev.next = nil
   862  							} else {
   863  								ls.uvcache = nil
   864  							}
   865  							uv.Close()
   866  						}
   867  						prev = uv
   868  					}
   869  				}
   870  			}
   871  			nret := B - 1
   872  			if B == 0 {
   873  				nret = reg.Top() - RA
   874  			}
   875  			n := cf.NRet
   876  			if cf.NRet == MultRet {
   877  				n = nret
   878  			}
   879  
   880  			if L.Parent != nil && L.stack.Sp() == 1 {
   881  				// this section is inlined by go-inline
   882  				// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
   883  				{
   884  					regv := reg.Top()
   885  					start := RA
   886  					b := B
   887  					if b == 1 {
   888  						// this section is inlined by go-inline
   889  						// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
   890  						{
   891  							rg := L.reg
   892  							regm := regv
   893  							for i := 0; i < n; i++ {
   894  								rg.array[regm+i] = LNil
   895  							}
   896  							rg.top = regm + n
   897  						}
   898  					} else {
   899  						// this section is inlined by go-inline
   900  						// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   901  						{
   902  							rg := L.reg
   903  							limit := -1
   904  							for i := 0; i < n; i++ {
   905  								if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   906  									rg.array[regv+i] = LNil
   907  								} else {
   908  									rg.array[regv+i] = rg.array[tidx]
   909  								}
   910  							}
   911  							rg.top = regv + n
   912  						}
   913  					}
   914  				}
   915  				switchToParentThread(L, n, false, true)
   916  				return 1
   917  			}
   918  			islast := baseframe == L.stack.Pop() || L.stack.IsEmpty()
   919  			// this section is inlined by go-inline
   920  			// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
   921  			{
   922  				regv := cf.ReturnBase
   923  				start := RA
   924  				b := B
   925  				if b == 1 {
   926  					// this section is inlined by go-inline
   927  					// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
   928  					{
   929  						rg := L.reg
   930  						regm := regv
   931  						for i := 0; i < n; i++ {
   932  							rg.array[regm+i] = LNil
   933  						}
   934  						rg.top = regm + n
   935  					}
   936  				} else {
   937  					// this section is inlined by go-inline
   938  					// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   939  					{
   940  						rg := L.reg
   941  						limit := -1
   942  						for i := 0; i < n; i++ {
   943  							if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   944  								rg.array[regv+i] = LNil
   945  							} else {
   946  								rg.array[regv+i] = rg.array[tidx]
   947  							}
   948  						}
   949  						rg.top = regv + n
   950  					}
   951  				}
   952  			}
   953  			L.currentFrame = L.stack.Last()
   954  			if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG {
   955  				return 1
   956  			}
   957  			return 0
   958  		},
   959  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP
   960  			reg := L.reg
   961  			cf := L.currentFrame
   962  			lbase := cf.LocalBase
   963  			A := int(inst>>18) & 0xff //GETA
   964  			RA := lbase + A
   965  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   966  				if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
   967  					if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
   968  						init += step
   969  						reg.SetNumber(RA, LNumber(init))
   970  						if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
   971  							Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   972  							cf.Pc += Sbx
   973  							reg.SetNumber(RA+3, LNumber(init))
   974  						} else {
   975  							reg.SetTop(RA + 1)
   976  						}
   977  					} else {
   978  						L.RaiseError("for statement step must be a number")
   979  					}
   980  				} else {
   981  					L.RaiseError("for statement limit must be a number")
   982  				}
   983  			} else {
   984  				L.RaiseError("for statement init must be a number")
   985  			}
   986  			return 0
   987  		},
   988  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
   989  			reg := L.reg
   990  			cf := L.currentFrame
   991  			lbase := cf.LocalBase
   992  			A := int(inst>>18) & 0xff //GETA
   993  			RA := lbase + A
   994  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   995  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   996  				if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
   997  					reg.SetNumber(RA, LNumber(init-step))
   998  				} else {
   999  					L.RaiseError("for statement step must be a number")
  1000  				}
  1001  			} else {
  1002  				L.RaiseError("for statement init must be a number")
  1003  			}
  1004  			cf.Pc += Sbx
  1005  			return 0
  1006  		},
  1007  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
  1008  			reg := L.reg
  1009  			cf := L.currentFrame
  1010  			lbase := cf.LocalBase
  1011  			A := int(inst>>18) & 0xff //GETA
  1012  			RA := lbase + A
  1013  			C := int(inst>>9) & 0x1ff //GETC
  1014  			nret := C
  1015  			reg.SetTop(RA + 3)
  1016  			L.callR(2, nret, RA+3)
  1017  			reg.SetTop(RA + 2 + C + 1)
  1018  			if value := reg.Get(RA + 3); value != LNil {
  1019  				reg.Set(RA+2, value)
  1020  			} else {
  1021  				cf.Pc++
  1022  			}
  1023  			return 0
  1024  		},
  1025  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
  1026  			reg := L.reg
  1027  			cf := L.currentFrame
  1028  			lbase := cf.LocalBase
  1029  			A := int(inst>>18) & 0xff //GETA
  1030  			RA := lbase + A
  1031  			B := int(inst & 0x1ff)    //GETB
  1032  			C := int(inst>>9) & 0x1ff //GETC
  1033  			if C == 0 {
  1034  				C = int(cf.Fn.Proto.Code[cf.Pc])
  1035  				cf.Pc++
  1036  			}
  1037  			offset := (C - 1) * FieldsPerFlush
  1038  			table := reg.Get(RA).(*LTable)
  1039  			nelem := B
  1040  			if B == 0 {
  1041  				nelem = reg.Top() - RA - 1
  1042  			}
  1043  			for i := 1; i <= nelem; i++ {
  1044  				table.RawSetInt(offset+i, reg.Get(RA+i))
  1045  			}
  1046  			return 0
  1047  		},
  1048  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
  1049  			cf := L.currentFrame
  1050  			lbase := cf.LocalBase
  1051  			A := int(inst>>18) & 0xff //GETA
  1052  			RA := lbase + A
  1053  			// this section is inlined by go-inline
  1054  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
  1055  			{
  1056  				ls := L
  1057  				idx := RA
  1058  				if ls.uvcache != nil {
  1059  					var prev *Upvalue
  1060  					for uv := ls.uvcache; uv != nil; uv = uv.next {
  1061  						if uv.index >= idx {
  1062  							if prev != nil {
  1063  								prev.next = nil
  1064  							} else {
  1065  								ls.uvcache = nil
  1066  							}
  1067  							uv.Close()
  1068  						}
  1069  						prev = uv
  1070  					}
  1071  				}
  1072  			}
  1073  			return 0
  1074  		},
  1075  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
  1076  			reg := L.reg
  1077  			cf := L.currentFrame
  1078  			lbase := cf.LocalBase
  1079  			A := int(inst>>18) & 0xff //GETA
  1080  			RA := lbase + A
  1081  			Bx := int(inst & 0x3ffff) //GETBX
  1082  			proto := cf.Fn.Proto.FunctionPrototypes[Bx]
  1083  			closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
  1084  			reg.Set(RA, closure)
  1085  			for i := 0; i < int(proto.NumUpvalues); i++ {
  1086  				inst = cf.Fn.Proto.Code[cf.Pc]
  1087  				cf.Pc++
  1088  				B := opGetArgB(inst)
  1089  				switch opGetOpCode(inst) {
  1090  				case OP_MOVE:
  1091  					closure.Upvalues[i] = L.findUpvalue(lbase + B)
  1092  				case OP_GETUPVAL:
  1093  					closure.Upvalues[i] = cf.Fn.Upvalues[B]
  1094  				}
  1095  			}
  1096  			return 0
  1097  		},
  1098  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
  1099  			reg := L.reg
  1100  			cf := L.currentFrame
  1101  			lbase := cf.LocalBase
  1102  			A := int(inst>>18) & 0xff //GETA
  1103  			RA := lbase + A
  1104  			B := int(inst & 0x1ff) //GETB
  1105  			nparams := int(cf.Fn.Proto.NumParameters)
  1106  			nvarargs := cf.NArgs - nparams
  1107  			if nvarargs < 0 {
  1108  				nvarargs = 0
  1109  			}
  1110  			nwant := B - 1
  1111  			if B == 0 {
  1112  				nwant = nvarargs
  1113  			}
  1114  			// this section is inlined by go-inline
  1115  			// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
  1116  			{
  1117  				rg := reg
  1118  				regv := RA
  1119  				start := cf.Base + nparams + 1
  1120  				limit := cf.LocalBase
  1121  				n := nwant
  1122  				for i := 0; i < n; i++ {
  1123  					if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
  1124  						rg.array[regv+i] = LNil
  1125  					} else {
  1126  						rg.array[regv+i] = rg.array[tidx]
  1127  					}
  1128  				}
  1129  				rg.top = regv + n
  1130  			}
  1131  			return 0
  1132  		},
  1133  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
  1134  			return 0
  1135  		},
  1136  	}
  1137  }
  1138  
  1139  func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
  1140  	reg := L.reg
  1141  	cf := L.currentFrame
  1142  	lbase := cf.LocalBase
  1143  	A := int(inst>>18) & 0xff //GETA
  1144  	RA := lbase + A
  1145  	opcode := int(inst >> 26) //GETOPCODE
  1146  	B := int(inst & 0x1ff)    //GETB
  1147  	C := int(inst>>9) & 0x1ff //GETC
  1148  	lhs := L.rkValue(B)
  1149  	rhs := L.rkValue(C)
  1150  	v1, ok1 := lhs.assertFloat64()
  1151  	v2, ok2 := rhs.assertFloat64()
  1152  	if ok1 && ok2 {
  1153  		reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
  1154  	} else {
  1155  		reg.Set(RA, objectArith(L, opcode, lhs, rhs))
  1156  	}
  1157  	return 0
  1158  }
  1159  
  1160  func luaModulo(lhs, rhs LNumber) LNumber {
  1161  	flhs := float64(lhs)
  1162  	frhs := float64(rhs)
  1163  	v := math.Mod(flhs, frhs)
  1164  	if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
  1165  		v += frhs
  1166  	}
  1167  	return LNumber(v)
  1168  }
  1169  
  1170  func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
  1171  	switch opcode {
  1172  	case OP_ADD:
  1173  		return lhs + rhs
  1174  	case OP_SUB:
  1175  		return lhs - rhs
  1176  	case OP_MUL:
  1177  		return lhs * rhs
  1178  	case OP_DIV:
  1179  		return lhs / rhs
  1180  	case OP_MOD:
  1181  		return luaModulo(lhs, rhs)
  1182  	case OP_POW:
  1183  		flhs := float64(lhs)
  1184  		frhs := float64(rhs)
  1185  		return LNumber(math.Pow(flhs, frhs))
  1186  	}
  1187  	panic("should not reach here")
  1188  	return LNumber(0)
  1189  }
  1190  
  1191  func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
  1192  	event := ""
  1193  	switch opcode {
  1194  	case OP_ADD:
  1195  		event = "__add"
  1196  	case OP_SUB:
  1197  		event = "__sub"
  1198  	case OP_MUL:
  1199  		event = "__mul"
  1200  	case OP_DIV:
  1201  		event = "__div"
  1202  	case OP_MOD:
  1203  		event = "__mod"
  1204  	case OP_POW:
  1205  		event = "__pow"
  1206  	}
  1207  	op := L.metaOp2(lhs, rhs, event)
  1208  	if op.Type() == LTFunction {
  1209  		L.reg.Push(op)
  1210  		L.reg.Push(lhs)
  1211  		L.reg.Push(rhs)
  1212  		L.Call(2, 1)
  1213  		return L.reg.Pop()
  1214  	}
  1215  	if str, ok := lhs.(LString); ok {
  1216  		if lnum, err := parseNumber(string(str)); err == nil {
  1217  			lhs = lnum
  1218  		}
  1219  	}
  1220  	if str, ok := rhs.(LString); ok {
  1221  		if rnum, err := parseNumber(string(str)); err == nil {
  1222  			rhs = rnum
  1223  		}
  1224  	}
  1225  	if v1, ok1 := lhs.assertFloat64(); ok1 {
  1226  		if v2, ok2 := rhs.assertFloat64(); ok2 {
  1227  			return numberArith(L, opcode, LNumber(v1), LNumber(v2))
  1228  		}
  1229  	}
  1230  	L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
  1231  		strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
  1232  
  1233  	return LNil
  1234  }
  1235  
  1236  func stringConcat(L *LState, total, last int) LValue {
  1237  	rhs := L.reg.Get(last)
  1238  	total--
  1239  	for i := last - 1; total > 0; {
  1240  		lhs := L.reg.Get(i)
  1241  		if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
  1242  			op := L.metaOp2(lhs, rhs, "__concat")
  1243  			if op.Type() == LTFunction {
  1244  				L.reg.Push(op)
  1245  				L.reg.Push(lhs)
  1246  				L.reg.Push(rhs)
  1247  				L.Call(2, 1)
  1248  				rhs = L.reg.Pop()
  1249  				total--
  1250  				i--
  1251  			} else {
  1252  				L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
  1253  				return LNil
  1254  			}
  1255  		} else {
  1256  			buf := make([]string, total+1)
  1257  			buf[total] = LVAsString(rhs)
  1258  			for total > 0 {
  1259  				lhs = L.reg.Get(i)
  1260  				if !LVCanConvToString(lhs) {
  1261  					break
  1262  				}
  1263  				buf[total-1] = LVAsString(lhs)
  1264  				i--
  1265  				total--
  1266  			}
  1267  			rhs = LString(strings.Join(buf, ""))
  1268  		}
  1269  	}
  1270  	return rhs
  1271  }
  1272  
  1273  func lessThan(L *LState, lhs, rhs LValue) bool {
  1274  	// optimization for numbers
  1275  	if v1, ok1 := lhs.assertFloat64(); ok1 {
  1276  		if v2, ok2 := rhs.assertFloat64(); ok2 {
  1277  			return v1 < v2
  1278  		}
  1279  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1280  	}
  1281  	if lhs.Type() != rhs.Type() {
  1282  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1283  		return false
  1284  	}
  1285  	ret := false
  1286  	switch lhs.Type() {
  1287  	case LTString:
  1288  		ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
  1289  	default:
  1290  		ret = objectRationalWithError(L, lhs, rhs, "__lt")
  1291  	}
  1292  	return ret
  1293  }
  1294  
  1295  func equals(L *LState, lhs, rhs LValue, raw bool) bool {
  1296  	if lhs.Type() != rhs.Type() {
  1297  		return false
  1298  	}
  1299  
  1300  	ret := false
  1301  	switch lhs.Type() {
  1302  	case LTNil:
  1303  		ret = true
  1304  	case LTNumber:
  1305  		v1, _ := lhs.assertFloat64()
  1306  		v2, _ := rhs.assertFloat64()
  1307  		ret = v1 == v2
  1308  	case LTBool:
  1309  		ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
  1310  	case LTString:
  1311  		ret = string(lhs.(LString)) == string(rhs.(LString))
  1312  	case LTUserData, LTTable:
  1313  		if lhs == rhs {
  1314  			ret = true
  1315  		} else if !raw {
  1316  			switch objectRational(L, lhs, rhs, "__eq") {
  1317  			case 1:
  1318  				ret = true
  1319  			default:
  1320  				ret = false
  1321  			}
  1322  		}
  1323  	default:
  1324  		ret = lhs == rhs
  1325  	}
  1326  	return ret
  1327  }
  1328  
  1329  func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
  1330  	switch objectRational(L, lhs, rhs, event) {
  1331  	case 1:
  1332  		return true
  1333  	case 0:
  1334  		return false
  1335  	}
  1336  	L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1337  	return false
  1338  }
  1339  
  1340  func objectRational(L *LState, lhs, rhs LValue, event string) int {
  1341  	m1 := L.metaOp1(lhs, event)
  1342  	m2 := L.metaOp1(rhs, event)
  1343  	if m1.Type() == LTFunction && m1 == m2 {
  1344  		L.reg.Push(m1)
  1345  		L.reg.Push(lhs)
  1346  		L.reg.Push(rhs)
  1347  		L.Call(2, 1)
  1348  		if LVAsBool(L.reg.Pop()) {
  1349  			return 1
  1350  		}
  1351  		return 0
  1352  	}
  1353  	return -1
  1354  }