1)lua 数据类型
from enum import Enum, unique
@unique
class LuaType(Enum):
NONE = -1
NIL = 0
BOOLEAN = 1
LIGHT_USER_DATA = 2
NUMBER = 3
STRING = 4
TABLE = 5
FUNCTION = 6
USER_DATA = 7
THREAD = 8
2)lua stack
class LuaStack:
MAX_STACK_SIZE = 1000
def __init__(self):
self.slots = []
def top(self):
return len(self.slots)
def check(self, n):
return len(self.slots) + n <= LuaStack.MAX_STACK_SIZE
def push(self, val):
if len(self.slots) > LuaStack.MAX_STACK_SIZE:
raise Exception('Stack Over Flow')
self.slots.append(val)
def pop(self):
ret = self.slots[-1]
self.slots.pop()
return ret
def abs_index(self, idx):
if idx >= 0:
return idx
return idx + len(self.slots) + 1
def is_valid(self, idx):
idx = self.abs_index(idx)
return (idx > 0) and (idx <= len(self.slots))
def get(self, idx):
if not self.is_valid(idx):
return None
return self.slots[self.abs_index(idx)-1]
def set(self, idx, val):
if not self.is_valid(idx):
raise Exception('Invalid Index')
self.slots[self.abs_index(idx)-1] = val
def reverse(self, begin, end):
while begin < end:
self.slots[begin], self.slots[end] = self.slots[end], self.slots[begin]
begin += 1
end -= 1
3)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
class LuaState:
def __init__(self):
self.stack = LuaStack()
def get_top(self):
return self.stack.top()
def abs_index(self, idx):
return self.stack.abs_index(idx)
def check_stack(self, n):
return self.stack.check(n)
def pop(self, n):
for i in range(n):
self.stack.pop()
def copy(self, src, dst):
self.stack.set(dst, self.stack.get(src))
def push_value(self, idx):
self.stack.push(self.stack.get(idx))
def replace(self, idx):
self.stack.set(idx, self.stack.pop())
def insert(self, idx):
self.rotate(idx, 1)
def remove(self, idx):
self.rotate(idx, -1)
self.pop(1)
def rotate(self, idx, n):
t = self.stack.top() - 1
p = self.stack.abs_index(idx) - 1
m = t - n if n >= 0 else p - n - 1
self.stack.reverse(p, m)
self.stack.reverse(m+1, t)
self.stack.reverse(p, t)
def set_top(self, idx):
new_top = self.stack.abs_index(idx)
assert(new_top >= 0)
n = self.stack.top() - new_top
if n > 0:
for i in range(n):
self.stack.pop()
elif n < 0:
for i in range(-n):
self.stack.push(None)
@staticmethod
def type_name(tp):
if tp == LuaType.NONE:
return 'no value'
elif tp == LuaType.NIL:
return 'nil'
elif tp == LuaType.BOOLEAN:
return 'boolean'
elif tp == LuaType.NUMBER:
return 'number'
elif tp == LuaType.STRING:
return 'string'
elif tp == LuaType.TABLE:
return 'table'
elif tp == LuaType.FUNCTION:
return 'function'
elif tp == LuaType.THREAD:
return 'thread'
elif tp == LuaType.USER_DATA:
return 'userdata'
def type(self, idx):
if self.stack.is_valid(idx):
return LuaValue.type_of(self.stack.get(idx))
return LuaType.NONE
def is_none(self, idx):
return self.type(idx) == LuaType.NONE
def is_nil(self, idx):
return self.type(idx) == LuaType.NIL
def is_none_or_nil(self, idx):
return self.is_none(idx) or self.is_nil(idx)
def is_boolean(self, idx):
return self.type(idx) == LuaType.BOOLEAN
def is_integer(self, idx):
return isinstance(self.stack.get(idx), int)
def is_number(self, idx):
return self.to_number(idx) is not None
def is_string(self, idx):
tp = self.type(idx)
return tp == LuaType.STRING or tp == LuaType.NUMBER
def is_table(self, idx):
return self.type(idx) == LuaType.TABLE
def is_thread(self, idx):
return self.type(idx) == LuaType.THREAD
def is_function(self, idx):
return self.type(idx) == LuaType.FUNCTION
def to_boolean(self, idx):
return LuaValue.to_boolean(self.stack.get(idx))
def to_integer(self, idx):
i = self.to_integerx(idx)
return 0 if i is None else i
def to_integerx(self, idx):
val = self.stack.get(idx)
return val if isinstance(val, int) else None
def to_number(self, idx):
val = self.stack.get(idx)
if isinstance(val, float):
return val
elif isinstance(val, int):
return float(val)
return 0
def to_string(self, idx):
val = self.stack.get(idx)
if isinstance(val, str):
return val
elif isinstance(val, int) or isinstance(val, float):
s = str(val)
self.stack.set(idx, s)
return s
return ''
def push_nil(self):
self.stack.push(None)
def push_boolean(self, b):
self.stack.push(b)
def push_integer(self, n):
self.stack.push(n)
def push_number(self, n):
self.stack.push(n)
def push_string(self, s):
self.stack.push(s)
def dump(self):
top = self.stack.top()
for i in range(1, top+1):
t = self.type(i)
if t == LuaType.BOOLEAN:
print('[%s]' % ('true' if self.to_boolean(i) else 'false'), end='')
elif t == LuaType.NUMBER:
if self.is_integer(i):
print('[%d]' % self.to_integer(i), end='')
else:
print('[%g]' % self.to_number(i), end='')
elif t == LuaType.STRING:
print('["%s"]' % self.to_string(i), end='')
else:
print('[%s]' % LuaState.type_name(t), end='')
print()
4)lua value
from lua_type import LuaType
class LuaValue:
@staticmethod
def type_of(val):
if val is None:
return LuaType.NIL
elif isinstance(val, bool):
return LuaType.BOOLEAN
elif isinstance(val, int) or isinstance(val, float):
return LuaType.NUMBER
elif isinstance(val, str):
return LuaType.STRING
raise Exception('Type not support')
@staticmethod
def to_boolean(val):
if val is None:
return False
elif isinstance(val, bool):
return val
else:
return True
5)test
from lua_state import LuaState
def main():
ls = LuaState()
ls.push_boolean(True)
ls.dump()
ls.push_integer(10)
ls.dump()
ls.push_nil()
ls.dump()
ls.push_string('hello')
ls.dump()
ls.push_value(-4)
ls.dump()
ls.replace(3)
ls.dump()
ls.set_top(6)
ls.dump()
ls.remove(-3)
ls.dump()
ls.set_top(-5)
ls.dump()
if __name__ == '__main__':
main()
6)test result
[true]
[true][10]
[true][10][nil]
[true][10][nil]["hello"]
[true][10][nil]["hello"][true]
[true][10][true]["hello"]
[true][10][true]["hello"][nil][nil]
[true][10][true][nil][nil]
[true]