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)