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