luapy (6) lua table

1)lua table

from lua_value import LuaValue


class LuaTable:
    def __init__(self, narr, nrec):
        self.arr = None
        self.map = None

        if narr > 0:
            self.arr = []
        if nrec > 0:
            self.map = {}

    def __len__(self):
        return len(self.arr) if self.arr is not None else 0

    def get(self, key):
        key = LuaValue.float2integer(key)

        if self.arr and isinstance(key, int):
            if 1 <= key <= len(self.arr):
                return self.arr[key-1]

        return self.map[key] if key in self.map else None

    def map_to_arr(self):
        if self.map:
            i = len(self.arr)
            while i in self.map:
                v = self.map[i]
                self.map.pop(i)
                self.arr.append(v)
                i += 1

    def put(self, key, val):
        assert(key is not None)
        assert(key is not float('NAN'))

        key = LuaValue.float2integer(key)
        if isinstance(key, int) and key >= 1:
            if not self.arr:
                self.arr = []
            arr_len = len(self.arr)
            if key <= arr_len:
                self.arr[key-1] = val
                if key == arr_len and val is None:
                    self.arr.pop(key)
                return
            if key == arr_len + 1:
                if self.map:
                    self.map.pop(key)
                if val is not None:
                    self.arr.append(val)
                    self.map_to_arr()
                return

        if val is not None:
            if not self.map:
                self.map = {key: val}
        else:
            self.map.pop(key)

2)lua state

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


class LuaState:
    def __init__(self, proto):
        self.stack = LuaStack()
        self.proto = proto
        self.pc = 0

    # ...
    
    # table
    def create_table(self, narr, nrec):
        table = LuaTable(narr, nrec)
        self.stack.push(table)

    @staticmethod
    def get_table_val(t, k):
        if isinstance(t, LuaTable):
            return t.get(k)
        raise Exception('not a table')

    def get_table(self, idx):
        t = self.stack.get(idx)
        k = self.stack.pop()
        v = LuaState.get_table_val(t, k)
        self.stack.push(v)
        return LuaValue.type_of(v)

    def get_i(self, idx, i):
        t = self.stack.get(idx)
        v = LuaState.get_table_val(t, i)
        self.stack.push(v)
        return LuaValue.type_of(v)

    def set_table(self, idx):
        t = self.stack.get(idx)
        v = self.stack.pop()
        k = self.stack.pop()
        LuaState.set_table_kv(t, k, v)

    @staticmethod
    def set_table_kv(t, k, v):
        if isinstance(t, LuaTable):
            t.put(k, v)
            return
        raise Exception('not a table')

    def set_field(self, idx, k):
        t = self.stack.get(idx)
        v = self.stack.pop()
        LuaState.set_table_kv(t, k, v)

    def set_i(self, idx, i):
        t = self.stack.get(idx)
        v = self.stack.pop()
        LuaState.set_table_kv(t, i, v)

3)instruction

# R(A) := {}
def newtable(inst, vm):
    a, b, c = inst.a_b_c()
    a += 1
    vm.create_table(LuaValue.fb2int(b), LuaValue.fb2int(c))
    vm.replace(a)


# R(A) := R(B)[RK(C)]
def gettable(inst, vm):
    a, b, c = inst.a_b_c()
    a += 1
    b += 1
    vm.get_rk(c)
    vm.get_table(b)
    vm.replace(a)


# R(A)[R(B)] := RK(C)
def settable(inst, vm):
    a, b, c = inst.a_b_c()
    a += 1
    vm.get_rk(b)
    vm.get_rk(c)
    vm.set_table(a)


# R(A)[(C-1)*LFIELDS_PER_FLUSH+i] := R(A+i), 1 <= i <= B
def setlist(inst, vm):
    a, b, c = inst.a_b_c()
    a += 1
    c = c - 1 if c > 0 else inst.ax(vm.fetch())

    vm.check_stack(1)
    idx = c * LFIELDS_PER_FLUSH
    for i in range(1, b+1):
        idx += 1
        vm.push_value(a+i)
        vm.set_i(a, idx)


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    ", None),      # 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    ", None),      # R(A), ...,R(A+C-2) := R(A)(R(A+1), ...,R(A+B-1))
    OpCode(0, 1, OpArgU, OpArgU, IABC,  "TAILCALL", None),      # return R(A)(R(A+1), ... ,R(A+B-1))
    OpCode(0, 0, OpArgU, OpArgN, IABC,  "RETURN  ", None),      # 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 ", None),      # R(A) := closure(KPROTO[Bx])
    OpCode(0, 1, OpArgU, OpArgN, IABC,  "VARARG  ", None),      # R(A), R(A+1), ..., R(A+B-2) = vararg
    OpCode(0, 0, OpArgU, OpArgU, IAx,   "EXTRAARG", None),      # extra (larger) argument for previous opcode
]

4)test

