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)
예제 #3
0
 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
예제 #4
0
        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
예제 #5
0
 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
 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 __call__(self, this, *args):
    '''
    Call the function. With the this argument.

    step by step:
    create function-environment with correct parent in the local scope
    create pointer to self (this)
    zip argument names from function initiation with argument values
    set all environment variables with its values
    return function-body(function-arguments) == return f(x)
    '''
    localEnvironment = Environment(self.parent)
    localEnvironment.defineVariable("this", this)
    argValuePairs = zip(self.argNames, args)
    for name, value in argValuePairs:
      localEnvironment.defineVariable(name, value)

    return self.body(localEnvironment)
 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
예제 #9
0
    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)
    def test_024_new(self):
        def func_new(env):
            self.assertTrue(env.value("this"), Object)
            self.assertEqual(env.value('a'), 1.0)
            self.assertEqual(env.value('b'), 2.0)

        f = Function(['a', 'b'], Environment(), func_new)
        self.run_test_executor([[OpCode.PUSH, 1.0], [OpCode.PUSH, 2.0],
                                [OpCode.PUSH, f], [OpCode.NEW, 2]], [Object()],
                               {}, {})
    def test_023_call(self):
        global test_014_called
        test_014_called = False

        def func_body(env):
            global test_014_called
            test_014_called = True

        f = Function([], Environment(), func_body)
        self.run_test_executor([[OpCode.PUSH, f], [OpCode.CALL, 0]], [None],
                               {}, {})
        self.assertTrue(test_014_called)

        def func_body_params(env):
            self.assertEqual(env.value('a'), 1.0)
            self.assertEqual(env.value('b'), 2.0)

        f = Function(['a', 'b'], Environment(), func_body)
        self.run_test_executor([[OpCode.PUSH, 1.0], [OpCode.PUSH, 2.0],
                                [OpCode.PUSH, f], [OpCode.CALL, 2]], [None],
                               {}, {})
  def call(self, that, this, *args):
    '''
    Call the function. This function is usefull since in ECMAScript, a function is an object and it can be called with the function "call". For instance:
    
    function MyFunction(arg)
    {
      console.log(arg)
    }
    MyFunction.call(2)
    
    In which case, that is a pointer to MyFunction and this to None. But where it becomes tricky is with:
    
    var obj = { member: function(arg) { this.value = arg } }
    obj.call(2)
    
    In which case that contains obj.member and this contains obj.
    
    In practice, the that argument can be ignored.
    
    In other word:
    * that is the pointer to the object of the function
    * this is the pointer to the object (equivalent of self in python)
    * args is the list of arguments passed to the function
    '''

    # Should you create a new Environment here and add the args to that env?
    current_env = Environment(self.environment)

    for i in range(len(args)):
      current_env.defineVariable(self.args[i], args[i])
    # Add 'this' and 'that' to current_env??
    current_env.defineVariable('this', this)
    current_env.defineVariable('that', that)
    return self.body(current_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)
 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
  def __call__(self, this, *args, thatVar=None):
    '''
    Call the function. With the this argument.

    step by step:
    create function-environment with correct parent in the local scope
    create pointer to self (this)
    zip argument names from function initiation with argument values
    set all environment variables with its values
    return function-body(function-arguments) == return f(x)
    '''

    localEnvironment = Environment(self.parent)
    if this:
      localEnvironment.defineVariable("this", this)
    if thatVar:
      localEnvironment.defineVariable("that", thatVar)
    argValuePairs = zip(self.argNames, args)
    for name, value in argValuePairs:
      localEnvironment.defineVariable(name, value)

    return self.body(localEnvironment)
예제 #16
0
 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
     }
예제 #17
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)
    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)
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() == ',']
예제 #20
0
#!/usr/bin/env python3

from Interpreter.Function import Function
from Interpreter.Environment import Environment

