1)operator(arithmetic, compare)
from enum import Enum, unique
@unique
class ArithOp(Enum):
ADD = 0 # +
SUB = 1 # -
MUL = 2 # *
MOD = 3 # %
POW = 4 # ^
DIV = 5 # /
IDIV = 6 # //
BAND = 7 # &
BOR = 8 # |
BXOR = 9 # ~
SHL = 10 # <<
SHR = 11 # >>
UNM = 12 # -
BNOT = 13 # ~
from enum import Enum, unique
@unique
class CmpOp(Enum):
EQ = 0 # ==
LT = 1 # <
LE = 2 # <=
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
class LuaState:
def __init__(self):
self.stack = LuaStack()
def get_top(self):
return self.stack.top()
# ...
def arith(self, op):
b = self.stack.pop()
a = self.stack.pop() if (op != ArithOp.UNM and op != ArithOp.BNOT) else b
result = Arithmetic.arith(a, op, b)
assert(result is not None)
self.stack.push(result)
def len(self, idx):
val = self.stack.get(idx)
assert(val is not None)
self.stack.push(len(val))
def concat(self, n):
if n == 0:
self.stack.push('')
elif n >= 2:
for i in range(1, n):
assert(self.is_string(-1) and self.is_string(-2))
s2 = self.to_string(-1)
s1 = self.to_string(-2)
self.stack.pop()
self.stack.pop()
self.stack.push(s1+s2)
def compare(self, idx1, op, idx2):
if not self.stack.is_valid(idx1) or not self.stack.is_valid(idx2):
return False
a = self.stack.get(idx1)
b = self.stack.get(idx2)
if op == CmpOp.EQ:
return Compare.eq(a, b)
elif op == CmpOp.LT:
return Compare.lt(a, b)
elif op == CmpOp.LE:
return Compare.le(a, b)
3)arithmetic
from collections import namedtuple
from lua_value import LuaValue
from arith_op import ArithOp
def add(a, b):
return a + b
def sub(a, b):
return a - b
def mul(a, b):
return a * b
def mod(a, b):
return a % b
def div(a, b):
return a / b
def fdiv(a, b):
return a // b
def band(a, b):
return a & b
def bor(a, b):
return a | b
def bxor(a, b):
return a ^ b
def shl(a, b):
if b >= 0:
return a << b
return a >> (-b)
def shr(a, b):
if b >= 0:
return a >> b
return a << (-b)
def unm(a, b):
return -a + (b-b)
def bnot(a, b):
return ~a + (b-b)
class Arithmetic:
operator = namedtuple('operator', ['integer_func', 'float_func'])
operators = {
ArithOp.ADD: operator(add, add),
ArithOp.SUB: operator(sub, sub),
ArithOp.MUL: operator(mul, mul),
ArithOp.MOD: operator(mod, mod),
ArithOp.POW: operator(None, pow),
ArithOp.DIV: operator(None, div),
ArithOp.IDIV: operator(fdiv, fdiv),
ArithOp.BAND: operator(band, None),
ArithOp.BOR: operator(bor, None),
ArithOp.BXOR: operator(bxor, None),
ArithOp.SHL: operator(shl, None),
ArithOp.SHR: operator(shr, None),
ArithOp.UNM: operator(unm, unm),
ArithOp.BNOT: operator(bnot, None)
}
@staticmethod
def arith(a, op, b):
integer_func = Arithmetic.operators[op].integer_func
float_func = Arithmetic.operators[op].float_func
if float_func is None:
x = LuaValue.to_integer(a)
if x:
y = LuaValue.to_integer(b)
if y:
return integer_func(x, y)
else:
if integer_func is not None:
if isinstance(a, int) and isinstance(b, int):
return integer_func(int(a), int(b))
x = LuaValue.to_float(a)
if x:
y = LuaValue.to_float(b)
if y:
return float_func(x, y)
return None
4)compare
class Compare:
@staticmethod
def eq(a, b):
if a is None:
return b is None
if isinstance(a, bool) or isinstance(a, str):
return a == b
if isinstance(a, int):
if isinstance(b, int):
return a == b
elif isinstance(b, float):
return float(a) == b
else:
return False
if isinstance(a, float):
if isinstance(b, float):
return a == b
elif isinstance(b, int):
return a == float(b)
else:
return False
@staticmethod
def lt(a, b):
if isinstance(a, str) and isinstance(b, str):
return a < b
if isinstance(a, int):
if isinstance(b, int):
return a < b
elif isinstance(b, float):
return float(a) < b
if isinstance(a, float):
if isinstance(b, float):
return a < b
elif isinstance(b, int):
return a < float(b)
raise Exception('Comparison Error')
@staticmethod
def le(a, b):
if isinstance(a, str) and isinstance(b, str):
return a <= b
if isinstance(a, int):
if isinstance(b, int):
return a <= b
elif isinstance(b, float):
return float(a) <= b
if isinstance(a, float):
if isinstance(b, float):
return a <= b
elif isinstance(b, int):
return a <= float(b)
raise Exception('Comparison Error')
5)test
from lua_state import LuaState
from arith_op import ArithOp
from cmp_op import CmpOp
def main():
ls = LuaState()
ls.push_integer(1)
ls.push_string('2.0')
ls.push_string('3.0')
ls.push_number(4.0)
ls.dump()
ls.arith(ArithOp.ADD)
ls.dump()
ls.arith(ArithOp.BNOT)
ls.dump()
ls.len(2)
ls.dump()
ls.concat(3)
ls.dump()
ls.push_boolean(ls.compare(1, CmpOp.EQ, 2))
ls.dump()
ls.push_number(2)
ls.push_number(2)
ls.dump()
ls.arith(ArithOp.POW)
ls.dump()
ls.push_number(3.0)
ls.push_boolean(ls.compare(4, CmpOp.LT, 5))
ls.dump()
ls.push_string('hello')
ls.push_string('world')
ls.push_boolean(ls.compare(7, CmpOp.LE, 8))
ls.dump()
if __name__ == '__main__':
main()
result:
[1]["2.0"]["3.0"][4]
[1]["2.0"][7]
[1]["2.0"][-8]
[1]["2.0"][-8][3]
[1]["2.0-83"]
[1]["2.0-83"][false]
[1]["2.0-83"][false][2][2]
[1]["2.0-83"][false][4]
[1]["2.0-83"][false][4][3][false]
[1]["2.0-83"][false][4][3][false]["hello"]["world"][true]