local t = {"a", "b", "c"}
t[2] = "B"
t["foo"] = "Bar"
local s = t[3] .. t[2] .. t[1] .. t["foo"] .. #t
from binary_chunk import BinaryChunk
from lua_state import LuaState
from opcode import Instruction
from opcode import OpCode


def lua_main(proto):
    vm = LuaState(proto)
    vm.set_top(proto.get_max_stack_size())
    while True:
        pc = vm.get_pc()
        i = vm.fetch()
        inst = Instruction(i)
        if inst.op_code() != OpCode.RETURN:
            inst.execute(vm)
            print('[%02d] %-8s ' % (pc+1, inst.op_name()), end='')
            vm.print_stack()
        else:
            break


def main():
    bc = BinaryChunk('./test/table.luac')
    bc.print_header()
    bc.check_header()
    bc.print_main_func()

    proto = bc.get_main_func()
    lua_main(proto)


if __name__ == '__main__':
    main()

5)result

signature:        b'\x1bLua'
version:          83
format:           0
luac_data:        b'\x19\x93\r\n\x1a\n'
cint_size:        4
csizet_size:      8
inst_size:        4
lua_int_size:     8
lua_number_size:  8
luac_int:         0x5678
luac_num:         370.5

main <@table.lua:0,0> (14 instructions)
0+ params, 6 slots, 1 upvalues, 2 locals, 9 constants, 0 functions
	1	[1]	NEWTABLE        0        3        0
	2	[1]	LOADK           1       -1
	3	[1]	LOADK           2       -2
	4	[1]	LOADK           3       -3
	5	[1]	SETLIST         0        3        1
	6	[2]	SETTABLE        0       -4       -5
	7	[3]	SETTABLE        0       -6       -7
	8	[4]	GETTABLE        1        0       -8
	9	[4]	GETTABLE        2        0       -4
	10	[4]	GETTABLE        3        0       -9
	11	[4]	GETTABLE        4        0       -6
	12	[4]	LEN             5        0
	13	[4]	CONCAT          1        1        5
	14	[4]	RETURN          0        1
constants (9):
	1	"a"
	2	"b"
	3	"c"
	4	2
	5	"B"
	6	"foo"
	7	"Bar"
	8	3
	9	1
locals (2):
	1	t	6	15
	2	s	14	15
upvalues (1):
	1	_ENV	1	0
[01] NEWTABLE [table][nil][nil][nil][nil][nil]
[02] LOADK    [table]["a"][nil][nil][nil][nil]
[03] LOADK    [table]["a"]["b"][nil][nil][nil]
[04] LOADK    [table]["a"]["b"]["c"][nil][nil]
[05] SETLIST  [table]["a"]["b"]["c"][nil][nil]
[06] SETTABLE [table]["a"]["b"]["c"][nil][nil]
[07] SETTABLE [table]["a"]["b"]["c"][nil][nil]
[08] GETTABLE [table]["c"]["b"]["c"][nil][nil]
[09] GETTABLE [table]["c"]["B"]["c"][nil][nil]
[10] GETTABLE [table]["c"]["B"]["a"][nil][nil]
[11] GETTABLE [table]["c"]["B"]["a"]["Bar"][nil]
[12] LEN      [table]["c"]["B"]["a"]["Bar"][3]
[13] CONCAT   [table]["cBaBar3"]["B"]["a"]["Bar"][3]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
详细描述Lua和C之间相互传递Table类型数据 /* ====================================================== */ // 遍历Lua传入的Table类型参数, 获取它的Key/Value, 其关键操作是 lua_next() // lua_next() 返回1表示读取成功,返回0表示已经没有数据可读了 // lua_next() 会使用栈顶元素作为Key去定位本次需要取出Table里面的那个值对 // 如果Key=nil, 那就表示本次取出的是第一个元素 // 它会先将当前的这个Key弹出,然后将本次取出的Key/Value压入栈, Value在栈顶 // 一个比较隐晦的处理就是, 我们不应直接使用lua_tostring(L, -2)来读取Key // 因为lua_tostring()在Key类型不是字符串时, 它会修改栈上的Key数据 // 这样, 下次调用lua_next()时, 就会因为Key被修改了而导致错误 // 为此,先调用lua_pushvalue(L, -2),将它Copy一份到栈顶,对这个Copy进行lua_tostring() // 读取Key,Value到C变量里面后,将Value和Copy弹出,留着Key在栈顶,给下次lua_next()用 // // 指令及栈图变化如下: (假如Table的栈下标是Index) // 0. 刚进入函数时 ...Table, ... <--- 这里栈顶 // 1. lua_pushnil(L) ...Table, ..., nil <--- 这里栈顶 // 2. lua_next(L, Index) ...Table, ..., Key, Value <--- 这里栈顶 // 3. lua_pushvalue(L, -2) ...Table, ..., Key, Value, KeyCopy <--- 这里栈顶 // 4. lua_pop(L, 2), ...Table, ..., Key <--- 这里栈顶 // ... 如此重复2,3,4 // N. lua_next(L, Index)返回0 ...Table, ... <--- 这里栈顶 /* ====================================================== */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值