f = Function(["arg1", "arg2"], Environment(), lambda env: print(env.value("arg1") + env.value("arg2")))
f(None,1,2)
from Interpreter.Environment import Environment
env = Environment()
env.value("lol")
    def __init__(self, environment=Environment()):
        self.environment = environment
        self.stack = Stack()
        self.current_index = 0
        self.return_values = Stack()  # Stack to push/pop return values
        self.try_addresses = Stack()  # Stack to push/pop addresses

        # The following code acts as a switch statements for OpCodes
        self.opmaps = {}
        # Stack
        self.opmaps[OpCode.PUSH] = Executor.execute_push
        self.opmaps[OpCode.POP] = Executor.execute_pop
        self.opmaps[OpCode.DUP] = Executor.execute_dup
        self.opmaps[OpCode.SWAP] = Executor.execute_swap
        # Environment and objects manipulation
        self.opmaps[OpCode.LOAD] = Executor.execute_load
        self.opmaps[OpCode.STORE] = Executor.execute_store
        self.opmaps[OpCode.DCL] = Executor.execute_dcl
        self.opmaps[OpCode.LOAD_MEMBER] = Executor.execute_load_member
        self.opmaps[OpCode.STORE_MEMBER] = Executor.execute_store_member
        self.opmaps[OpCode.LOAD_INDEX] = Executor.execute_load_index
        self.opmaps[OpCode.STORE_INDEX] = Executor.execute_store_index
        # Control
        self.opmaps[OpCode.JMP] = Executor.execute_jmp
        self.opmaps[OpCode.IFJMP] = Executor.execute_ifjmp
        self.opmaps[OpCode.UNLESSJMP] = Executor.execute_unlessjmp
        self.opmaps[OpCode.CALL] = Executor.execute_call
        self.opmaps[OpCode.NEW] = Executor.execute_new
        self.opmaps[OpCode.RET] = Executor.execute_ret
        self.opmaps[OpCode.SWITCH] = Executor.execute_switch
        # Exceptions
        self.opmaps[OpCode.TRY_PUSH] = Executor.execute_try_push
        self.opmaps[OpCode.THROW] = Executor.execute_throw
        self.opmaps[OpCode.TRY_POP] = Executor.execute_try_pop
        # Array and Objects creation
        self.opmaps[OpCode.MAKE_ARRAY] = Executor.execute_make_array
        self.opmaps[OpCode.MAKE_OBJECT] = Executor.execute_make_object
        self.opmaps[OpCode.MAKE_FUNC] = Executor.execute_make_func
        self.opmaps[OpCode.MAKE_GETTER] = Executor.execute_make_getter
        self.opmaps[OpCode.MAKE_SETTER] = Executor.execute_make_setter
        # Binary arithmetic operation
        self.opmaps[OpCode.ADD] = Executor.execute_add
        self.opmaps[OpCode.SUB] = Executor.execute_sub
        self.opmaps[OpCode.DIV] = Executor.execute_div
        self.opmaps[OpCode.MUL] = Executor.execute_mul
        self.opmaps[OpCode.MOD] = Executor.execute_mod
        self.opmaps[OpCode.LEFT_SHIFT] = Executor.execute_left_shift
        self.opmaps[OpCode.RIGHT_SHIFT] = Executor.execute_right_shift
        self.opmaps[
            OpCode.
            UNSIGNED_RIGHT_SHIFT] = Executor.execute_unsigned_right_shift
        # Binary bolean operation
        self.opmaps[OpCode.SUPPERIOR] = Executor.execute_superior
        self.opmaps[OpCode.SUPPERIOR_EQUAL] = Executor.execute_superior_equal
        self.opmaps[OpCode.INFERIOR] = Executor.execute_inferior
        self.opmaps[OpCode.INFERIOR_EQUAL] = Executor.execute_inferior_equal
        self.opmaps[OpCode.EQUAL] = Executor.execute_equal
        self.opmaps[OpCode.DIFFERENT] = Executor.execute_different
        self.opmaps[OpCode.AND] = Executor.execute_and
        self.opmaps[OpCode.OR] = Executor.execute_or
        # Unary operations
        self.opmaps[OpCode.NEG] = Executor.execute_neg
        self.opmaps[OpCode.TILDE] = Executor.execute_tilde
        self.opmaps[OpCode.NOT] = Executor.execute_not
