tile38/vendor/github.com/yuin/gopher-lua/vm.go

1719 lines
45 KiB
Go

package lua
////////////////////////////////////////////////////////
// This file was generated by go-inline. DO NOT EDIT. //
////////////////////////////////////////////////////////
import (
"fmt"
"math"
"strings"
)
func mainLoop(L *LState, baseframe *callFrame) {
var inst uint32
var cf *callFrame
if L.stack.IsEmpty() {
return
}
L.currentFrame = L.stack.Last()
if L.currentFrame.Fn.IsG {
callGFunction(L, false)
return
}
for {
cf = L.currentFrame
inst = cf.Fn.Proto.Code[cf.Pc]
cf.Pc++
if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 {
return
}
}
}
func mainLoopWithContext(L *LState, baseframe *callFrame) {
var inst uint32
var cf *callFrame
if L.stack.IsEmpty() {
return
}
L.currentFrame = L.stack.Last()
if L.currentFrame.Fn.IsG {
callGFunction(L, false)
return
}
for {
cf = L.currentFrame
inst = cf.Fn.Proto.Code[cf.Pc]
cf.Pc++
select {
case <-L.ctx.Done():
L.RaiseError(L.ctx.Err().Error())
return
default:
if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 {
return
}
}
}
}
// regv is the first target register to copy the return values to.
// It can be reg.top, indicating that the copied values are going into new registers, or it can be below reg.top
// Indicating that the values should be within the existing registers.
// b is the available number of return values + 1.
// n is the desired number of return values.
// If n more than the available return values then the extra values are set to nil.
// When this function returns the top of the registry will be set to regv+n.
func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start
if b == 1 {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
} else {
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := L.reg
limit := -1
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
if b > 1 && n > (b-1) {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv + b - 1
n := n - (b - 1)
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
}
}
} // +inline-end
func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) {
parent := L.Parent
if parent == nil {
L.RaiseError("can not yield from outside of a coroutine")
}
L.G.CurrentThread = parent
L.Parent = nil
if !L.wrapped {
if haserror {
parent.Push(LFalse)
} else {
parent.Push(LTrue)
}
}
L.XMoveTo(parent, nargs)
L.stack.Pop()
offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase
L.currentFrame = L.stack.Last()
L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions)
if kill {
L.kill()
}
}
func callGFunction(L *LState, tailcall bool) bool {
frame := L.currentFrame
gfnret := frame.Fn.GFunction(L)
if tailcall {
L.currentFrame = L.RemoveCallerFrame()
}
if gfnret < 0 {
switchToParentThread(L, L.GetTop(), false, false)
return true
}
wantret := frame.NRet
if wantret == MultRet {
wantret = gfnret
}
if tailcall && L.Parent != nil && L.stack.Sp() == 1 {
switchToParentThread(L, wantret, false, true)
return true
}
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := L.reg
regv := frame.ReturnBase
start := L.reg.Top() - gfnret
limit := -1
n := wantret
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
L.stack.Pop()
L.currentFrame = L.stack.Last()
return false
}
func threadRun(L *LState) {
if L.stack.IsEmpty() {
return
}
defer func() {
if rcv := recover(); rcv != nil {
var lv LValue
if v, ok := rcv.(*ApiError); ok {
lv = v.Object
} else {
lv = LString(fmt.Sprint(rcv))
}
if parent := L.Parent; parent != nil {
if L.wrapped {
L.Push(lv)
parent.Panic(L)
} else {
L.SetTop(0)
L.Push(lv)
switchToParentThread(L, 1, true, true)
}
} else {
panic(rcv)
}
}
}()
L.mainLoop(L, nil)
}
type instFunc func(*LState, uint32, *callFrame) int
var jumpTable [opCodeMax + 1]instFunc
func init() {
jumpTable = [opCodeMax + 1]instFunc{
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
reg.Set(RA, reg.Get(lbase+B))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
reg.Set(lbase+A, reg.Get(lbase+B))
code := cf.Fn.Proto.Code
pc := cf.Pc
for i := 0; i < C; i++ {
inst = code[pc]
pc++
A = int(inst>>18) & 0xff //GETA
B = int(inst & 0x1ff) //GETB
reg.Set(lbase+A, reg.Get(lbase+B))
}
cf.Pc = pc
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
Bx := int(inst & 0x3ffff) //GETBX
reg.Set(RA, cf.Fn.Proto.Constants[Bx])
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
if B != 0 {
reg.Set(RA, LTrue)
} else {
reg.Set(RA, LFalse)
}
if C != 0 {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
for i := RA; i <= lbase+B; i++ {
reg.Set(i, LNil)
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
reg.Set(RA, cf.Fn.Upvalues[B].Value())
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
Bx := int(inst & 0x3ffff) //GETBX
//reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx]))
reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C)))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C)))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
Bx := int(inst & 0x3ffff) //GETBX
//L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA))
L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
cf.Fn.Upvalues[B].SetValue(reg.Get(RA))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
reg.Set(RA, newLTable(B, C))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
selfobj := reg.Get(lbase + B)
reg.Set(RA, L.getFieldString(selfobj, L.rkString(C)))
reg.Set(RA+1, selfobj)
return 0
},
opArith, // OP_ADD
opArith, // OP_SUB
opArith, // OP_MUL
opArith, // OP_DIV
opArith, // OP_MOD
opArith, // OP_POW
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
unaryv := L.rkValue(B)
if nm, ok := unaryv.(LNumber); ok {
reg.SetNumber(RA, -nm)
} else {
op := L.metaOp1(unaryv, "__unm")
if op.Type() == LTFunction {
reg.Push(op)
reg.Push(unaryv)
L.Call(1, 1)
reg.Set(RA, reg.Pop())
} else if str, ok1 := unaryv.(LString); ok1 {
if num, err := parseNumber(string(str)); err == nil {
reg.Set(RA, -num)
} else {
L.RaiseError("__unm undefined")
}
} else {
L.RaiseError("__unm undefined")
}
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
if LVIsFalse(reg.Get(lbase + B)) {
reg.Set(RA, LTrue)
} else {
reg.Set(RA, LFalse)
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
switch lv := L.rkValue(B).(type) {
case LString:
reg.SetNumber(RA, LNumber(len(lv)))
default:
op := L.metaOp1(lv, "__len")
if op.Type() == LTFunction {
reg.Push(op)
reg.Push(lv)
L.Call(1, 1)
ret := reg.Pop()
if ret.Type() == LTNumber {
reg.SetNumber(RA, ret.(LNumber))
} else {
reg.SetNumber(RA, LNumber(0))
}
} else if lv.Type() == LTTable {
reg.SetNumber(RA, LNumber(lv.(*LTable).Len()))
} else {
L.RaiseError("__len undefined")
}
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
RC := lbase + C
RB := lbase + B
reg.Set(RA, stringConcat(L, RC-RB+1, RC))
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP
cf := L.currentFrame
Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
cf.Pc += Sbx
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ
cf := L.currentFrame
A := int(inst>>18) & 0xff //GETA
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
ret := equals(L, L.rkValue(B), L.rkValue(C), false)
v := 1
if ret {
v = 0
}
if v == A {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT
cf := L.currentFrame
A := int(inst>>18) & 0xff //GETA
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
ret := lessThan(L, L.rkValue(B), L.rkValue(C))
v := 1
if ret {
v = 0
}
if v == A {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE
cf := L.currentFrame
A := int(inst>>18) & 0xff //GETA
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
lhs := L.rkValue(B)
rhs := L.rkValue(C)
ret := false
if v1, ok1 := lhs.assertFloat64(); ok1 {
if v2, ok2 := rhs.assertFloat64(); ok2 {
ret = v1 <= v2
} else {
L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
}
} else {
if lhs.Type() != rhs.Type() {
L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
}
switch lhs.Type() {
case LTString:
ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0
default:
switch objectRational(L, lhs, rhs, "__le") {
case 1:
ret = true
case 0:
ret = false
default:
ret = !objectRationalWithError(L, rhs, lhs, "__lt")
}
}
}
v := 1
if ret {
v = 0
}
if v == A {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
C := int(inst>>9) & 0x1ff //GETC
if LVAsBool(reg.Get(RA)) == (C == 0) {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) {
reg.Set(RA, value)
} else {
cf.Pc++
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
nargs := B - 1
if B == 0 {
nargs = reg.Top() - (RA + 1)
}
lv := reg.Get(RA)
nret := C - 1
var callable *LFunction
var meta bool
if fn, ok := lv.assertFunction(); ok {
callable = fn
meta = false
} else {
callable, meta = L.metaCall(lv)
}
// this section is inlined by go-inline
// source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go'
{
ls := L
cf := callFrame{Fn: callable, Pc: 0, Base: RA, LocalBase: RA + 1, ReturnBase: RA, NArgs: nargs, NRet: nret, Parent: cf, TailCall: 0}
fn := lv
if meta {
cf.NArgs++
ls.reg.Insert(fn, cf.LocalBase)
}
if cf.Fn == nil {
ls.RaiseError("attempt to call a non-function object")
}
if ls.stack.IsFull() {
ls.RaiseError("stack overflow")
}
ls.stack.Push(cf)
newcf := ls.stack.Last()
// this section is inlined by go-inline
// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
{
cf := newcf
if cf.Fn.IsG {
ls.reg.SetTop(cf.LocalBase + cf.NArgs)
} else {
proto := cf.Fn.Proto
nargs := cf.NArgs
np := int(proto.NumParameters)
newSize := cf.LocalBase + np
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
rg := ls.reg
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := nargs; i < np; i++ {
ls.reg.array[cf.LocalBase+i] = LNil
nargs = np
}
if (proto.IsVarArg & VarArgIsVarArg) == 0 {
if nargs < int(proto.NumUsedRegisters) {
nargs = int(proto.NumUsedRegisters)
}
newSize = cf.LocalBase + nargs
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
rg := ls.reg
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := np; i < nargs; i++ {
ls.reg.array[cf.LocalBase+i] = LNil
}
ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
} else {
/* swap vararg positions:
closure
namedparam1 <- lbase
namedparam2
vararg1
vararg2
TO
closure
nil
nil
vararg1
vararg2
namedparam1 <- lbase
namedparam2
*/
nvarargs := nargs - np
if nvarargs < 0 {
nvarargs = 0
}
ls.reg.SetTop(cf.LocalBase + nargs + np)
for i := 0; i < np; i++ {
//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
//ls.reg.Set(cf.LocalBase+i, LNil)
ls.reg.array[cf.LocalBase+i] = LNil
}
if CompatVarArg {
ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
if (proto.IsVarArg & VarArgNeedsArg) != 0 {
argtb := newLTable(nvarargs, 0)
for i := 0; i < nvarargs; i++ {
argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
}
argtb.RawSetString("n", LNumber(nvarargs))
//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
ls.reg.array[cf.LocalBase+nargs+np] = argtb
} else {
ls.reg.array[cf.LocalBase+nargs+np] = LNil
}
}
cf.LocalBase += nargs
maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
ls.reg.SetTop(maxreg)
}
}
}
ls.currentFrame = newcf
}
if callable.IsG && callGFunction(L, false) {
return 1
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
nargs := B - 1
if B == 0 {
nargs = reg.Top() - (RA + 1)
}
lv := reg.Get(RA)
var callable *LFunction
var meta bool
if fn, ok := lv.assertFunction(); ok {
callable = fn
meta = false
} else {
callable, meta = L.metaCall(lv)
}
if callable == nil {
L.RaiseError("attempt to call a non-function object")
}
// this section is inlined by go-inline
// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
{
ls := L
idx := lbase
if ls.uvcache != nil {
var prev *Upvalue
for uv := ls.uvcache; uv != nil; uv = uv.next {
if uv.index >= idx {
if prev != nil {
prev.next = nil
} else {
ls.uvcache = nil
}
uv.Close()
}
prev = uv
}
}
}
if callable.IsG {
luaframe := cf
L.pushCallFrame(callFrame{
Fn: callable,
Pc: 0,
Base: RA,
LocalBase: RA + 1,
ReturnBase: cf.ReturnBase,
NArgs: nargs,
NRet: cf.NRet,
Parent: cf,
TailCall: 0,
}, lv, meta)
if callGFunction(L, true) {
return 1
}
if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe {
return 1
}
} else {
base := cf.Base
cf.Fn = callable
cf.Pc = 0
cf.Base = RA
cf.LocalBase = RA + 1
cf.ReturnBase = cf.ReturnBase
cf.NArgs = nargs
cf.NRet = cf.NRet
cf.TailCall++
lbase := cf.LocalBase
if meta {
cf.NArgs++
L.reg.Insert(lv, cf.LocalBase)
}
// this section is inlined by go-inline
// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
{
ls := L
if cf.Fn.IsG {
ls.reg.SetTop(cf.LocalBase + cf.NArgs)
} else {
proto := cf.Fn.Proto
nargs := cf.NArgs
np := int(proto.NumParameters)
newSize := cf.LocalBase + np
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
rg := ls.reg
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := nargs; i < np; i++ {
ls.reg.array[cf.LocalBase+i] = LNil
nargs = np
}
if (proto.IsVarArg & VarArgIsVarArg) == 0 {
if nargs < int(proto.NumUsedRegisters) {
nargs = int(proto.NumUsedRegisters)
}
newSize = cf.LocalBase + nargs
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
rg := ls.reg
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := np; i < nargs; i++ {
ls.reg.array[cf.LocalBase+i] = LNil
}
ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
} else {
/* swap vararg positions:
closure
namedparam1 <- lbase
namedparam2
vararg1
vararg2
TO
closure
nil
nil
vararg1
vararg2
namedparam1 <- lbase
namedparam2
*/
nvarargs := nargs - np
if nvarargs < 0 {
nvarargs = 0
}
ls.reg.SetTop(cf.LocalBase + nargs + np)
for i := 0; i < np; i++ {
//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
//ls.reg.Set(cf.LocalBase+i, LNil)
ls.reg.array[cf.LocalBase+i] = LNil
}
if CompatVarArg {
ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
if (proto.IsVarArg & VarArgNeedsArg) != 0 {
argtb := newLTable(nvarargs, 0)
for i := 0; i < nvarargs; i++ {
argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
}
argtb.RawSetString("n", LNumber(nvarargs))
//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
ls.reg.array[cf.LocalBase+nargs+np] = argtb
} else {
ls.reg.array[cf.LocalBase+nargs+np] = LNil
}
}
cf.LocalBase += nargs
maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
ls.reg.SetTop(maxreg)
}
}
}
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := L.reg
regv := base
start := RA
limit := -1
n := reg.Top() - RA - 1
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
cf.Base = base
cf.LocalBase = base + (cf.LocalBase - lbase + 1)
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
// this section is inlined by go-inline
// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
{
ls := L
idx := lbase
if ls.uvcache != nil {
var prev *Upvalue
for uv := ls.uvcache; uv != nil; uv = uv.next {
if uv.index >= idx {
if prev != nil {
prev.next = nil
} else {
ls.uvcache = nil
}
uv.Close()
}
prev = uv
}
}
}
nret := B - 1
if B == 0 {
nret = reg.Top() - RA
}
n := cf.NRet
if cf.NRet == MultRet {
n = nret
}
if L.Parent != nil && L.stack.Sp() == 1 {
// this section is inlined by go-inline
// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
{
regv := reg.Top()
start := RA
b := B
if b == 1 {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
} else {
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := L.reg
limit := -1
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
if b > 1 && n > (b-1) {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv + b - 1
n := n - (b - 1)
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
}
}
}
switchToParentThread(L, n, false, true)
return 1
}
islast := baseframe == L.stack.Pop() || L.stack.IsEmpty()
// this section is inlined by go-inline
// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
{
regv := cf.ReturnBase
start := RA
b := B
if b == 1 {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
} else {
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := L.reg
limit := -1
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
if b > 1 && n > (b-1) {
// this section is inlined by go-inline
// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
{
rg := L.reg
regm := regv + b - 1
n := n - (b - 1)
newSize := regm + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
for i := 0; i < n; i++ {
rg.array[regm+i] = LNil
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regm + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
}
}
}
L.currentFrame = L.stack.Last()
if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG {
return 1
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
init += step
reg.SetNumber(RA, LNumber(init))
if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
cf.Pc += Sbx
reg.SetNumber(RA+3, LNumber(init))
} else {
reg.SetTop(RA + 1)
}
} else {
L.RaiseError("for statement step must be a number")
}
} else {
L.RaiseError("for statement limit must be a number")
}
} else {
L.RaiseError("for statement init must be a number")
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
reg.SetNumber(RA, LNumber(init-step))
} else {
L.RaiseError("for statement step must be a number")
}
} else {
L.RaiseError("for statement init must be a number")
}
cf.Pc += Sbx
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
C := int(inst>>9) & 0x1ff //GETC
nret := C
reg.SetTop(RA + 3 + 2)
reg.Set(RA+3+2, reg.Get(RA+2))
reg.Set(RA+3+1, reg.Get(RA+1))
reg.Set(RA+3, reg.Get(RA))
L.callR(2, nret, RA+3)
if value := reg.Get(RA + 3); value != LNil {
reg.Set(RA+2, value)
pc := cf.Fn.Proto.Code[cf.Pc]
cf.Pc += int(pc&0x3ffff) - opMaxArgSbx
}
cf.Pc++
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
if C == 0 {
C = int(cf.Fn.Proto.Code[cf.Pc])
cf.Pc++
}
offset := (C - 1) * FieldsPerFlush
table := reg.Get(RA).(*LTable)
nelem := B
if B == 0 {
nelem = reg.Top() - RA - 1
}
for i := 1; i <= nelem; i++ {
table.RawSetInt(offset+i, reg.Get(RA+i))
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
// this section is inlined by go-inline
// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
{
ls := L
idx := RA
if ls.uvcache != nil {
var prev *Upvalue
for uv := ls.uvcache; uv != nil; uv = uv.next {
if uv.index >= idx {
if prev != nil {
prev.next = nil
} else {
ls.uvcache = nil
}
uv.Close()
}
prev = uv
}
}
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
Bx := int(inst & 0x3ffff) //GETBX
proto := cf.Fn.Proto.FunctionPrototypes[Bx]
closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
reg.Set(RA, closure)
for i := 0; i < int(proto.NumUpvalues); i++ {
inst = cf.Fn.Proto.Code[cf.Pc]
cf.Pc++
B := opGetArgB(inst)
switch opGetOpCode(inst) {
case OP_MOVE:
closure.Upvalues[i] = L.findUpvalue(lbase + B)
case OP_GETUPVAL:
closure.Upvalues[i] = cf.Fn.Upvalues[B]
}
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
B := int(inst & 0x1ff) //GETB
nparams := int(cf.Fn.Proto.NumParameters)
nvarargs := cf.NArgs - nparams
if nvarargs < 0 {
nvarargs = 0
}
nwant := B - 1
if B == 0 {
nwant = nvarargs
}
// this section is inlined by go-inline
// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
{
rg := reg
regv := RA
start := cf.Base + nparams + 1
limit := cf.LocalBase
n := nwant
newSize := regv + n
// this section is inlined by go-inline
// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go'
{
requiredSize := newSize
if requiredSize > cap(rg.array) {
rg.resize(requiredSize)
}
}
if limit == -1 || limit > rg.top {
limit = rg.top
}
for i := 0; i < n; i++ {
srcIdx := start + i
if srcIdx >= limit || srcIdx < 0 {
rg.array[regv+i] = LNil
} else {
rg.array[regv+i] = rg.array[srcIdx]
}
}
// values beyond top don't need to be valid LValues, so setting them to nil is fine
// setting them to nil rather than LNil lets us invoke the golang memclr opto
oldtop := rg.top
rg.top = regv + n
if rg.top < oldtop {
nilRange := rg.array[rg.top:oldtop]
for i := range nilRange {
nilRange[i] = nil
}
}
}
return 0
},
func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
return 0
},
}
}
func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
reg := L.reg
cf := L.currentFrame
lbase := cf.LocalBase
A := int(inst>>18) & 0xff //GETA
RA := lbase + A
opcode := int(inst >> 26) //GETOPCODE
B := int(inst & 0x1ff) //GETB
C := int(inst>>9) & 0x1ff //GETC
lhs := L.rkValue(B)
rhs := L.rkValue(C)
v1, ok1 := lhs.assertFloat64()
v2, ok2 := rhs.assertFloat64()
if ok1 && ok2 {
reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
} else {
reg.Set(RA, objectArith(L, opcode, lhs, rhs))
}
return 0
}
func luaModulo(lhs, rhs LNumber) LNumber {
flhs := float64(lhs)
frhs := float64(rhs)
v := math.Mod(flhs, frhs)
if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
v += frhs
}
return LNumber(v)
}
func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
switch opcode {
case OP_ADD:
return lhs + rhs
case OP_SUB:
return lhs - rhs
case OP_MUL:
return lhs * rhs
case OP_DIV:
return lhs / rhs
case OP_MOD:
return luaModulo(lhs, rhs)
case OP_POW:
flhs := float64(lhs)
frhs := float64(rhs)
return LNumber(math.Pow(flhs, frhs))
}
panic("should not reach here")
return LNumber(0)
}
func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
event := ""
switch opcode {
case OP_ADD:
event = "__add"
case OP_SUB:
event = "__sub"
case OP_MUL:
event = "__mul"
case OP_DIV:
event = "__div"
case OP_MOD:
event = "__mod"
case OP_POW:
event = "__pow"
}
op := L.metaOp2(lhs, rhs, event)
if op.Type() == LTFunction {
L.reg.Push(op)
L.reg.Push(lhs)
L.reg.Push(rhs)
L.Call(2, 1)
return L.reg.Pop()
}
if str, ok := lhs.(LString); ok {
if lnum, err := parseNumber(string(str)); err == nil {
lhs = lnum
}
}
if str, ok := rhs.(LString); ok {
if rnum, err := parseNumber(string(str)); err == nil {
rhs = rnum
}
}
if v1, ok1 := lhs.assertFloat64(); ok1 {
if v2, ok2 := rhs.assertFloat64(); ok2 {
return numberArith(L, opcode, LNumber(v1), LNumber(v2))
}
}
L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
return LNil
}
func stringConcat(L *LState, total, last int) LValue {
rhs := L.reg.Get(last)
total--
for i := last - 1; total > 0; {
lhs := L.reg.Get(i)
if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
op := L.metaOp2(lhs, rhs, "__concat")
if op.Type() == LTFunction {
L.reg.Push(op)
L.reg.Push(lhs)
L.reg.Push(rhs)
L.Call(2, 1)
rhs = L.reg.Pop()
total--
i--
} else {
L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
return LNil
}
} else {
buf := make([]string, total+1)
buf[total] = LVAsString(rhs)
for total > 0 {
lhs = L.reg.Get(i)
if !LVCanConvToString(lhs) {
break
}
buf[total-1] = LVAsString(lhs)
i--
total--
}
rhs = LString(strings.Join(buf, ""))
}
}
return rhs
}
func lessThan(L *LState, lhs, rhs LValue) bool {
// optimization for numbers
if v1, ok1 := lhs.assertFloat64(); ok1 {
if v2, ok2 := rhs.assertFloat64(); ok2 {
return v1 < v2
}
L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
}
if lhs.Type() != rhs.Type() {
L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
return false
}
ret := false
switch lhs.Type() {
case LTString:
ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
default:
ret = objectRationalWithError(L, lhs, rhs, "__lt")
}
return ret
}
func equals(L *LState, lhs, rhs LValue, raw bool) bool {
if lhs.Type() != rhs.Type() {
return false
}
ret := false
switch lhs.Type() {
case LTNil:
ret = true
case LTNumber:
v1, _ := lhs.assertFloat64()
v2, _ := rhs.assertFloat64()
ret = v1 == v2
case LTBool:
ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
case LTString:
ret = string(lhs.(LString)) == string(rhs.(LString))
case LTUserData, LTTable:
if lhs == rhs {
ret = true
} else if !raw {
switch objectRational(L, lhs, rhs, "__eq") {
case 1:
ret = true
default:
ret = false
}
}
default:
ret = lhs == rhs
}
return ret
}
func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
switch objectRational(L, lhs, rhs, event) {
case 1:
return true
case 0:
return false
}
L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
return false
}
func objectRational(L *LState, lhs, rhs LValue, event string) int {
m1 := L.metaOp1(lhs, event)
m2 := L.metaOp1(rhs, event)
if m1.Type() == LTFunction && m1 == m2 {
L.reg.Push(m1)
L.reg.Push(lhs)
L.reg.Push(rhs)
L.Call(2, 1)
if LVAsBool(L.reg.Pop()) {
return 1
}
return 0
}
return -1
}