# HG changeset patch # User Laman # Date 2023-01-01 13:25:39 # Node ID c296b5584a9df3198a3b6f0e4026963027d941b1 basic variable declaration and arithmetic addition diff --git a/src/jasinta.py b/src/jasinta.py new file mode 100644 --- /dev/null +++ b/src/jasinta.py @@ -0,0 +1,123 @@ +from std import lib as stdlib + + +class Undefined: + pass + + +def evaluate(node, context): + if node is None: + return None + + node_type = node["type"] + if node_type == "Identifier": + for ctx in reversed(context): + if node["name"] in ctx: + return ctx[node["name"]] + return Undefined + + 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 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): + return self.node["value"] + + +node_index = {cls.__name__: cls for cls in [ + Program, ExpressionStatement, CallExpression, MemberExpression, EmptyStatement, BinaryExpression, + VariableDeclaration, VariableDeclarator, Literal +]} + + +def interpret(parse_tree): + return evaluate(parse_tree, [stdlib]) diff --git a/src/std.py b/src/std.py new file mode 100644 --- /dev/null +++ b/src/std.py @@ -0,0 +1,3 @@ +lib = { + "document": {"write": print} +}