예제 #23
0
    def __init__(self, environment=Environment()):
        self.environment = environment
        self.stack = Stack()
        self.try_stack = Stack()
        self.program_counter = 0
        self.program_counter_stack = []

        # The following code acts as a switch statements for OpCodes
        self.opmaps = {}

        # Stack Manipulation
        self.opmaps[OpCode.NOP] = Executor.execute_NOP
        self.opmaps[OpCode.PUSH] = Executor.execute_PUSH
        self.opmaps[OpCode.POP] = Executor.execute_POP
        self.opmaps[OpCode.DUP] = Executor.execute_DUP
        self.opmaps[OpCode.SWAP] = Executor.execute_SWAP

        # Environment and objects manipulation
        self.opmaps[OpCode.LOAD] = Executor.execute_LOAD
        self.opmaps[OpCode.STORE] = Executor.execute_STORE
        self.opmaps[OpCode.DCL] = Executor.execute_DCL
        self.opmaps[OpCode.LOAD_MEMBER] = Executor.execute_LOAD_MEMBER
        self.opmaps[OpCode.STORE_MEMBER] = Executor.execute_STORE_MEMBER
        self.opmaps[OpCode.LOAD_INDEX] = Executor.execute_LOAD_INDEX
        self.opmaps[OpCode.STORE_INDEX] = Executor.execute_STORE_INDEX

        # Control
        self.opmaps[OpCode.JMP] = Executor.execute_JMP
        self.opmaps[OpCode.IFJMP] = Executor.execute_IFJMP
        self.opmaps[OpCode.UNLESSJMP] = Executor.execute_UNLESSJMP
        self.opmaps[OpCode.CALL] = Executor.execute_CALL
        self.opmaps[OpCode.NEW] = Executor.execute_NEW
        self.opmaps[OpCode.RET] = Executor.execute_RET
        self.opmaps[OpCode.SWITCH] = Executor.execute_SWITCH

        # Exceptions
        self.opmaps[OpCode.TRY_PUSH] = Executor.execute_TRY_PUSH
        self.opmaps[OpCode.TRY_POP] = Executor.execute_TRY_POP
        self.opmaps[OpCode.THROW] = Executor.execute_THROW

        # Array and Objects creation
        self.opmaps[OpCode.MAKE_ARRAY] = Executor.execute_MAKE_ARRAY
        self.opmaps[OpCode.MAKE_OBJECT] = Executor.execute_MAKE_OBJECT
        self.opmaps[OpCode.MAKE_FUNC] = Executor.execute_MAKE_FUNC
        self.opmaps[OpCode.MAKE_GETTER] = Executor.execute_MAKE_GETTER
        self.opmaps[OpCode.MAKE_SETTER] = Executor.execute_MAKE_SETTER

        # Binary arithmetic operation
        self.opmaps[OpCode.ADD] = Executor.execute_ADD
        self.opmaps[OpCode.MUL] = Executor.execute_MUL
        self.opmaps[OpCode.SUB] = Executor.execute_SUB
        self.opmaps[OpCode.DIV] = Executor.execute_DIV
        self.opmaps[OpCode.MOD] = Executor.execute_MOD
        self.opmaps[OpCode.LEFT_SHIFT] = Executor.execute_LEFT_SHIFT
        self.opmaps[OpCode.RIGHT_SHIFT] = Executor.execute_RIGHT_SHIFT
        self.opmaps[
            OpCode.
            UNSIGNED_RIGHT_SHIFT] = Executor.execute_UNSIGNED_RIGHT_SHIFT

        # Binary bolean operation
        self.opmaps[OpCode.SUPPERIOR] = Executor.execute_SUPPERIOR
        self.opmaps[OpCode.SUPPERIOR_EQUAL] = Executor.execute_SUPPERIOR_EQUAL
        self.opmaps[OpCode.INFERIOR] = Executor.execute_INFERIOR
        self.opmaps[OpCode.INFERIOR_EQUAL] = Executor.execute_INFERIOR_EQUAL
        self.opmaps[OpCode.EQUAL] = Executor.execute_EQUAL
        self.opmaps[OpCode.DIFFERENT] = Executor.execute_DIFFERENT
        self.opmaps[OpCode.AND] = Executor.execute_AND
        self.opmaps[OpCode.OR] = Executor.execute_OR

        # Unary operations
        self.opmaps[OpCode.NEG] = Executor.execute_NEG
        self.opmaps[OpCode.TILDE] = Executor.execute_TILDE
        self.opmaps[OpCode.NOT] = Executor.execute_NOT
예제 #24
0
 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())
예제 #25
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)
예제 #26
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() == ','
        ]