from std import lib as stdlib, Number, String class Undefined: pass def evaluate(node, context): if node is None: return None node_type = node["type"] # retrieve an already existing object from the context if node_type == "Identifier": if hasattr(context[-1], node["name"]): return getattr(context[-1], node["name"]) for ctx in reversed(context): if node["name"] in ctx: return ctx[node["name"]] return Undefined # create a new object cls = node_index[node_type] obj = cls(node) return obj.eval(context) class Program: def __init__(self, node): self.node = node def eval(self, context): program_context = [*context, dict()] for node in self.node["body"]: evaluate(node, program_context) class ExpressionStatement: def __init__(self, node): self.node = node def eval(self, context): evaluate(self.node["expression"], context) class CallExpression: def __init__(self, node): self.node = node def eval(self, context): callee = evaluate(self.node["callee"], context) arguments = [evaluate(arg, context) for arg in self.node["arguments"]] return callee(*arguments) class MemberExpression: def __init__(self, node): self.node = node def eval(self, context): obj = evaluate(self.node["object"], context) prop = evaluate(self.node["property"], [obj]) return prop class AssignmentExpression: def __init__(self, node): self.node = node def eval(self, context): left = evaluate(self.node["left"], context) right = evaluate(self.node["right"], context) op = self.node["operator"] if op == "=": left.val = right.val elif op == "+=": left.val += right.val else: raise NotImplementedError class BinaryExpression: def __init__(self, node): self.node = node def eval(self, context): left = evaluate(self.node["left"], context) right = evaluate(self.node["right"], context) # in fact this doesn't follow JavaScript "+" semantics if self.node["operator"] == "+": return left+right else: raise NotImplementedError class EmptyStatement: def __init__(self, node): pass def eval(self, context): pass class VariableDeclaration: def __init__(self, node): self.node = node def eval(self, context): for node in self.node["declarations"]: evaluate(node, context) class VariableDeclarator: def __init__(self, node): self.node = node def eval(self, context): value = evaluate(self.node["init"], context) if self.node["id"]["type"] == "Identifier": name = self.node["id"]["name"] context[-1][name] = value else: raise NotImplementedError class Literal: def __init__(self, node): self.node = node def eval(self, context): val = self.node["value"] if isinstance(val, float): if int(val) == val: return Number(int(val)) else: return Number(val) else: return String(val) node_index = {cls.__name__: cls for cls in [ Program, ExpressionStatement, CallExpression, MemberExpression, EmptyStatement, AssignmentExpression, BinaryExpression, VariableDeclaration, VariableDeclarator, Literal ]} def interpret(parse_tree): return evaluate(parse_tree, [stdlib])