138 lines
4.4 KiB
Python
138 lines
4.4 KiB
Python
class LuaState:
|
|
def __init__(self, ast):
|
|
self.env = {}
|
|
self.functions = {}
|
|
self.last_error = 0
|
|
print("[LUA] Evaluating")
|
|
self._eval_block(ast)
|
|
print("[LUA] Done")
|
|
|
|
|
|
def _eval_expr(self, expr, local_env):
|
|
kind = expr[0]
|
|
try:
|
|
if kind == 'number':
|
|
return expr[1]
|
|
elif kind == 'name':
|
|
return local_env.get(expr[1], self.env.get(expr[1]))
|
|
elif kind == 'binop':
|
|
op = expr[1]
|
|
a = self._eval_expr(expr[2], local_env)
|
|
b = self._eval_expr(expr[3], local_env)
|
|
return {
|
|
'+': a + b,
|
|
'-': a - b,
|
|
'*': a * b,
|
|
'/': a / b,
|
|
'>': a > b,
|
|
'<': a < b,
|
|
'>=': a >= b,
|
|
'<=': a <= b,
|
|
'==': a == b,
|
|
'!=': a != b
|
|
}[op]
|
|
elif kind == 'call':
|
|
func_name = expr[1]
|
|
args = [self._eval_expr(arg, local_env) for arg in expr[2]]
|
|
if func_name == 'print':
|
|
print(*args)
|
|
else:
|
|
return self.call(func_name, *args)
|
|
except Exception as e:
|
|
self.last_error = 1
|
|
return str(e)
|
|
|
|
def _eval_stmt(self, stmt, local_env):
|
|
kind = stmt[0]
|
|
if kind == 'local':
|
|
local_env[stmt[1]] = self._eval_expr(stmt[2], local_env)
|
|
elif kind == 'assign':
|
|
val = self._eval_expr(stmt[2], local_env)
|
|
if stmt[1] in local_env:
|
|
local_env[stmt[1]] = val
|
|
else:
|
|
self.env[stmt[1]] = val
|
|
elif kind == 'function':
|
|
name, args, body = stmt[1], stmt[2], stmt[3]
|
|
self.functions[name] = (args, body)
|
|
elif kind == 'if':
|
|
cond, true_blk, elifs, else_blk = stmt[1], stmt[2], stmt[3], stmt[4]
|
|
if self._eval_expr(cond, local_env):
|
|
return self._eval_block(true_blk, local_env)
|
|
for elif_cond, elif_blk in elifs:
|
|
if self._eval_expr(elif_cond, local_env):
|
|
return self._eval_block(elif_blk, local_env)
|
|
return self._eval_block(else_blk, local_env)
|
|
elif kind == 'while':
|
|
while self._eval_expr(stmt[1], local_env):
|
|
result = self._eval_block(stmt[2], local_env)
|
|
if result is not None:
|
|
return result
|
|
elif kind == 'return':
|
|
return self._eval_expr(stmt[1], local_env)
|
|
elif kind == 'call':
|
|
self._eval_expr(stmt, local_env)
|
|
|
|
def _eval_block(self, block, env=None):
|
|
local_env = {} if env is None else dict(env)
|
|
|
|
for stmt in block[1]:
|
|
result = self._eval_stmt(stmt, local_env)
|
|
if result is not None:
|
|
return result
|
|
|
|
def call(self, name, *args):
|
|
self.last_error = 0
|
|
if name not in self.functions:
|
|
self.last_error = 2
|
|
return self.last_error, f"function '{name}' not defined"
|
|
try:
|
|
params, body = self.functions[name]
|
|
call_env = {param: arg for param, arg in zip(params, args)}
|
|
result = self._eval_block(body, call_env)
|
|
return self.last_error, result
|
|
except Exception as e:
|
|
self.last_error = 3
|
|
return self.last_error, str(e)
|
|
|
|
|
|
|
|
|
|
|
|
ast = ('block',
|
|
[('local', 'x', ('number', 1.0)),
|
|
('local',
|
|
'y',
|
|
('binop',
|
|
'+',
|
|
('name', 'x'),
|
|
('binop', '*', ('number', 2.0), ('number', 3.0)))),
|
|
('function',
|
|
'hello',
|
|
['a', 'b'],
|
|
('block',
|
|
[('if',
|
|
('binop', '>', ('name', 'a'), ('name', 'b')),
|
|
('block', [('return', ('name', 'a'))]),
|
|
[(('binop', '>', ('name', 'b'), ('name', 'a')),
|
|
('block', [('return', ('name', 'b'))]))],
|
|
('block', [('return', ('number', 0.0))]))])),
|
|
('while',
|
|
('binop', '<', ('name', 'x'), ('number', 10.0)),
|
|
('block',
|
|
[('assign', 'x', ('binop', '+', ('name', 'x'), ('number', 1.0))),
|
|
('call', 'print', [('name', 'x')])]))])
|
|
|
|
|
|
print("State")
|
|
state = LuaState(ast)
|
|
print("call")
|
|
|
|
err, out = state.call("hello", 10, 20)
|
|
print("hello(10, 20):", err, out)
|
|
|
|
err, out = state.call("hello", 5, 1)
|
|
print("hello(5, 1):", err, out)
|
|
|
|
err, out = state.call("not_real")
|
|
print("not_real():", err, out) |