def test_single_environment(self): environment = Environment() self.assertRaises(Utils.UnknownVariable, environment.value, "test") environment.defineVariable("test", 10) self.assertEqual(environment.value("test"), 10) environment.setVariable("test", 5) self.assertEqual(environment.value("test"), 5) self.assertRaises(Utils.UnknownVariable, environment.setVariable, "test2", 5)
def test_chain_environment(self): root_environment = Environment() child_environment = Environment(root_environment) root_environment.defineVariable("test", 5) self.assertEqual(root_environment.value("test"), 5) self.assertEqual(child_environment.value("test"), 5) child_environment.setVariable("test", 2) self.assertEqual(root_environment.value("test"), 2) self.assertEqual(child_environment.value("test"), 2) child_environment.defineVariable("test", 3) self.assertEqual(root_environment.value("test"), 2) self.assertEqual(child_environment.value("test"), 3) child_environment.setVariable("test", 6) self.assertEqual(root_environment.value("test"), 2) self.assertEqual(child_environment.value("test"), 6) child_environment.defineVariable("test2", 4) self.assertRaises(Utils.UnknownVariable, root_environment.value, "test2") self.assertEqual(child_environment.value("test2"), 4) self.assertRaises(Utils.UnknownVariable, root_environment.setVariable, "test2", 5)
def run_test_executor(self, instructions, final_stack, initial_environment, final_environment): code = Code() for inst in instructions: code.add_instruction(Instruction(inst[0], *tuple(inst[1:len(inst)]))) env = Environment() for key, value in initial_environment.items(): env.defineVariable(key, value) executor = Executor(env) executor.execute(code) self.assertEqual(len(final_stack), len(executor.stack.stack)) for i in range(0, len(final_stack)): f_elt = final_stack[i] a_elt = executor.stack.stack[i] if(isinstance(f_elt, Object) or isinstance(f_elt, Function)): self.assertEqual(f_elt.__class__, a_elt.__class__) else: self.assertEqual(f_elt, a_elt) for key, value in final_environment.items(): self.assertEqual(env.value(key), value) return (executor.stack.stack, env)
def run_test_executor(self, instructions, final_stack, initial_environment, final_environment): code = Code() for inst in instructions: code.add_instruction( Instruction(inst[0], *tuple(inst[1:len(inst)]))) env = Environment() for key, value in initial_environment.items(): env.defineVariable(key, value) executor = Executor(env) executor.execute(code) self.assertEqual(len(final_stack), len(executor.stack.stack)) for i in range(0, len(final_stack)): f_elt = final_stack[i] a_elt = executor.stack.stack[i] if (isinstance(f_elt, Object) or isinstance(f_elt, Function)): self.assertEqual(f_elt.__class__, a_elt.__class__) else: self.assertEqual(f_elt, a_elt) for key, value in final_environment.items(): self.assertEqual(env.value(key), value) return (executor.stack.stack, env)
def test_function(self): # # This test that a simple call works # env = Environment() function = Function(["arg1", "arg2", "finalarg"], env, lambda environment: self.func1(environment)) function(None, 10, 2, 5) function.call(None, None, 10, 2, 5) # # This test that "this" is correctly set # env = Environment() function = Function(["arg1", "arg2"], env, lambda environment: self.func2(environment)) function(10, 2, 5) function.call(None, 10, 2, 5) # # This test that global variables works # env = Environment() env.defineVariable("glob", 4) function = Function(["arg1", "arg2"], env, lambda environment: self.func3(environment)) function(10, 2, 5) self.assertEqual(env.value("glob"), 3) self.assertRaises(Utils.UnknownVariable, env.value, "testator") env.setVariable("glob", 4) function.call(None, 10, 2, 5) self.assertEqual(env.value("glob"), 3) self.assertRaises(Utils.UnknownVariable, env.value, "testator") # # This test that the ReturnException is correctly catched in the call function # env = Environment() function = Function(["arg1", "arg2"], env, lambda environment: self.func4(environment)) self.assertEqual(function(None, 2, 5), 7)
class InterpreterVisitor(ECMAScriptVisitor): def __init__(self, environment=Environment(), input=None): self.environment = environment self.environment.defineVariable("console", Console()) self.environment.defineVariable("Math", MathModule()) self.environment.defineVariable("Object", ObjectModule()) def visitTerminal(self, node): if node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.BooleanLiteral: # 54 if node.symbol.text == 'true': return True elif node.symbol.text == 'false': return False elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.DecimalLiteral: # 55 # Not sure if were supposed to ever return int # Changes this because test 02_expression/01_addition expects float as result # Change back to make the implementation of binary_ops easier try: return int(node.symbol.text) except ValueError: return float(node.symbol.text) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.HexIntegerLiteral: # 56 return float(int(node.symbol.text, 0)) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.StringLiteral: # 101 # Assume that a string atleast contains ""? return node.symbol.text[1:-1] else: return node.symbol.text # Visit a parse tree produced by ECMAScriptParser#PropertyExpressionAssignment. def visitPropertyExpressionAssignment(self, ctx): # Example of input: <name>:<expression> # NOTE: convert expr to float if int name = ctx.children[0].accept(self) expr = ctx.children[2].accept(self) if isinstance(expr, int): expr = float(expr) return (name, expr) # Visit a parse tree produced by ECMAScriptParser#assignmentOperator. def visitAssignmentOperator(self, ctx): # Returns a lambda which performs the right operator node = ctx.children[0] if node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Assign: # 11 return lambda x, y: y elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.PlusAssign: # 43 return lambda x, y: x + y elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.MinusAssign: # 44 return lambda x, y: x - y elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.MultiplyAssign: # 40 return lambda x, y: x * y elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.DivideAssign: # 41 return lambda x, y: x / y else: raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#eos. def visitEos(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#program. def visitProgram(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#argumentList. def visitArgumentList(self, ctx): args = [] for c in ctx.children: if (not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," value = c.accept(self) if isinstance(value, Property): args.append(value.get()) else: args.append(value) return args # Visit a parse tree produced by ECMAScriptParser#ArgumentsExpression. def visitArgumentsExpression(self, ctx): func = ctx.children[0].accept(self) args = ctx.children[1].accept(self) if (args == None): args = [] res = None if isinstance(func, tuple): res = func[1](func[0], *args) elif str(type(func)) == "<class 'builtin_function_or_method'>": return func(*args) else: res = func(None, *args) if isinstance(res, int): res = float(res) #print('THE RES FROM ARGEXPR:', res) return res # Visit a parse tree produced by ECMAScriptParser#ThisExpression. def visitThisExpression(self, ctx): return self.environment.value("this") # Visit a parse tree produced by ECMAScriptParser#identifierName. def visitIdentifierName(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#BinaryExpression. def visitBinaryExpression(self, ctx): node = ctx.children[1] # Handle AND and OR first to achieve normal-order evaluation if node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.And: # 38 return ctx.children[0].accept(self) and ctx.children[2].accept( self) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Or: # 39 return ctx.children[0].accept(self) or ctx.children[2].accept(self) op1 = ctx.children[0].accept(self) op2 = ctx.children[2].accept(self) # Only convert to int if type is float if isinstance(op1, float) and op1 == int(op1): op1 = int(op1) if isinstance(op2, float) and op2 == int(op2): op2 = int(op2) if node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Plus: # 17 if isinstance(op1, int): return float(op1 + op2) else: return op1 + op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Minus: # 18 return float(op1 - op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Multiply: # 21 return float(op1 * op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Divide: # 22 return float(op1 / op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Modulus: # 23 return float(op1 % op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.LeftShiftArithmetic: # 25 return float(op1 << op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.RightShiftArithmetic: # 24 return float(op1 >> op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.RightShiftLogical: # 26 return float((op1 % 0x100000000) >> op2) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.LessThan: # 27 return op1 < op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.MoreThan: # 28 return op1 > op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.LessThanEquals: # 29 return op1 <= op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.GreaterThanEquals: # 30 return op1 >= op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Equals: # 31 return op1 == op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.NotEquals: # 32 return not op1 == op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.IdentityEquals: # 33 return op1 is op2 elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.IdentityNotEquals: # 34 return op1 is not op2 else: raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#futureReservedWord. def visitFutureReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#initialiser. def visitInitialiser(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#statementList. def visitStatementList(self, ctx): res = None for c in ctx.children: res = c.accept(self) if res == "BREAK-LOOP": return "BREAK-LOOP" elif res == "CONTINUE-LOOP": # Skip the remaining statements return "CONTINUE-LOOP" elif isinstance(res, tuple) and res[0] == "THROW": return res return res # Visit a parse tree produced by ECMAScriptParser#PropertyGetter. def visitPropertyGetter(self, ctx): name = ctx.children[1].accept(self) getter_body = ctx.children[-2].children[0] def func(env): previous_env = self.environment self.environment = env return_val = getter_body.accept(self) if isinstance(return_val, tuple): return_val = return_val[1] self.environment = previous_env return return_val return ('get', name, Function([], self.environment, func)) #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#block. def visitBlock(self, ctx): res = ctx.children[1].accept(self) return res # Visit a parse tree produced by ECMAScriptParser#expressionStatement. def visitExpressionStatement(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#keyword. def visitKeyword(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#elementList. def visitElementList(self, ctx): array = [] for c in ctx.children: if (not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," res = c.accept(self) # NOTE: Conversion of int to float, should it be done here? if isinstance(res, int): res = float(res) array.append(res) return array # Visit a parse tree produced by ECMAScriptParser#numericLiteral. def visitNumericLiteral(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#ForInStatement. def visitForInStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#emptyStatement. def visitEmptyStatement(self, ctx): return # Visit a parse tree produced by ECMAScriptParser#labelledStatement. def visitLabelledStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#PropertySetter. def visitPropertySetter(self, ctx): name = ctx.children[1].accept(self) param = ctx.children[3].accept(self) setter_body = ctx.children[-2].children[0] def func(env): previous_env = self.environment self.environment = env return_value = setter_body.accept(self) self.environment = previous_env return return_value return ('set', name, Function([param], self.environment, func)) #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#NewExpression. def visitNewExpression(self, ctx): obj = ctx.children[1].accept(self) params = ctx.children[2].accept(self) if params == None: params = [] if isinstance(obj, ObjectModule): return obj elif isinstance(obj, Function): new_obj = ObjectModule() obj(obj, *params) obj2 = new_obj.create(None, obj) setattr(obj2, "prototype", obj) obj = obj2 return obj else: raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#LiteralExpression. def visitLiteralExpression(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#ArrayLiteralExpression. def visitArrayLiteralExpression(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#MemberDotExpression. def visitMemberDotExpression(self, ctx): obj = ctx.children[0].accept(self) member = ctx.children[2].accept(self) if isinstance(obj, tuple): obj = obj[0] returnval = None if hasattr(obj, member): returnval = getattr(obj, member) elif isinstance(obj, list) and member == 'length': returnval = float(len(obj)) else: returnval = getattr(getattr(obj, "prototype"), member) if isinstance(returnval, Function): return (obj, returnval) return returnval # Visit a parse tree produced by ECMAScriptParser#withStatement. def visitWithStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#MemberIndexExpression. def visitMemberIndexExpression(self, ctx): obj = ctx.children[0].accept(self) idx = ctx.children[2].accept(self) if (isinstance(obj, Object)): return getattr(obj, str(idx)) else: return obj[int(idx)] # Visit a parse tree produced by ECMAScriptParser#formalParameterList. def visitFormalParameterList(self, ctx): params = [param.accept(self) for param in ctx.children[0::2]] return params # Visit a parse tree produced by ECMAScriptParser#incrementOperator. def visitIncrementOperator(self, ctx): # Return a lambda based on what type of operator if ctx.children[ 0].symbol.type == ECMAScriptLexer.ECMAScriptLexer.PlusPlus: return lambda x: x + 1 elif ctx.children[ 0].symbol.type == ECMAScriptLexer.ECMAScriptLexer.MinusMinus: return lambda x: x - 1 else: raise Utils.UnimplementedVisitorException(ctx) ########################################################################### ############### Helper functions for AssignmentOperatorExpression ######### ########################################################################### def objectExpression(self, ctx, var): member = ctx.children[2].accept(self) op = None val = None if isinstance(ctx.children[3], antlr4.tree.Tree.TerminalNodeImpl): op = ctx.children[4].accept(self) val = ctx.children[5].accept(self) #print(ctx.children[5].children) else: op = ctx.children[3].accept(self) val = ctx.children[4].accept(self) #print(ctx.children[4].children) if isinstance(val, int): val = float(val) if hasattr(var, member): attr = getattr(var, member) if isinstance(attr, Property): attr.set(val) return val setattr(var, member, val) return val def prototypeExpression(self, ctx): prototype = ctx.children[0].accept(self) if isinstance(prototype, tuple): prototype = prototype[0] member = ctx.children[2].accept(self) value = ctx.children[4].accept(self) # if value is an object, add each member if isinstance(value, Object): for attr in dir(value): if attr.startswith('__'): continue val = getattr(value, attr) if isinstance(val, tuple): val = list(val) val[0] = prototype val = (val[0], val[1]) setattr(prototype, attr, val) else: setattr(prototype, member, value) # Visit a parse tree produced by ECMAScriptParser#AssignmentOperatorExpression. def visitAssignmentOperatorExpression(self, ctx): if isinstance( ctx.children[0], ECMAScriptParser.ECMAScriptParser.IdentifierExpressionContext): var = ctx.children[0].accept(self) #print('Type of var:',type(var)) if isinstance(var, Object) or isinstance(var, ObjectModule): return self.objectExpression(ctx, var) elif isinstance(var, Function): return self.prototypeExpression(ctx) else: # Handle the case when assigning to array element #print('IN ARRAY CASE') res = ctx.children[5].accept(self) if isinstance(res, int): res = float(res) var[ctx.children[2].accept(self)] = res return elif isinstance( ctx.children[0], ECMAScriptParser.ECMAScriptParser.ThisExpressionContext): return self.objectExpression(ctx, ctx.children[0].accept(self)) elif isinstance( ctx.children[0], ECMAScriptParser.ECMAScriptParser.MemberDotExpressionContext): return self.prototypeExpression(ctx) var_name = ctx.children[0].accept(self) func = ctx.children[1].accept(self) value = ctx.children[2].accept(self) res = func(self.environment.value(var_name), value) self.environment.setVariable(var_name, res) # Visit a parse tree produced by ECMAScriptParser#PostUnaryAssignmentExpression. def visitPostUnaryAssignmentExpression(self, ctx): var_name = ctx.children[0].accept(self) func = ctx.children[1].accept(self) old_value = self.environment.value(var_name) res = func(old_value) self.environment.setVariable(var_name, res) return float(old_value) # Visit a parse tree produced by ECMAScriptParser#TernaryExpression. def visitTernaryExpression(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#tryStatement. def visitTryStatement(self, ctx): res = ctx.children[1].accept(self) if isinstance( res, tuple ) and res[0] == "THROW": # There was a throw in the try-block var_name, block = ctx.children[2].accept(self) # Create new environment for the catch block self.environment = Environment(self.environment) self.environment.defineVariable(var_name.accept(self), res[1].accept(self)) block.accept(self) # Set back the environment self.environment = self.environment.parent # Check for finally-clause and evaluate if so if len(ctx.children) == 4: ctx.children[3].accept(self) # Visit a parse tree produced by ECMAScriptParser#debuggerStatement. def visitDebuggerStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#DoStatement. def visitDoStatement(self, ctx): ctx.children[1].accept(self) while ctx.children[4].accept(self): if ctx.children[1].accept(self) == "BREAK-LOOP": break #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#ObjectLiteralExpression. def visitObjectLiteralExpression(self, ctx): obj = Object() # res is a list of tuples res = ctx.children[0].accept(self) for value in res: if len(value) == 3: prop = Property(obj) if value[0] == 'get': prop.getter = value[-1] else: prop.setter = value[-1] setattr(obj, str(value[1]), prop) else: setattr(obj, str(value[0]), value[1]) return obj #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#arrayLiteral. def visitArrayLiteral(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#elision. def visitElision(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#statements. def visitStatements(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryExpression. def visitUnaryExpression(self, ctx): node = ctx.children[0] if node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Minus: # 18 return -float(ctx.children[1].accept(self)) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Plus: # 17 return float(ctx.children[1].accept(self)) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.BitNot: # 19 return float(~int(ctx.children[1].accept(self))) elif node.symbol.type == ECMAScriptLexer.ECMAScriptLexer.Not: # 20 return not bool(ctx.children[1].accept(self)) else: raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#WhileStatement. def visitWhileStatement(self, ctx): while ctx.children[2].accept(self): res = ctx.children[4].accept(self) if res == "BREAK-LOOP": break #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#returnStatement. def visitReturnStatement(self, ctx): return ("RETURN", ctx.children[1].accept(self)) # Visit a parse tree produced by ECMAScriptParser#switchStatement. def visitSwitchStatement(self, ctx): val_to_switch = ctx.children[2].accept(self) case_found = False # Indicates a case without break has been found cases = ctx.children[4].accept(self) for case in cases: if val_to_switch == case[0] or case_found: if case[1].accept(self) == "BREAK-LOOP": return case_found = True # Handle default case here if not case_found: for case in cases: if case[0] == "DEFAULT": case[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#expressionSequence. def visitExpressionSequence(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#literal. def visitLiteral(self, ctx): res = ctx.children[0].accept(self) return res # Visit a parse tree produced by ECMAScriptParser#variableStatement. def visitVariableStatement(self, ctx): # TODO: should probably somehow check if the variable already has been declared / # perhaps return variable_name and value as a tuple and then check... args = ctx.children[1].accept(self) for name, value in args: self.environment.defineVariable(name, value) #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#FunctionExpression. def visitFunctionExpression(self, ctx): # Now uses the Function class # Check if it is an anonomous function if ctx.children[ 1].symbol.type == ECMAScriptLexer.ECMAScriptLexer.OpenParen: # 5 # Check if there are any params if isinstance( ctx.children[2], ECMAScriptParser.ECMAScriptParser. FormalParameterListContext): params = ctx.children[2].accept(self) body = ctx.children[5].accept(self) else: params = [] body = ctx.children[4].accept(self) new_func_to_return = Function(params, self.environment, body) setattr(new_func_to_return, "prototype", new_func_to_return) return new_func_to_return elif ctx.children[ 1].symbol.type == ECMAScriptLexer.ECMAScriptLexer.Identifier: # 100 variable declaration func_name = ctx.children[1].accept(self) # Check if there are any params if isinstance( ctx.children[3], ECMAScriptParser.ECMAScriptParser. FormalParameterListContext): params = ctx.children[3].accept(self) body = ctx.children[6].accept(self) else: params = [] body = ctx.children[5].accept(self) new_func = Function(params, self.environment, body) setattr(new_func, "prototype", new_func) self.environment.defineVariable(func_name, new_func) else: raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#defaultClause. def visitDefaultClause(self, ctx): return ("DEFAULT", ctx.children[2]) # Visit a parse tree produced by ECMAScriptParser#statement. def visitStatement(self, ctx): res = ctx.children[0].accept(self) return res class MockExpression(object): def __init__(self): self.v = True def accept(self, ctx): return True # Visit a parse tree produced by ECMAScriptParser#ForStatement. def visitForStatement(self, ctx): # This is working for the tests but there are alot of variations # of the for-loop that will not break, most of which will happen # when there is a variable definition in a statement. expression1 = InterpreterVisitor.MockExpression() expression2 = InterpreterVisitor.MockExpression() expression3 = InterpreterVisitor.MockExpression() # Three different cases to consider: 0,1,2 och 3(all) statements missing if len(ctx.children) == 10: # Not a really good solution, not generic at all... args = ctx.children[3].accept(self) for name, value in args: self.environment.defineVariable(name, value) expression2 = ctx.children[5] expression3 = ctx.children[7] elif len(ctx.children) == 9: # All statements provided expression1 = ctx.children[2] expression2 = ctx.children[4] expression3 = ctx.children[6] elif len(ctx.children) == 8: # One statement missing # Find which one if isinstance(ctx.children[2], antlr4.tree.Tree.TerminalNodeImpl): # First missing expression2 = ctx.children[3] expression3 = ctx.children[5] elif isinstance(ctx.children[4], antlr4.tree.Tree.TerminalNodeImpl): # Sec missing expression1 = ctx.children[2] expression3 = ctx.children[5] else: # third(last) missing expression1 = ctx.children[2] expression2 = ctx.children[4] elif len(ctx.children) == 7: # Two statements missing # Find which one exists if isinstance( ctx.children[2], ECMAScriptParser.ECMAScriptParser. ExpressionSequenceContext): # First provided expression1 = ctx.children[2] elif isinstance( ctx.children[3], ECMAScriptParser.ECMAScriptParser. ExpressionSequenceContext): # Second provided expression2 = ctx.children[3] else: # Third provided expression3 = ctx.children[4] #else: # all missing, no need to do anythin #print("In FOR-LOOP") #raise Utils.UnimplementedVisitorException(ctx) # Evaluate the for-loop: expression1.accept(self) while expression2.accept(self): # Execute the body if ctx.children[-1].accept(self) == "BREAK-LOOP": break # Execute last statement in for-loop expression3.accept(self) # Visit a parse tree produced by ECMAScriptParser#caseBlock. def visitCaseBlock(self, ctx): res = [] for c in ctx.children: if (not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," res.append(c.accept(self)) return res #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#ParenthesizedExpression. def visitParenthesizedExpression(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#objectLiteral. def visitObjectLiteral(self, ctx): res = [] for i in range(1, len(ctx.children), 2): res.append(ctx.children[i].accept(self)) return res # raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#throwStatement. def visitThrowStatement(self, ctx): #raise Utils.UnimplementedVisitorException(ctx) return ("THROW", ctx.children[1]) # Visit a parse tree produced by ECMAScriptParser#breakStatement. def visitBreakStatement(self, ctx): #raise Utils.UnimplementedVisitorException(ctx) return "BREAK-LOOP" # Visit a parse tree produced by ECMAScriptParser#ifStatement. def visitIfStatement(self, ctx): if not len(ctx.children) == 5 and not len(ctx.children) == 7: raise Utils.UnimplementedVisitorException(ctx) if ctx.children[2].accept(self): return ctx.children[4].accept(self) elif len(ctx.children) == 7: return ctx.children[6].accept(self) else: # The expression evaluated to false and no else clause: return None # Visit a parse tree produced by ECMAScriptParser#reservedWord. def visitReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#variableDeclaration. def visitVariableDeclaration(self, ctx): variable_name = ctx.children[0].accept(self) value = None if len(ctx.children) == 2: value = ctx.children[1].accept(self) #print('######', value) #pprint(vars(value)) return (variable_name, value) #raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#finallyProduction. def visitFinallyProduction(self, ctx): #raise Utils.UnimplementedVisitorException(ctx) return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#IdentifierExpression. def visitIdentifierExpression(self, ctx): res = self.environment.value(ctx.children[0].accept(self)) if isinstance(res, int): return float(res) else: return res # Visit a parse tree produced by ECMAScriptParser#propertyName. def visitPropertyName(self, ctx): return ctx.children[0].accept(self) raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#catchProduction. def visitCatchProduction(self, ctx): return (ctx.children[2], ctx.children[4]) # Visit a parse tree produced by ECMAScriptParser#continueStatement. def visitContinueStatement(self, ctx): return "CONTINUE-LOOP" # Visit a parse tree produced by ECMAScriptParser#caseClause. def visitCaseClause(self, ctx): return (ctx.children[1].accept(self), ctx.children[3]) # Visit a parse tree produced by ECMAScriptParser#arguments. def visitArguments(self, ctx): if len(ctx.children) == 2: return None else: return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#variableDeclarationList. def visitVariableDeclarationList(self, ctx): args = [] for c in ctx.children: if (not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," args.append(c.accept(self)) return args # Visit a parse tree produced by ECMAScriptParser#functionBody. def visitFunctionBody(self, ctx): # construct the function to be returned so this # body can be called def func(env): previous_environment = self.environment self.environment = Environment(env) for c in ctx.children: res = c.accept(self) if isinstance(res, tuple) and res[0] == "RETURN": res = res[1] break self.environment = previous_environment return res return func # Visit a parse tree produced by ECMAScriptParser#eof. def visitEof(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryAssignmentExpression. def visitUnaryAssignmentExpression(self, ctx): # It seems as if there is no way to determine if its pre- or postincrement # other than the position of IncrementOperatorContext in children # NOTE: It seem post increment is handled elsewhere... # Handle preincrement first if isinstance(ctx.children[1], antlr4.tree.Tree.TerminalNodeImpl): func = ctx.children[0].accept(self) var_name = ctx.children[1].accept(self) res = func(self.environment.value(var_name)) self.environment.setVariable(var_name, res) return float(res) else: raise Utils.UnimplementedVisitorException(ctx)
class InterpreterVisitor(ECMAScriptVisitor): def __init__(self, environment=Environment(), input=None): self.environment = environment self.environment.defineVariable("console", Console()) self.environment.defineVariable("Math", MathModule()) self.environment.defineVariable("Object", ObjectModule()) self.binaries = { '+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv, '%': operator.mod, '<<': lambda x, y: float(operator.lshift(int(x), int(y))), '>>': lambda x, y: float(operator.rshift(int(x), int(y))), '>>>': lambda x, y: float((int(x) % 0x100000000) >> int(y)), '<': operator.lt, '>': operator.gt, '<=': operator.le, '>=': operator.ge, '==': operator.eq, '!=': operator.ne, '===': lambda x, y: type(x) == type(y) and x == y, '!==': lambda x, y: type(x) != type(y) or x != y, '||': lambda x, y: x or y, '&&': lambda x, y: x and y } self.unaries = { '-': operator.neg, '+': operator.pos, '~': lambda x: float(~int(x)), '!': operator.not_, '++': lambda x: x.__add__(1), '--': lambda x: x.__add__(-1) } self.assignment = { '=': lambda x, y: y, '+=': operator.iadd, '-=': operator.isub, '*=': operator.mul, '/=': operator.truediv } def print_env_chain(self, env): if not env.parent: print("GlobalFrame:", env.variableDictionary) else: print("Frame:", env.variableDictionary) self.print_env_chain(env.parent) def inspector(self, ctx): print("‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾") print("In function: ", inspect.stack()[1].function) self.print_env_chain(self.environment) print("_______________________") print("") print("Begin child list, there are", len(ctx.children), "children.") i = 0 for child in ctx.children: try: typ = type(child.accept(self)) except: typ = "<Unacceptable>" val = child.getText() print(i, str(typ) + ": " + str(val)) i += 1 print("End child list of", inspect.stack()[1].function, "\t.!.") print("") def visitTerminal(self, node): if node.symbol.text == "true": return True elif node.symbol.text == "false": return False elif node.symbol.text[0] == '"' or node.symbol.text[0] == "'": return node.symbol.text[1:-1] elif node.symbol.text[0:2] == "0x": return float.fromhex(node.symbol.text) else: return node.symbol.text # Visit a parse tree produced by ECMAScriptParser#PropertyExpressionAssignment. def visitPropertyExpressionAssignment(self, ctx): return (ctx.children[0].accept(self), ctx.children[2].accept(self)) # Visit a parse tree produced by ECMAScriptParser#assignmentOperator. def visitAssignmentOperator(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#eos. def visitEos(self, ctx): return # Visit a parse tree produced by ECMAScriptParser#program. def visitProgram(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#argumentList. def visitArgumentList(self, ctx): args = [] for c in ctx.children: if (not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," args.append(c.accept(self)) return args # Visit a parse tree produced by ECMAScriptParser#ArgumentsExpression. def visitArgumentsExpression(self, ctx): this = self.environment.value(ctx.children[0].getText().split('.')[0]) func = ctx.children[0].accept(self) args = ctx.children[1].accept(self) if (args == None or args == ')'): args = [] if isinstance(func, types.MethodType ) and func.__func__ == ObjectModule.defineProperty: return func(args[0], *args) else: return func(this, *args) # Visit a parse tree produced by ECMAScriptParser#ThisExpression. def visitThisExpression(self, ctx): return self.environment.value(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#identifierName. def visitIdentifierName(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#BinaryExpression. def visitBinaryExpression(self, ctx): arg1 = ctx.children[0].accept(self) operator = ctx.children[1].accept(self) if operator == "&&": return arg1 and ctx.children[2].accept(self) elif operator == "||": return arg1 or ctx.children[2].accept(self) arg2 = ctx.children[2].accept(self) return self.binaries[operator](arg1, arg2) # Visit a parse tree produced by ECMAScriptParser#futureReservedWord. def visitFutureReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#initialiser. def visitInitialiser(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#statementList. def visitStatementList(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#PropertyGetter. def visitPropertyGetter(self, ctx): name = ctx.children[1].accept(self) body = ctx.children[5].accept(self) param = Object() param.get = Function([], self.environment, body) return (name, param) # Visit a parse tree produced by ECMAScriptParser#block. def visitBlock(self, ctx): # We don't have to define any environment since we don't have # to implement the let keyword. self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#expressionStatement. def visitExpressionStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#keyword. def visitKeyword(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#elementList. def visitElementList(self, ctx): return self.childrenToList(ctx.children) # Visit a parse tree produced by ECMAScriptParser#numericLiteral. def visitNumericLiteral(self, ctx): return float(self.visitChildren(ctx)) # Visit a parse tree produced by ECMAScriptParser#ForInStatement. def visitForInStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#emptyStatement. def visitEmptyStatement(self, ctx): return # Visit a parse tree produced by ECMAScriptParser#labelledStatement. def visitLabelledStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#PropertySetter. def visitPropertySetter(self, ctx): name = ctx.children[1].accept(self) argName = ctx.children[3].accept(self) body = ctx.children[6].accept(self) param = Object() param.set = Function([argName], self.environment, body) return (name, param) # Visit a parse tree produced by ECMAScriptParser#NewExpression. def visitNewExpression(self, ctx): func = ctx.children[1].accept(self) args = ctx.children[2].accept(self) if (args == None or args == ')'): args = [] if hasattr(func, "prototype") and hasattr(func.prototype, "create"): theNewObject = func.prototype.create(None, func.prototype) else: theNewObject = ObjectModule() self.environment = Environment(self.environment) func(theNewObject, *args) self.environment.defineVariable('this', theNewObject) if self.environment.parent: self.environment = self.environment.parent return theNewObject # Visit a parse tree produced by ECMAScriptParser#LiteralExpression. def visitLiteralExpression(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#ArrayLiteralExpression. def visitArrayLiteralExpression(self, ctx): return JSList(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#MemberDotExpression. def visitMemberDotExpression(self, ctx): obj = ctx.children[0].accept(self) member = ctx.children[2].accept(self) retval = getattr(obj, member) if type(retval) == Property: if isinstance(retval.get(), types.MethodType): return retval.get()() return retval.get() else: return retval # Visit a parse tree produced by ECMAScriptParser#withStatement. def visitWithStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#MemberIndexExpression. def visitMemberIndexExpression(self, ctx): array = ctx.children[0].accept(self) index = ctx.children[2].accept(self) if type(array) == ObjectModule: return array.__dict__[str(index)] else: return array[int(index)] # Visit a parse tree produced by ECMAScriptParser#formalParameterList. def visitFormalParameterList(self, ctx): return self.childrenToList(ctx.children) # Visit a parse tree produced by ECMAScriptParser#incrementOperator. def visitIncrementOperator(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#AssignmentOperatorExpression. def visitAssignmentOperatorExpression(self, ctx): name = ctx.children[0].getText() # We're doing arrays now. if ctx.children[1].getText() == '[': index = ctx.children[2].accept(self) operator = ctx.children[4].accept(self) rhs = ctx.children[5].accept(self) lhs = self.environment.value(name) if type(lhs) == ObjectModule: lhs.__dict__[index] = self.assignment[operator]( lhs.__dict__[index], rhs) value = lhs.__dict__[index] else: lhs[int(index)] = self.assignment[operator](lhs[int(index)], rhs) value = lhs[int(index)] self.environment.setVariable(name, lhs) elif ctx.children[1].getText() == '.': key = ctx.children[2].accept(self) operator = ctx.children[3].accept(self) rhs = ctx.children[4].accept(self) lhs = ctx.children[0].accept(self) if key not in lhs.__dict__: lhs.__dict__[key] = None # Is there a setter there? if type(lhs.__dict__[key]) == Property: lhs.__dict__[key].set(rhs) value = rhs else: lhs.__dict__[key] = self.assignment[operator]( lhs.__dict__[key], rhs) value = lhs.__dict__[key] # If there are nestled objects if '.' in name: rootName = name.split('.')[0] rootObject = self.environment.value(rootName) rootObject.__dict__[name.split('.')[1]] = lhs self.environment.defineVariable(rootName, rootObject) else: self.environment.setVariable(name, lhs) else: operator = ctx.children[1].accept(self) rhs = ctx.children[2].accept(self) lhs = self.environment.value(name) if not self.environment.exists(name) and operator == '=': self.environment.defineGlobal(name) value = self.assignment[operator](lhs, rhs) self.environment.setVariable(name, value) return value # Visit a parse tree produced by ECMAScriptParser#PostUnaryAssignmentExpression. def visitPostUnaryAssignmentExpression(self, ctx): name = ctx.children[0].accept(self) operator = ctx.children[1].accept(self) value = self.environment.value(name) self.environment.setVariable(name, self.unaries[operator](value)) return value # Visit a parse tree produced by ECMAScriptParser#TernaryExpression. def visitTernaryExpression(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#tryStatement. def visitTryStatement(self, ctx): try: ctx.children[1].accept(self) except ESException as e: ctx.children[2].exceptionValue = e.value ctx.children[2].accept(self) if len(ctx.children) == 4: ctx.children[3].accept(self) # Visit a parse tree produced by ECMAScriptParser#debuggerStatement. def visitDebuggerStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#DoStatement. def visitDoStatement(self, ctx): ctx.children[1].accept(self) while ctx.children[4].accept(self): ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#ObjectLiteralExpression. def visitObjectLiteralExpression(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#arrayLiteral. def visitArrayLiteral(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#elision. def visitElision(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#statements. def visitStatements(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryExpression. def visitUnaryExpression(self, ctx): operator = ctx.children[0].accept(self) argument = ctx.children[1].accept(self) return self.unaries[operator](argument) # Visit a parse tree produced by ECMAScriptParser#WhileStatement. def visitWhileStatement(self, ctx): while ctx.children[2].accept(self): try: ctx.children[4].accept(self) except BreakException: break except ContinueException: continue # Visit a parse tree produced by ECMAScriptParser#returnStatement. def visitReturnStatement(self, ctx): returnValue = ctx.children[1].accept(self) raise ReturnException(returnValue) # Visit a parse tree produced by ECMAScriptParser#switchStatement. def visitSwitchStatement(self, ctx): ctx.children[4].chosenValue = ctx.children[2].accept(self) ctx.children[4].accept(self) # Visit a parse tree produced by ECMAScriptParser#expressionSequence. def visitExpressionSequence(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#literal. def visitLiteral(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#variableStatement. def visitVariableStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#FunctionExpression. def visitFunctionExpression(self, ctx): argumentIndex = 3 # If we are dealing with a lambda. if ctx.children[1].getText() == '(': argumentIndex -= 1 else: name = ctx.children[1].accept(self) if ctx.children[argumentIndex].getText() == ')': arguments = [] argumentIndex -= 1 else: arguments = ctx.children[argumentIndex].accept(self) body = ctx.children[argumentIndex + 3].accept(self) function = Function(arguments, self.environment, body) if ctx.children[1].getText() == '(': return Function(arguments, self.environment, body) else: self.environment.defineVariable(name, function) # Visit a parse tree produced by ECMAScriptParser#defaultClause. def visitDefaultClause(self, ctx): return (ctx.children[0].accept(self), ctx.children[2]) # Visit a parse tree produced by ECMAScriptParser#statement. def visitStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#ForStatement. def visitForStatement(self, ctx): initialization = ctx.children[2].accept(self) condIndex = 4 if initialization == ';': condIndex -= 1 elif initialization == 'var': condIndex += 1 ctx.children[3].accept(self) condition = ctx.children[condIndex].accept(self) incrementorIndex = condIndex + 2 if condition == ';': incrementorIndex -= 1 incrementor = ctx.children[incrementorIndex].getText() expressionIndex = incrementorIndex + 2 if incrementor == ')': expressionIndex -= 1 while ctx.children[condIndex].accept(self): try: ctx.children[expressionIndex].accept(self) ctx.children[incrementorIndex].accept(self) except BreakException: break except ContinueException: ctx.children[incrementorIndex].accept(self) continue # Visit a parse tree produced by ECMAScriptParser#caseBlock. def visitCaseBlock(self, ctx): keyBodyPairs = collections.OrderedDict() for child in ctx.children[1:-1]: (key, body) = child.accept(self) keyBodyPairs[key] = body keys = list(keyBodyPairs) if ctx.chosenValue in keys: startIndex = keys.index(ctx.chosenValue) elif "default" in keys: startIndex = keys.index("default") bodies = list(keyBodyPairs.values()) for body in bodies[startIndex:]: try: body.accept(self) except BreakException: break # Visit a parse tree produced by ECMAScriptParser#ParenthesizedExpression. def visitParenthesizedExpression(self, ctx): # Return what's between the parenthesis ( what ). return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#objectLiteral. def visitObjectLiteral(self, ctx): obj = ObjectModule() for key, value in self.childrenToList(ctx.children[1:-1]): if hasattr(value, "get") or hasattr(value, "set"): obj.defineProperty(obj, obj, str(key), value) else: setattr(obj, str(key), value) return obj # Visit a parse tree produced by ECMAScriptParser#throwStatement. def visitThrowStatement(self, ctx): raise ESException(ctx.children[1].accept(self)) # Visit a parse tree produced by ECMAScriptParser#breakStatement. def visitBreakStatement(self, ctx): raise BreakException() # Visit a parse tree produced by ECMAScriptParser#ifStatement. def visitIfStatement(self, ctx): if ctx.children[2].accept(self): ctx.children[4].accept(self) # If there is an else statement elif len(ctx.children) > 6: ctx.children[6].accept(self) # Visit a parse tree produced by ECMAScriptParser#reservedWord. def visitReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#variableDeclaration. def visitVariableDeclaration(self, ctx): name = ctx.children[0].accept(self) if len(ctx.children) == 2: value = ctx.children[1].accept(self) else: value = None self.environment.defineVariable(name, value) # Visit a parse tree produced by ECMAScriptParser#finallyProduction. def visitFinallyProduction(self, ctx): ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#IdentifierExpression. def visitIdentifierExpression(self, ctx): return self.environment.value(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#propertyName. def visitPropertyName(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#catchProduction. def visitCatchProduction(self, ctx): exceptionName = ctx.children[2].accept(self) self.environment.defineVariable(exceptionName, ctx.exceptionValue) ctx.children[4].accept(self) self.environment.removeVariable(exceptionName) # Visit a parse tree produced by ECMAScriptParser#continueStatement. def visitContinueStatement(self, ctx): raise ContinueException # Visit a parse tree produced by ECMAScriptParser#caseClause. def visitCaseClause(self, ctx): return (ctx.children[1].accept(self), ctx.children[3]) # Visit a parse tree produced by ECMAScriptParser#arguments. def visitArguments(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#variableDeclarationList. def visitVariableDeclarationList(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#functionBody. def visitFunctionBody(self, ctx): def runFunction(environment): self.environment = Environment(environment) for c in ctx.children: try: c.accept(self) except ReturnException as re: return re.value finally: self.environment = self.environment.parent return runFunction # Visit a parse tree produced by ECMAScriptParser#eof. def visitEof(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryAssignmentExpression. def visitUnaryAssignmentExpression(self, ctx): operator = ctx.children[0].accept(self) name = ctx.children[1].accept(self) value = self.environment.value(name) self.environment.setVariable(name, self.unaries[operator](value)) return self.environment.value(name) def childrenToList(self, items): return [ item.accept(self) for item in items if not item.getText() == ',' ]
from Interpreter.Environment import Environment env = Environment() env.value("lol")
class InterpreterVisitor(ECMAScriptVisitor): def __init__(self, environment = Environment(), input=None): self.environment = environment self.environment.defineVariable("console", Console()) self.environment.defineVariable("Math", MathModule()) self.environment.defineVariable("Object", ObjectModule()) self.binaries = { '+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv, '%': operator.mod, '<<': lambda x, y: float(operator.lshift(int(x), int(y))), '>>': lambda x, y: float(operator.rshift(int(x), int(y))), '>>>': lambda x, y: float((int(x) % 0x100000000) >> int(y)), '<': operator.lt, '>': operator.gt, '<=': operator.le, '>=': operator.ge, '==': operator.eq, '!=': operator.ne, '===': lambda x, y: type(x) == type(y) and x == y, '!==': lambda x, y: type(x) != type(y) or x != y, '||': lambda x, y: x or y, '&&': lambda x, y: x and y } self.unaries = { '-': operator.neg, '+': operator.pos, '~': lambda x: float(~int(x)), '!': operator.not_, '++': lambda x: x.__add__(1), '--': lambda x: x.__add__(-1)} self.assignment = { '=': lambda x, y: y, '+=': operator.iadd, '-=': operator.isub, '*=': operator.mul, '/=': operator.truediv} def print_env_chain(self, env): if not env.parent: print("GlobalFrame:", env.variableDictionary) else: print("Frame:", env.variableDictionary) self.print_env_chain(env.parent) def inspector(self, ctx): print("‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾") print("In function: ", inspect.stack()[1].function) self.print_env_chain(self.environment) print("_______________________") print("") print("Begin child list, there are", len(ctx.children), "children.") i = 0 for child in ctx.children: try: typ = type(child.accept(self)) except: typ = "<Unacceptable>" val = child.getText() print(i, str(typ) + ": " + str(val)) i += 1 print("End child list of", inspect.stack()[1].function, "\t.!.") print("") def visitTerminal(self, node): if node.symbol.text == "true": return True elif node.symbol.text == "false": return False elif node.symbol.text[0] == '"' or node.symbol.text[0] == "'" : return node.symbol.text[1:-1] elif node.symbol.text[0:2] == "0x": return float.fromhex(node.symbol.text) else: return node.symbol.text # Visit a parse tree produced by ECMAScriptParser#PropertyExpressionAssignment. def visitPropertyExpressionAssignment(self, ctx): return (ctx.children[0].accept(self), ctx.children[2].accept(self)) # Visit a parse tree produced by ECMAScriptParser#assignmentOperator. def visitAssignmentOperator(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#eos. def visitEos(self, ctx): return # Visit a parse tree produced by ECMAScriptParser#program. def visitProgram(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#argumentList. def visitArgumentList(self, ctx): args = [] for c in ctx.children: if(not isinstance(c, antlr4.tree.Tree.TerminalNodeImpl)): # Skip "," args.append(c.accept(self)) return args # Visit a parse tree produced by ECMAScriptParser#ArgumentsExpression. def visitArgumentsExpression(self, ctx): this = self.environment.value(ctx.children[0].getText().split('.')[0]) func = ctx.children[0].accept(self) args = ctx.children[1].accept(self) if(args == None or args == ')'): args = [] if isinstance(func, types.MethodType) and func.__func__ == ObjectModule.defineProperty: return func(args[0], *args) else: return func(this, *args) # Visit a parse tree produced by ECMAScriptParser#ThisExpression. def visitThisExpression(self, ctx): return self.environment.value(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#identifierName. def visitIdentifierName(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#BinaryExpression. def visitBinaryExpression(self, ctx): arg1 = ctx.children[0].accept(self) operator = ctx.children[1].accept(self) if operator == "&&": return arg1 and ctx.children[2].accept(self) elif operator == "||": return arg1 or ctx.children[2].accept(self) arg2 = ctx.children[2].accept(self) return self.binaries[operator](arg1, arg2) # Visit a parse tree produced by ECMAScriptParser#futureReservedWord. def visitFutureReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#initialiser. def visitInitialiser(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#statementList. def visitStatementList(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#PropertyGetter. def visitPropertyGetter(self, ctx): name = ctx.children[1].accept(self) body = ctx.children[5].accept(self) param = Object() param.get = Function([], self.environment, body) return (name, param) # Visit a parse tree produced by ECMAScriptParser#block. def visitBlock(self, ctx): # We don't have to define any environment since we don't have # to implement the let keyword. self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#expressionStatement. def visitExpressionStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#keyword. def visitKeyword(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#elementList. def visitElementList(self, ctx): return self.childrenToList(ctx.children) # Visit a parse tree produced by ECMAScriptParser#numericLiteral. def visitNumericLiteral(self, ctx): return float(self.visitChildren(ctx)) # Visit a parse tree produced by ECMAScriptParser#ForInStatement. def visitForInStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#emptyStatement. def visitEmptyStatement(self, ctx): return # Visit a parse tree produced by ECMAScriptParser#labelledStatement. def visitLabelledStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#PropertySetter. def visitPropertySetter(self, ctx): name = ctx.children[1].accept(self) argName = ctx.children[3].accept(self) body = ctx.children[6].accept(self) param = Object() param.set = Function([argName], self.environment, body) return (name, param) # Visit a parse tree produced by ECMAScriptParser#NewExpression. def visitNewExpression(self, ctx): func = ctx.children[1].accept(self) args = ctx.children[2].accept(self) if(args == None or args == ')'): args = [] if hasattr(func, "prototype") and hasattr(func.prototype, "create"): theNewObject = func.prototype.create(None, func.prototype) else: theNewObject = ObjectModule() self.environment = Environment(self.environment) func(theNewObject, *args) self.environment.defineVariable('this', theNewObject) if self.environment.parent: self.environment = self.environment.parent return theNewObject # Visit a parse tree produced by ECMAScriptParser#LiteralExpression. def visitLiteralExpression(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#ArrayLiteralExpression. def visitArrayLiteralExpression(self, ctx): return JSList(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#MemberDotExpression. def visitMemberDotExpression(self, ctx): obj = ctx.children[0].accept(self) member = ctx.children[2].accept(self) retval = getattr(obj, member) if type(retval) == Property: if isinstance(retval.get(), types.MethodType): return retval.get()() return retval.get() else: return retval # Visit a parse tree produced by ECMAScriptParser#withStatement. def visitWithStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#MemberIndexExpression. def visitMemberIndexExpression(self, ctx): array = ctx.children[0].accept(self) index = ctx.children[2].accept(self) if type(array) == ObjectModule: return array.__dict__[str(index)] else: return array[int(index)] # Visit a parse tree produced by ECMAScriptParser#formalParameterList. def visitFormalParameterList(self, ctx): return self.childrenToList(ctx.children) # Visit a parse tree produced by ECMAScriptParser#incrementOperator. def visitIncrementOperator(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#AssignmentOperatorExpression. def visitAssignmentOperatorExpression(self, ctx): name = ctx.children[0].getText() # We're doing arrays now. if ctx.children[1].getText() == '[': index = ctx.children[2].accept(self) operator = ctx.children[4].accept(self) rhs = ctx.children[5].accept(self) lhs = self.environment.value(name) if type(lhs) == ObjectModule: lhs.__dict__[index] = self.assignment[operator](lhs.__dict__[index], rhs) value = lhs.__dict__[index] else: lhs[int(index)] = self.assignment[operator](lhs[int(index)], rhs) value = lhs[int(index)] self.environment.setVariable(name, lhs) elif ctx.children[1].getText() == '.': key = ctx.children[2].accept(self) operator = ctx.children[3].accept(self) rhs = ctx.children[4].accept(self) lhs = ctx.children[0].accept(self) if key not in lhs.__dict__: lhs.__dict__[key] = None # Is there a setter there? if type(lhs.__dict__[key]) == Property: lhs.__dict__[key].set(rhs) value = rhs else: lhs.__dict__[key] = self.assignment[operator](lhs.__dict__[key], rhs) value = lhs.__dict__[key] # If there are nestled objects if '.' in name: rootName = name.split('.')[0] rootObject = self.environment.value(rootName) rootObject.__dict__[name.split('.')[1]] = lhs self.environment.defineVariable(rootName, rootObject) else: self.environment.setVariable(name, lhs) else: operator = ctx.children[1].accept(self) rhs = ctx.children[2].accept(self) lhs = self.environment.value(name) if not self.environment.exists(name) and operator == '=': self.environment.defineGlobal(name) value = self.assignment[operator](lhs, rhs) self.environment.setVariable(name, value) return value # Visit a parse tree produced by ECMAScriptParser#PostUnaryAssignmentExpression. def visitPostUnaryAssignmentExpression(self, ctx): name = ctx.children[0].accept(self) operator = ctx.children[1].accept(self) value = self.environment.value(name) self.environment.setVariable(name, self.unaries[operator](value)) return value # Visit a parse tree produced by ECMAScriptParser#TernaryExpression. def visitTernaryExpression(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#tryStatement. def visitTryStatement(self, ctx): try: ctx.children[1].accept(self) except ESException as e: ctx.children[2].exceptionValue = e.value ctx.children[2].accept(self) if len(ctx.children) == 4: ctx.children[3].accept(self) # Visit a parse tree produced by ECMAScriptParser#debuggerStatement. def visitDebuggerStatement(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#DoStatement. def visitDoStatement(self, ctx): ctx.children[1].accept(self) while ctx.children[4].accept(self): ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#ObjectLiteralExpression. def visitObjectLiteralExpression(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#arrayLiteral. def visitArrayLiteral(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#elision. def visitElision(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#statements. def visitStatements(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryExpression. def visitUnaryExpression(self, ctx): operator = ctx.children[0].accept(self) argument = ctx.children[1].accept(self) return self.unaries[operator](argument) # Visit a parse tree produced by ECMAScriptParser#WhileStatement. def visitWhileStatement(self, ctx): while ctx.children[2].accept(self): try: ctx.children[4].accept(self) except BreakException: break except ContinueException: continue # Visit a parse tree produced by ECMAScriptParser#returnStatement. def visitReturnStatement(self, ctx): returnValue = ctx.children[1].accept(self) raise ReturnException(returnValue) # Visit a parse tree produced by ECMAScriptParser#switchStatement. def visitSwitchStatement(self, ctx): ctx.children[4].chosenValue = ctx.children[2].accept(self) ctx.children[4].accept(self) # Visit a parse tree produced by ECMAScriptParser#expressionSequence. def visitExpressionSequence(self, ctx): return self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#literal. def visitLiteral(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#variableStatement. def visitVariableStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#FunctionExpression. def visitFunctionExpression(self, ctx): argumentIndex = 3 # If we are dealing with a lambda. if ctx.children[1].getText() == '(': argumentIndex -= 1 else: name = ctx.children[1].accept(self) if ctx.children[argumentIndex].getText() == ')': arguments = [] argumentIndex -= 1 else: arguments = ctx.children[argumentIndex].accept(self) body = ctx.children[argumentIndex + 3].accept(self) function = Function(arguments, self.environment, body) if ctx.children[1].getText() == '(': return Function(arguments, self.environment, body) else: self.environment.defineVariable(name, function) # Visit a parse tree produced by ECMAScriptParser#defaultClause. def visitDefaultClause(self, ctx): return (ctx.children[0].accept(self), ctx.children[2]) # Visit a parse tree produced by ECMAScriptParser#statement. def visitStatement(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#ForStatement. def visitForStatement(self, ctx): initialization = ctx.children[2].accept(self) condIndex = 4 if initialization == ';': condIndex -= 1 elif initialization == 'var': condIndex += 1 ctx.children[3].accept(self) condition = ctx.children[condIndex].accept(self) incrementorIndex = condIndex + 2 if condition == ';': incrementorIndex -= 1 incrementor = ctx.children[incrementorIndex].getText() expressionIndex = incrementorIndex + 2 if incrementor == ')': expressionIndex -= 1 while ctx.children[condIndex].accept(self): try: ctx.children[expressionIndex].accept(self) ctx.children[incrementorIndex].accept(self) except BreakException: break except ContinueException: ctx.children[incrementorIndex].accept(self) continue # Visit a parse tree produced by ECMAScriptParser#caseBlock. def visitCaseBlock(self, ctx): keyBodyPairs = collections.OrderedDict() for child in ctx.children[1:-1]: (key, body) = child.accept(self) keyBodyPairs[key] = body keys = list(keyBodyPairs) if ctx.chosenValue in keys: startIndex = keys.index(ctx.chosenValue) elif "default" in keys: startIndex = keys.index("default") bodies = list(keyBodyPairs.values()) for body in bodies[startIndex:]: try: body.accept(self) except BreakException: break # Visit a parse tree produced by ECMAScriptParser#ParenthesizedExpression. def visitParenthesizedExpression(self, ctx): # Return what's between the parenthesis ( what ). return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#objectLiteral. def visitObjectLiteral(self, ctx): obj = ObjectModule() for key, value in self.childrenToList(ctx.children[1:-1]): if hasattr(value, "get") or hasattr(value, "set"): obj.defineProperty(obj, obj, str(key), value) else: setattr(obj, str(key), value) return obj # Visit a parse tree produced by ECMAScriptParser#throwStatement. def visitThrowStatement(self, ctx): raise ESException(ctx.children[1].accept(self)) # Visit a parse tree produced by ECMAScriptParser#breakStatement. def visitBreakStatement(self, ctx): raise BreakException() # Visit a parse tree produced by ECMAScriptParser#ifStatement. def visitIfStatement(self, ctx): if ctx.children[2].accept(self): ctx.children[4].accept(self) # If there is an else statement elif len(ctx.children) > 6: ctx.children[6].accept(self) # Visit a parse tree produced by ECMAScriptParser#reservedWord. def visitReservedWord(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#variableDeclaration. def visitVariableDeclaration(self, ctx): name = ctx.children[0].accept(self) if len(ctx.children) == 2: value = ctx.children[1].accept(self) else: value = None self.environment.defineVariable(name, value) # Visit a parse tree produced by ECMAScriptParser#finallyProduction. def visitFinallyProduction(self, ctx): ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#IdentifierExpression. def visitIdentifierExpression(self, ctx): return self.environment.value(ctx.children[0].accept(self)) # Visit a parse tree produced by ECMAScriptParser#propertyName. def visitPropertyName(self, ctx): return ctx.children[0].accept(self) # Visit a parse tree produced by ECMAScriptParser#catchProduction. def visitCatchProduction(self, ctx): exceptionName = ctx.children[2].accept(self) self.environment.defineVariable(exceptionName, ctx.exceptionValue) ctx.children[4].accept(self) self.environment.removeVariable(exceptionName) # Visit a parse tree produced by ECMAScriptParser#continueStatement. def visitContinueStatement(self, ctx): raise ContinueException # Visit a parse tree produced by ECMAScriptParser#caseClause. def visitCaseClause(self, ctx): return (ctx.children[1].accept(self), ctx.children[3]) # Visit a parse tree produced by ECMAScriptParser#arguments. def visitArguments(self, ctx): return ctx.children[1].accept(self) # Visit a parse tree produced by ECMAScriptParser#variableDeclarationList. def visitVariableDeclarationList(self, ctx): self.visitChildren(ctx) # Visit a parse tree produced by ECMAScriptParser#functionBody. def visitFunctionBody(self, ctx): def runFunction(environment): self.environment = Environment(environment) for c in ctx.children: try: c.accept(self) except ReturnException as re: return re.value finally: self.environment = self.environment.parent return runFunction # Visit a parse tree produced by ECMAScriptParser#eof. def visitEof(self, ctx): raise Utils.UnimplementedVisitorException(ctx) # Visit a parse tree produced by ECMAScriptParser#UnaryAssignmentExpression. def visitUnaryAssignmentExpression(self, ctx): operator = ctx.children[0].accept(self) name = ctx.children[1].accept(self) value = self.environment.value(name) self.environment.setVariable(name, self.unaries[operator](value)) return self.environment.value(name) def childrenToList(self, items): return [item.accept(self) for item in items if not item.getText() == ',']