コード例 #1
0
 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)
コード例 #2
0
    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)
コード例 #3
0
  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)
コード例 #4
0
    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)
コード例 #5
0
    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)
コード例 #6
0
  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)
コード例 #7
0
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)
コード例 #8
0
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() == ','
        ]
コード例 #9
0
from Interpreter.Environment import Environment
env = Environment()
env.value("lol")
コード例 #10
0
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() == ',']