from lua_stack import LuaStack
from lua_type import LuaType
from lua_value import LuaValue
from arith_op import ArithOp
from arithmetic import Arithmetic
from cmp_op import CmpOp
from compare import Compare
from lua_table import LuaTable
from binary_chunk import BinaryChunk
from closure import Closure
from opcode import Instruction
from opcode import OpCode
from thread_state import ThreadStatus
classLuaState:def__init__(self):
self.stack = LuaStack()# ...# vmdefget_pc(self):return self.stack.pc
defadd_pc(self, n):
self.stack.pc += n
deffetch(self):
code = self.stack.closure.proto.get_code()[self.stack.pc]
self.stack.pc +=1return code
defget_const(self, idx):
self.stack.push(self.stack.closure.proto.get_constants()[idx])defget_rk(self, rk):if rk >0xff:# constant
self.get_const(rk &0xff)else:# register
self.push_value(rk +1)# ...defload(self, chunk):
bc = BinaryChunk(chunk)
proto = bc.undump()
closure = Closure(proto)
self.stack.push(closure)return ThreadStatus.OK
defcall(self, nargs, nresults):
val = self.stack.get(-(nargs+1))ifisinstance(val, Closure):print('call %s<%d,%d>'%(val.proto.get_source(), val.proto.get_line_defined(),
val.proto.get_last_line_defined()))
self.call_lua_closure(nargs, nresults, val)else:raise Exception('not function')defcall_lua_closure(self, nargs, nresults, c):
nregs = c.proto.get_max_stack_size()
nparams = c.proto.get_num_params()
is_vararg = c.proto.get_is_vararg()# create new lua stack
new_stack = LuaStack()
new_stack.closure = c
# pass args, pop func
func_and_args = self.stack.popn(nargs+1)
new_stack.pushn(func_and_args[1:], nparams)if nargs > nparams and is_vararg:
new_stack.varargs = func_and_args[nparams+1:]# run closure
self.push_lua_stack(new_stack)
self.set_top(nregs)
self.run_lua_closure()
self.pop_lua_stack()# return resultsif nresults !=0:
results = new_stack.popn(new_stack.top()- nregs)
self.stack.check(len(results))
self.stack.pushn(results, nresults)defrun_lua_closure(self):whileTrue:
pc = self.get_pc()+1
inst = Instruction(self.fetch())
inst.execute(self)print('[%02d] %-12s '%(pc, inst.op_name()), end='')
self.print_stack()if inst.op_code()== OpCode.RETURN:breakdefpush_lua_stack(self, s):
s.caller = self.stack
self.stack = s
defpop_lua_stack(self):
s = self.stack
self.stack = s.caller
s.caller =Nonedefregister_count(self):return self.stack.closure.proto.get_max_stack_size()defload_vararg(self, n):if n <0:
n =len(self.stack.varargs)
self.stack.check(n)
self.stack.pushn(self.stack.varargs, n)defload_proto(self, idx):
proto = self.stack.closure.proto.get_protos()[idx]
c = Closure(proto)
self.stack.push(c)
instructions
# R(A)[(C-1)*LFIELDS_PER_FLUSH+i] := R(A+i), 1 <= i <= Bdefsetlist(inst, vm):
a, b, c = inst.a_b_c()
a +=1
c = c -1if c >0else inst.ax(vm.fetch())
is_zero = b ==0if is_zero:
b = vm.to_integer(-1)- a -1
vm.pop(1)
vm.check_stack(1)
idx = c * LFIELDS_PER_FLUSH
for i inrange(1, b+1):
idx +=1
vm.push_value(a+i)
vm.set_i(a, idx)if is_zero:for i inrange(vm.register_count()+1, vm.get_top()+1):
idx +=1
vm.push_value(i)
vm.set_i(a, idx)
vm.set_top(vm.register_count())# R(A+1) := R(B); R(A) := R(B)[RK(C)]defluaself(inst, vm):
a, b, c = inst.a_b_c()
a +=1
b +=1
vm.copy(b, a+1)
vm.get_rk(c)
vm.get_table(b)
vm.replace(a)# R(A) := closure(KPROTO[Bx])defclosure(inst, vm):
a, bx = inst.a_bx()
a +=1
vm.load_proto(bx)
vm.replace(a)defvararg(inst, vm):
a, b, _ = inst.a_b_c()
a +=1if b !=1:
vm.load_vararg(b-1)
pop_results(a, b, vm)deftailcall(inst, vm):
a, b, _ = inst.a_b_c()
a +=1
c =0
nargs = push_func_and_args(a, b, vm)
vm.call(nargs, c-1)
pop_results(a, c, vm)defcall(inst, vm):
a, b, c = inst.a_b_c()
a +=1
nargs = push_func_and_args(a, b, vm)
vm.call(nargs, c-1)
pop_results(a, c, vm)defluaret(inst, vm):
a, b, _ = inst.a_b_c()
a +=1if b ==1:passelif b >1:
vm.check_stack(b-1)for i inrange(a, a+b-1):
vm.push_value(i)else:
fix_stack(a, vm)defpush_func_and_args(a, b, vm):if b >=1:
vm.check_stack(b)for i inrange(a, a+b):
vm.push_value(i)return b-1else:
fix_stack(a, vm)return vm.get_top()- vm.register_count()-1deffix_stack(a, vm):
x = vm.to_integer(-1)
vm.pop(1)
vm.check_stack(x-a)for i inrange(a, x):
vm.push_value(i)
vm.rotate(vm.register_count()+1, x-a)defpop_results(a, c, vm):if c ==1:passelif c >1:for i inrange(a+c-2, a-1,-1):
vm.replace(i)else:
vm.check_stack(1)
vm.push_integer(a)
op_codes =[# T A B C mode name action
OpCode(0,1, OpArgR, OpArgN, IABC,"MOVE ", move),# R(A) := R(B)
OpCode(0,1, OpArgK, OpArgN, IABx,"LOADK ", loadk),# R(A) := Kst(Bx)
OpCode(0,1, OpArgN, OpArgN, IABx,"LOADKX ", loadkx),# R(A) := Kst(extra arg)
OpCode(0,1, OpArgU, OpArgU, IABC,"LOADBOOL", loadbool),# R(A) := (bool)B; if (C) pc++
OpCode(0,1, OpArgU, OpArgN, IABC,"LOADNIL ", loadnil),# R(A), R(A+1), ..., R(A+B) := nil
OpCode(0,1, OpArgU, OpArgN, IABC,"GETUPVAL",None),# R(A) := UpValue[B]
OpCode(0,1, OpArgU, OpArgK, IABC,"GETTABUP",None),# R(A) := UpValue[B][RK(C)]
OpCode(0,1, OpArgR, OpArgK, IABC,"GETTABLE", gettable),# R(A) := R(B)[RK(C)]
OpCode(0,0, OpArgK, OpArgK, IABC,"SETTABUP",None),# UpValue[A][RK(B)] := RK(C)
OpCode(0,0, OpArgU, OpArgN, IABC,"SETUPVAL",None),# UpValue[B] := R(A)
OpCode(0,0, OpArgK, OpArgK, IABC,"SETTABLE", settable),# R(A)[RK(B)] := RK(C)
OpCode(0,1, OpArgU, OpArgU, IABC,"NEWTABLE", newtable),# R(A) := {} (size = B,C)
OpCode(0,1, OpArgR, OpArgK, IABC,"SELF ", luaself),# R(A+1) := R(B); R(A) := R(B)[RK(C)]
OpCode(0,1, OpArgK, OpArgK, IABC,"ADD ", add),# R(A) := RK(B) + RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"SUB ", sub),# R(A) := RK(B) - RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"MUL ", mul),# R(A) := RK(B) * RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"MOD ", mod),# R(A) := RK(B) % RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"POW ", luapow),# R(A) := RK(B) ^ RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"DIV ", div),# R(A) := RK(B) / RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"IDIV ", idiv),# R(A) := RK(B) // RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"BAND ", band),# R(A) := RK(B) & RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"BOR ", bor),# R(A) := RK(B) | RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"BXOR ", bxor),# R(A) := RK(B) ~ RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"SHL ", shl),# R(A) := RK(B) << RK(C)
OpCode(0,1, OpArgK, OpArgK, IABC,"SHR ", shr),# R(A) := RK(B) >> RK(C)
OpCode(0,1, OpArgR, OpArgN, IABC,"UNM ", unm),# R(A) := -R(B)
OpCode(0,1, OpArgR, OpArgN, IABC,"BNOT ", bnot),# R(A) := ~R(B)
OpCode(0,1, OpArgR, OpArgN, IABC,"NOT ", luanot),# R(A) := not R(B)
OpCode(0,1, OpArgR, OpArgN, IABC,"LEN ", length),# R(A) := length of R(B)
OpCode(0,1, OpArgR, OpArgR, IABC,"CONCAT ", concat),# R(A) := R(B).. ... ..R(C)
OpCode(0,0, OpArgR, OpArgN, IAsBx,"JMP ", jmp),# pc+=sBx; if (A) close all upvalues >= R(A - 1)
OpCode(1,0, OpArgK, OpArgK, IABC,"EQ ", eq),# if ((RK(B) == RK(C)) ~= A) then pc++
OpCode(1,0, OpArgK, OpArgK, IABC,"LT ", lt),# if ((RK(B) < RK(C)) ~= A) then pc++
OpCode(1,0, OpArgK, OpArgK, IABC,"LE ", le),# if ((RK(B) <= RK(C)) ~= A) then pc++
OpCode(1,0, OpArgN, OpArgU, IABC,"TEST ", test),# if not (R(A) <=> C) then pc++
OpCode(1,1, OpArgR, OpArgU, IABC,"TESTSET ", testset),# if (R(B) <=> C) then R(A) := R(B) else pc++
OpCode(0,1, OpArgU, OpArgU, IABC,"CALL ", call),# R(A), ...,R(A+C-2) := R(A)(R(A+1), ...,R(A+B-1))
OpCode(0,1, OpArgU, OpArgU, IABC,"TAILCALL", tailcall),# return R(A)(R(A+1), ... ,R(A+B-1))
OpCode(0,0, OpArgU, OpArgN, IABC,"RETURN ", luaret),# return R(A), ... ,R(A+B-2)
OpCode(0,1, OpArgR, OpArgN, IAsBx,"FORLOOP ", forloop),# R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
OpCode(0,1, OpArgR, OpArgN, IAsBx,"FORPREP ", forprep),# R(A)-=R(A+2); pc+=sBx
OpCode(0,0, OpArgN, OpArgU, IABC,"TFORCALL",None),# R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
OpCode(0,1, OpArgR, OpArgN, IAsBx,"TFORLOOP",None),# if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }
OpCode(0,0, OpArgU, OpArgU, IABC,"SETLIST ", setlist),# R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
OpCode(0,1, OpArgU, OpArgN, IABx,"CLOSURE ", closure),# R(A) := closure(KPROTO[Bx])
OpCode(0,1, OpArgU, OpArgN, IABC,"VARARG ", vararg),# R(A), R(A+1), ..., R(A+B-2) = vararg
OpCode(0,0, OpArgU, OpArgU, IAx,"EXTRAARG",None),# extra (larger) argument for previous opcode]
test
local function max(...)
local args = {...}
local val, idx
for i = 1, #args do
if val == nil or args[i] > val then
val, idx = args[i], i
end
end
return val, idx
end
local function assert(v)
if not v then fail() end
end
local v1 = max(3, 9, 7, 128, 35)
assert(v1 == 128)
local v2, i2 = max(3, 9, 7, 128, 35)
assert(v2 == 128 and i2 == 4)
local v3, i3 = max(max(3, 9, 7, 128, 35))
assert(v3 == 128 and i3 == 1)
local t = {max(3, 9, 7, 128, 35)}
assert(t[1] == 128 and t[2] == 4)
from lua_state import LuaState
defmain():withopen('./test/function_call.luac','rb')as f:
data = f.read()
ls = LuaState()
ls.load(data)
ls.call(0,0)if __name__ =='__main__':
main()