Best Python code snippet using hypothesis
test_compiler.py
Source:test_compiler.py  
1import pytest2from naulang.compiler import ast3from naulang.compiler.context import FunctionCompilerContext4from naulang.compiler.compiler import SyntaxDirectedTranslator5from naulang.interpreter.space import ObjectSpace6from naulang.interpreter.bytecode import Bytecode7from naulang.interpreter.objectspace.integer import Integer8from naulang.interpreter.objectspace.float import Float9from naulang.interpreter.objectspace.boolean import Boolean10class DummyCompilationUnit(ast.Node):11    def __init__(self, code_to_emit):12        self.code_to_emit = code_to_emit13    def compile(self, context):14        context.emit([self.code_to_emit])15    def accept(self, visitor):16        visitor.visit_dummycompilationunit(self)17    def __repr__(self):18        return "DummyCompilationUnit(%r)" % self.code_to_emit19def create_interpreter_context():20    space = ObjectSpace()21    ctx = FunctionCompilerContext(space)22    return ctx23def create_syntax_directed_translator(ctx):24    def dummy_visit(self, node):25        self.context.emit([node.code_to_emit])26        return True27    # Patch the visit dummy method on to the translator28    SyntaxDirectedTranslator.visit_dummycompilationunit = dummy_visit29    return SyntaxDirectedTranslator(ctx)30def test_optimise_sequential_load_consts():31    ctx = create_interpreter_context()32    ctx.should_optimise = True33    t = create_syntax_directed_translator(ctx)34    node = ast.Block([ast.Multiply(ast.IntegerConstant(10), ast.IntegerConstant(10))])35    node.accept(t)36    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0, Bytecode.DUP, Bytecode.MUL]37def test_optimise_sequential_loads():38    ctx = create_interpreter_context()39    ctx.should_optimise = True40    t = create_syntax_directed_translator(ctx)41    a = ctx.register_local('a')42    node = ast.Block([ast.Multiply(ast.IdentifierExpression('a'), ast.IdentifierExpression('a'))])43    node.accept(t)44    assert ctx.get_bytecode() == [Bytecode.LOAD, a, Bytecode.DUP, Bytecode.MUL]45def test_compile_empty_functionexpression():46    ctx = create_interpreter_context()47    t = create_syntax_directed_translator(ctx)48    node = ast.FunctionExpression(ast.ParameterList([]), None)49    node.accept(t)50    assert ctx.inner_contexts[0].get_bytecode() == [Bytecode.HALT]51def test_return_statement_empty():52    ctx = create_interpreter_context()53    t = create_syntax_directed_translator(ctx)54    node = ast.ReturnStatement(None)55    node.accept(t)56    assert ctx.get_bytecode() == [Bytecode.HALT]57def test_return_statement():58    ctx = create_interpreter_context()59    t = create_syntax_directed_translator(ctx)60    node = ast.ReturnStatement(ast.IntegerConstant(10))61    node.accept(t)62    assert ctx.literals[0] == Integer(10)63    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0, Bytecode.RETURN]64def test_ast_integer_compile():65    ctx = create_interpreter_context()66    t = create_syntax_directed_translator(ctx)67    node = ast.IntegerConstant(100)68    node.accept(t)69    # Expect the constant to be stored in the literals area at position 0 (as this was a new context)70    assert ctx.literals[0] == Integer(100)71    # Expect the byte code to be [Bytecode.LOAD_CONST, 0]72    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0]73def test_ast_float_compile():74    ctx = create_interpreter_context()75    t = create_syntax_directed_translator(ctx)76    node = ast.FloatConstant(100.213)77    node.accept(t)78    # Expect the constant to be stored in the literals area at position 0 (as this was a new context)79    assert ctx.literals[0] == Float(100.213)80    # Expect the byte code to be [Bytecode.LOAD_CONST, 0]81    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0]82def test_ast_boolean_constant_compiler():83    ctx = create_interpreter_context()84    t = create_syntax_directed_translator(ctx)85    node = ast.BooleanConstant(True)86    node.accept(t)87    # Expect the constant to be stored in the literals area at position 0 (as this was a new context)88    assert ctx.literals[0] == Boolean(True)89    # Expect the byte code to be [Bytecode.LOAD_CONST, 0]90    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0]91def test_ast_assignment_compiler():92    ctx = create_interpreter_context()93    t = create_syntax_directed_translator(ctx)94    node = ast.ScopedAssignment('a', ast.BooleanConstant(True))95    node.accept(t)96    # Expect the constant to be stored in the literals area at position 097    assert ctx.literals[0] == Boolean(True)98    # Expect the bytecode to be [Bytecode.LOAD_CONST, 0, Bytecode.STORE, 0]99    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0, Bytecode.STORE, 0]100def test_ast_or_compiler():101    ctx = create_interpreter_context()102    t = create_syntax_directed_translator(ctx)103    node = ast.Or(DummyCompilationUnit(91), DummyCompilationUnit(90))104    node.accept(t)105    # Expect bytecode: [91, 90, Bytecode.OR]106    assert ctx.get_bytecode() == [91, 90, Bytecode.OR]107def test_ast_and_compiler():108    ctx = create_interpreter_context()109    t = create_syntax_directed_translator(ctx)110    node = ast.And(DummyCompilationUnit(91), DummyCompilationUnit(90))111    node.accept(t)112    assert ctx.get_bytecode() == [91, 90, Bytecode.AND]113def test_ast_equals_compiler():114    ctx = create_interpreter_context()115    t = create_syntax_directed_translator(ctx)116    node = ast.Equals(DummyCompilationUnit(91), DummyCompilationUnit(90))117    node.accept(t)118    assert ctx.get_bytecode() == [91, 90, Bytecode.EQUAL]119def test_ast_not_equals_compiler():120    ctx = create_interpreter_context()121    t = create_syntax_directed_translator(ctx)122    node = ast.NotEquals(DummyCompilationUnit(91), DummyCompilationUnit(90))123    node.accept(t)124    assert ctx.get_bytecode() == [91, 90, Bytecode.NOT_EQUAL]125def test_ast_lessthan_compiler():126    ctx = create_interpreter_context()127    t = create_syntax_directed_translator(ctx)128    node = ast.LessThan(DummyCompilationUnit(91), DummyCompilationUnit(90))129    node.accept(t)130    assert ctx.get_bytecode() == [91, 90, Bytecode.LESS_THAN]131def test_ast_lessthanorequal_compiler():132    ctx = create_interpreter_context()133    t = create_syntax_directed_translator(ctx)134    node = ast.LessThanOrEqual(DummyCompilationUnit(91), DummyCompilationUnit(90))135    node.accept(t)136    assert ctx.get_bytecode() == [91, 90, Bytecode.LESS_THAN_EQ]137def test_ast_greaterthanorequal_compiler():138    ctx = create_interpreter_context()139    t = create_syntax_directed_translator(ctx)140    node = ast.GreaterThanOrEqual(DummyCompilationUnit(91), DummyCompilationUnit(90))141    node.accept(t)142    assert ctx.get_bytecode() == [91, 90, Bytecode.GREATER_THAN_EQ]143def test_ast_greaterthan_compiler():144    ctx = create_interpreter_context()145    t = create_syntax_directed_translator(ctx)146    node = ast.GreaterThan(DummyCompilationUnit(91), DummyCompilationUnit(90))147    node.accept(t)148    assert ctx.get_bytecode() == [91, 90, Bytecode.GREATER_THAN]149def test_ast_addop_compiler():150    ctx = create_interpreter_context()151    t = create_syntax_directed_translator(ctx)152    node = ast.Add(DummyCompilationUnit(91), DummyCompilationUnit(90))153    node.accept(t)154    assert ctx.get_bytecode() == [90, 91, Bytecode.ADD]155def test_ast_subtractop_compiler():156    ctx = create_interpreter_context()157    t = create_syntax_directed_translator(ctx)158    node = ast.Subtract(DummyCompilationUnit(91), DummyCompilationUnit(90))159    node.accept(t)160    assert ctx.get_bytecode() == [90, 91, Bytecode.SUB]161def test_ast_mulop_compiler():162    ctx = create_interpreter_context()163    t = create_syntax_directed_translator(ctx)164    node = ast.Multiply(DummyCompilationUnit(91), DummyCompilationUnit(90))165    node.accept(t)166    assert ctx.get_bytecode() == [90, 91, Bytecode.MUL]167def test_ast_divop_compiler():168    ctx = create_interpreter_context()169    t = create_syntax_directed_translator(ctx)170    node = ast.Divide(DummyCompilationUnit(91), DummyCompilationUnit(90))171    node.accept(t)172    assert ctx.get_bytecode() == [90, 91, Bytecode.DIV]173def test_ast_unarynot_compiler():174    ctx = create_interpreter_context()175    t = create_syntax_directed_translator(ctx)176    node = ast.UnaryNot(DummyCompilationUnit(90))177    node.accept(t)178    assert ctx.get_bytecode() == [90, Bytecode.NOT]179def test_ast_unarynegate_compiler():180    ctx = create_interpreter_context()181    t = create_syntax_directed_translator(ctx)182    node = ast.UnaryNegate(DummyCompilationUnit(90))183    node.accept(t)184    assert ctx.get_bytecode() == [90, Bytecode.NEG]185def test_ast_whilestatement_compiler():186    ctx = create_interpreter_context()187    t = create_syntax_directed_translator(ctx)188    # Add padding to bytecodes to test non-zero based context (this is more realistic)189    ctx.emit([100])190    node = ast.WhileStatement(DummyCompilationUnit(90), ast.Block([DummyCompilationUnit(91)]))191    node.accept(t)192    assert ctx.get_bytecode() == [100, 90, Bytecode.JUMP_IF_FALSE, 7, 91, Bytecode.JUMP, 1]193def test_ast_ifstatement_compiler():194    ctx = create_interpreter_context()195    t = create_syntax_directed_translator(ctx)196    # Add padding to bytecodes to test non-zero based context (this is more realistic)197    ctx.emit([100])198    node = ast.IfStatement(DummyCompilationUnit(90), ast.Block([DummyCompilationUnit(91)]))199    node.accept(t)200    assert ctx.get_bytecode() == [100, 90, Bytecode.JUMP_IF_FALSE, 5, 91]201def test_ast_printstatement():202    ctx = create_interpreter_context()203    t = create_syntax_directed_translator(ctx)204    node = ast.PrintStatement(DummyCompilationUnit(90))205    node.accept(t)206    assert ctx.get_bytecode() == [90, Bytecode.PRINT]207@pytest.mark.xfail208def test_ast_functionstatement():209    ctx = create_interpreter_context()210    t = create_syntax_directed_translator(ctx)211    node = ast.FunctionStatement('a', ast.ParameterList(['a']), ast.Block([DummyCompilationUnit(90)]))212    node.accept(t)213    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0]214    assert len(ctx.inner_contexts) == 1215    assert ctx.inner_contexts[0].get_bytecode() == [90, Bytecode.HALT]216    assert ctx.inner_contexts[0].has_local('a')217    assert ctx.inner_contexts[0].get_parameter_count() == 1218def test_ast_functionexpression():219    ctx = create_interpreter_context()220    t = create_syntax_directed_translator(ctx)221    node = ast.FunctionExpression(ast.ParameterList(['a']),222                                  ast.Block([ast.ReturnStatement(ast.IdentifierExpression('a'))]))223    node.accept(t)224    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0]225    assert len(ctx.inner_contexts) == 1226    assert ctx.inner_contexts[0].get_bytecode() == [Bytecode.LOAD, 0, Bytecode.RETURN, Bytecode.HALT]227    assert ctx.inner_contexts[0].has_local('a')228    assert ctx.inner_contexts[0].get_parameter_count() == 1229def test_ast_functioncall():230    ctx = create_interpreter_context()231    t = create_syntax_directed_translator(ctx)232    function_local = ctx.register_local('a')233    node = ast.FunctionCall(ast.IdentifierExpression('a'), ast.ArgumentList(234        [DummyCompilationUnit(90), DummyCompilationUnit(91)]))235    node.accept(t)236    assert ctx.get_bytecode() == [90, 91, Bytecode.LOAD, function_local, Bytecode.INVOKE]237def test_ast_asyncfunctioncall():238    ctx = create_interpreter_context()239    t = create_syntax_directed_translator(ctx)240    function_local = ctx.register_local('a')241    node = ast.AsyncFunctionCall(ast.IdentifierExpression('a'), ast.ArgumentList(242        [DummyCompilationUnit(90), DummyCompilationUnit(91)]))243    node.accept(t)244    assert ctx.get_bytecode() == [90, 91, Bytecode.LOAD, function_local, Bytecode.INVOKE_ASYNC]245def test_ast_returnstatement():246    ctx = create_interpreter_context()247    t = create_syntax_directed_translator(ctx)248    node = ast.ReturnStatement(DummyCompilationUnit(90))249    node.accept(t)250    assert ctx.get_bytecode() == [90, Bytecode.RETURN]251def test_array_access():252    ctx = create_interpreter_context()253    t = create_syntax_directed_translator(ctx)254    node = ast.ArrayAccess(DummyCompilationUnit(90), DummyCompilationUnit(91))255    node.accept(t)256    assert ctx.get_bytecode() == [90, 91, Bytecode.ARRAY_LOAD]257def test_array_access_assignment():258    ctx = create_interpreter_context()259    t = create_syntax_directed_translator(ctx)260    node = ast.ArrayAssignment(261        ast.ArrayAccess(262            DummyCompilationUnit(90),263            DummyCompilationUnit(91)),264        DummyCompilationUnit(93))265    node.accept(t)266    assert ctx.get_bytecode() == [90, 91, 93, Bytecode.ARRAY_STORE]267def test_invoke_global_list():268    ctx = create_interpreter_context()269    t = create_syntax_directed_translator(ctx)270    node = ast.FunctionCall(ast.IdentifierExpression('list'), ast.ArgumentList([ast.IntegerConstant(10)]))271    node.accept(t)272    assert ctx.get_bytecode() == [Bytecode.LOAD_CONST, 0, Bytecode.INVOKE_GLOBAL, 0]273def test_break_statement():274    ctx = create_interpreter_context()275    t = create_syntax_directed_translator(ctx)276    node = ast.WhileStatement(DummyCompilationUnit(90), ast.Block([ast.BreakStatement()]))277    node.accept(t)278    assert ctx.get_bytecode() == [279        90,280        Bytecode.JUMP_IF_FALSE, 7,281        Bytecode.JUMP, 7,282        Bytecode.JUMP, 0283    ]284def test_continue_statement():285    ctx = create_interpreter_context()286    t = create_syntax_directed_translator(ctx)287    node = ast.WhileStatement(DummyCompilationUnit(90), ast.Block([ast.ContinueStatement()]))288    node.accept(t)289    assert ctx.get_bytecode() == [290        90,291        Bytecode.JUMP_IF_FALSE, 7,292        Bytecode.JUMP, 0,293        Bytecode.JUMP, 0294    ]295def test_channel_out():296    ctx = create_interpreter_context()297    t = create_syntax_directed_translator(ctx)298    node = ast.ChannelOut(DummyCompilationUnit(90))299    node.accept(t)300    assert ctx.get_bytecode() == [301        90,302        Bytecode.CHAN_OUT,303    ]304def test_channel_in():305    ctx = create_interpreter_context()306    t = create_syntax_directed_translator(ctx)307    node = ast.ChannelIn(DummyCompilationUnit(90), ast.Multiply(ast.IntegerConstant(10), ast.IntegerConstant(10)))308    node.accept(t)309    assert ctx.get_bytecode() == [310        90,311        Bytecode.LOAD_CONST, 0,312        Bytecode.LOAD_CONST, 0,313        Bytecode.MUL,314        Bytecode.CHAN_IN,315    ]316def test_channel_in_out():317    ctx = create_interpreter_context()318    t = create_syntax_directed_translator(ctx)319    node = ast.Block([ast.ChannelIn(DummyCompilationUnit(90), ast.ChannelOut(DummyCompilationUnit(91)))])320    node.accept(t)321    assert ctx.get_bytecode() == [322        90,323        91,324        Bytecode.CHAN_OUT,325        Bytecode.CHAN_IN326    ]327def test_ast_scoped_assignment():328    ctx = create_interpreter_context()329    t = create_syntax_directed_translator(ctx)330    node = ast.Block([331        ast.ScopedAssignment('x', ast.IntegerConstant(10)),332        ast.FunctionExpression(333            ast.ParameterList(['a']),334            ast.Block([335                ast.Assignment('x', ast.IntegerConstant(12)),336                ast.PrintStatement(ast.IdentifierExpression('x'))337            ])338        )339    ])340    """ AST Equivalent to:341            let x = 10342            fn(a) {343               x = 12344               print x345            }346    """347    node.accept(t)348    assert ctx.literals[0] == Integer(10)349    # Outer context loads the function expression constant from literals area 0350    assert ctx.get_bytecode() == [351        Bytecode.LOAD_CONST, 0,  # Push the constant at 0 onto the stack (10)352        Bytecode.STORE, 0,       # Store the top of the stack into locals aread at 0353        Bytecode.LOAD_CONST, 1   # Push the function expression onto the top of the stack354    ]355    # Expect the constant to be stored in the literals area at position 0356    # Of the first inner method context357    inner_contexts = ctx.get_inner_contexts()358    assert len(inner_contexts) == 1359    assert inner_contexts[0].literals[0] == Integer(12)360    assert inner_contexts[0].get_bytecode() == [361        Bytecode.LOAD_CONST, 0,            # Push 12 onto the stack362        Bytecode.STORE_DYNAMIC, 0, 1,  # Store 12 into the dynamic variable x363        Bytecode.LOAD_DYNAMIC, 0, 1,  # Load dynamic variable x onto the top of the stack364        Bytecode.PRINT,                         # Call print365        Bytecode.HALT                           # All functions end in HALT366    ]367def test_ast_scoped_usage():368    ctx = create_interpreter_context()369    t = create_syntax_directed_translator(ctx)370    node = ast.Block([371        ast.ScopedAssignment('n', ast.IntegerConstant(10)),372        ast.ScopedAssignment('a', ast.FunctionExpression(373            ast.ParameterList(['x']),374            ast.Block([375                ast.PrintStatement(376                    ast.Add(377                        ast.Multiply(378                            ast.IdentifierExpression('x'),379                            ast.IntegerConstant(2)380                        ),381                        ast.IdentifierExpression('n')382                    )383                )384            ])385        )),386        ast.FunctionCall(387            ast.IdentifierExpression('a'),388            ast.ArgumentList([ast.IntegerConstant(2)])389        ),390        ast.FunctionCall(391            ast.IdentifierExpression('a'),392            ast.ArgumentList([ast.IntegerConstant(4)])393        )394    ])395    node.accept(t)396    expected = [397        Bytecode.LOAD_CONST, 0,398        Bytecode.STORE, 0,399        Bytecode.LOAD_CONST, 1,400        Bytecode.STORE, 1,401        Bytecode.LOAD_CONST, 2,402        Bytecode.LOAD, 1,403        Bytecode.INVOKE,404        Bytecode.LOAD_CONST, 3,405        Bytecode.LOAD, 1,406        Bytecode.INVOKE,407    ]408    assert ctx.get_bytecode() == expected409    inner_contexts = ctx.get_inner_contexts()410    assert inner_contexts[0].get_bytecode() == [411        Bytecode.LOAD_DYNAMIC, 0, 1,412        Bytecode.LOAD_CONST, 0,413        Bytecode.LOAD, 0,414        Bytecode.MUL,415        Bytecode.ADD,416        Bytecode.PRINT,417        Bytecode.HALT...translator.py
Source:translator.py  
1from naulang.compiler.context import FunctionCompilerContext2from naulang.compiler import ast3from naulang.compiler.error import CompilerException4from naulang.interpreter.bytecode import Bytecode5from naulang.interpreter.objectspace.primitives.builtin_definitions import builtin_functions6_builtin_functions = builtin_functions()7class SyntaxDirectedTranslator(ast.ASTVisitor):8    """ Translate an AST to a function object graph.9        This doesn't emit pure bytecode, literals and symbol tables. Instead it10        uses the AST to build a tree of Method objects using the11        FunctionCompilerContext. Each time a function expression is encountered12        in the AST, a new FunctionCompilerContext is created and a new13        translator is created and invoked on the function subtree, this means14        the tree structure of the function definitions is recursively translated15        into a tree of method objects.  Inner functions are stored as literals16        in its containing function to be referenced with LOAD_CONST bytecodes17        in the same way that all data is referenced. This allows us to use18        functions, as first class data types and gives rise to the 'lambda'19        style syntax of function composition:20            let f = fn(b, x) {21                return b(fn(y) {22                    return x + y23                })24            }25            print f(fn(x) {26                return x(10)27            }, 15)28        Output: 25  (the sum of 10 and 15 [in a somewhat contrived way])29        The translator would create 4 Method objects in this instance. One for30        the containing 'main' function.  One for the function assigned to f,31        within that function there is another that is used to pass into the32        function in 'b'.33        Another contained in the main function is the function that returns34        x(10). The structure created would look something like the following:35        [ MAIN ]36           |37           |------ fn(b,x) { ... }38           |          |39           |          |----- fn(y) { ... }40           |41           |------ fn(x) { ... }42    """43    def __init__(self, compiler_context):44        self.context = compiler_context45    def visit_booleanconstant(self, node):46        boolean = self.context.space.new_boolean(node.get_boolean_value())47        self.context.emit([Bytecode.LOAD_CONST,48                           self.context.register_literal(boolean)],49                          sourceposition=node.getsourcepos())50        return True51    def visit_integerconstant(self, node):52        integer = self.context.space.new_integer(node.get_integer_constant())53        self.context.emit([Bytecode.LOAD_CONST,54                           self.context.register_literal(integer)],55                          sourceposition=node.getsourcepos())56        return True57    def visit_floatconstant(self, node):58        float_val = self.context.space.new_float(node.get_float_constant())59        self.context.emit([Bytecode.LOAD_CONST,60                           self.context.register_literal(float_val)],61                          sourceposition=node.getsourcepos())62    def visit_stringconstant(self, node):63        string = self.context.space.new_string(node.get_string_value())64        self.context.emit([Bytecode.LOAD_CONST,65                           self.context.register_literal(string)],66                          sourceposition=node.getsourcepos())67        return True68    def visit_assignment(self, node):69        if self.context.has_local(node.get_varname()):70            local = self.context.register_local(node.get_varname())71            node.expression.accept(self)72            self.context.emit([Bytecode.STORE, local], sourceposition=node.getsourcepos())73        else:74            slot, level = self.context.register_dynamic(node.get_varname())75            if slot is FunctionCompilerContext.REGISTER_DYNAMIC_FAILED:76                raise CompilerException(77                    "'%s' has not been defined in this scope. You should use `let %s = ...` to initialise a variable" %78                    (node.get_varname(), node.get_varname()), node.getsourcepos())79            node.expression.accept(self)80            self.context.emit([Bytecode.STORE_DYNAMIC, slot, level], sourceposition=node.getsourcepos())81        return False82    def visit_or(self, node):83        node.lhs.accept(self)84        node.rhs.accept(self)85        self.context.emit([Bytecode.OR], sourceposition=node.getsourcepos())86        return False87    def visit_and(self, node):88        node.lhs.accept(self)89        node.rhs.accept(self)90        self.context.emit([Bytecode.AND], sourceposition=node.getsourcepos())91        return False92    def visit_equals(self, node):93        node.lhs.accept(self)94        node.rhs.accept(self)95        self.context.emit([Bytecode.EQUAL], sourceposition=node.getsourcepos())96        return False97    def visit_notequals(self, node):98        node.lhs.accept(self)99        node.rhs.accept(self)100        self.context.emit([Bytecode.NOT_EQUAL], sourceposition=node.getsourcepos())101        return False102    def visit_lessthan(self, node):103        node.lhs.accept(self)104        node.rhs.accept(self)105        self.context.emit([Bytecode.LESS_THAN], sourceposition=node.getsourcepos())106        return False107    def visit_lessthanorequal(self, node):108        node.lhs.accept(self)109        node.rhs.accept(self)110        self.context.emit([Bytecode.LESS_THAN_EQ], sourceposition=node.getsourcepos())111        return False112    def visit_greaterthan(self, node):113        node.lhs.accept(self)114        node.rhs.accept(self)115        self.context.emit([Bytecode.GREATER_THAN], sourceposition=node.getsourcepos())116        return False117    def visit_greaterthanorequal(self, node):118        node.lhs.accept(self)119        node.rhs.accept(self)120        self.context.emit([Bytecode.GREATER_THAN_EQ], sourceposition=node.getsourcepos())121        return False122    def visit_add(self, node):123        node.rhs.accept(self)124        node.lhs.accept(self)125        self.context.emit([Bytecode.ADD], sourceposition=node.getsourcepos())126        return False127    def visit_subtract(self, node):128        node.rhs.accept(self)129        node.lhs.accept(self)130        self.context.emit([Bytecode.SUB], sourceposition=node.getsourcepos())131        return False132    def visit_multiply(self, node):133        node.rhs.accept(self)134        node.lhs.accept(self)135        self.context.emit([Bytecode.MUL], sourceposition=node.getsourcepos())136        return False137    def visit_divide(self, node):138        node.rhs.accept(self)139        node.lhs.accept(self)140        self.context.emit([Bytecode.DIV], sourceposition=node.getsourcepos())141        return False142    def visit_mod(self, node):143        node.rhs.accept(self)144        node.lhs.accept(self)145        self.context.emit([Bytecode.MOD], sourceposition=node.getsourcepos())146        return False147    def visit_unarynot(self, node):148        node.expression.accept(self)149        self.context.emit([Bytecode.NOT], sourceposition=node.getsourcepos())150        return False151    def visit_unarynegate(self, node):152        node.expression.accept(self)153        self.context.emit([Bytecode.NEG], sourceposition=node.getsourcepos())154        return False155    def visit_breakstatement(self, node):156        loop_control = self.context.peek_loop_control()157        self.context.emit([Bytecode.JUMP, loop_control[1]], sourceposition=node.getsourcepos())158        return True159    def visit_continuestatement(self, node):160        loop_control = self.context.peek_loop_control()161        self.context.emit([Bytecode.JUMP, loop_control[0]], sourceposition=node.getsourcepos())162        return True163    def visit_whilestatement(self, node):164        # Set up the labels for this while block and push them onto the loop control stack165        label_start = self.context.add_label(166            initial_value=self.context.get_top_position() + 1167        )168        label_end = self.context.add_label()169        self.context.push_loop_control(label_start, label_end)170        # Evaluate the condition and emit control instructions171        node.condition.accept(self)172        self.context.emit([Bytecode.JUMP_IF_FALSE, label_end], sourceposition=node.getsourcepos())173        # Evaluate block174        node.block.accept(self)175        # Loop block so remove loop control labels from stack176        self.context.pop_loop_control()177        # Emit a GOTO to actually loop178        self.context.emit([Bytecode.JUMP, label_start], sourceposition=node.getsourcepos())179        # Now we know what the value of the end label should be set it.180        self.context.set_label(label_end, self.context.get_top_position() + 1)181        return False182    def visit_ifstatement(self, node):183        node.condition.accept(self)184        endlabel = self.context.add_label()185        self.context.emit([Bytecode.JUMP_IF_FALSE, endlabel], sourceposition=node.getsourcepos())186        node.ifclause.accept(self)187        self.context.set_label(endlabel, self.context.get_top_position() + 1)188        return False189    def visit_printstatement(self, node):190        node.expression.accept(self)191        self.context.emit([Bytecode.PRINT], sourceposition=node.getsourcepos())192        return False193    def visit_functionstatement(self, node):194        raise NotImplementedError()195    def visit_functionexpression(self, node):196        new_context = FunctionCompilerContext(197            self.context.space,198            outer=self.context,199            optimise=self.context.should_optimise)200        self.context.add_inner_context(new_context)201        parameters = node.get_parameterlist().get_parameter_list()202        parameter_count = len(parameters)203        for param in parameters:204            new_context.register_local(param)205        new_context.set_parameter_count(parameter_count)206        new_visitor = SyntaxDirectedTranslator(new_context)207        if node.block is not None:208            node.block.accept(new_visitor)209        new_context.emit([Bytecode.HALT])210        method = new_context.generate_method()211        self.context.emit([Bytecode.LOAD_CONST,212                           self.context.register_literal(method)],213                          sourceposition=node.getsourcepos())214        return False215    def visit_asyncfunctioncall(self, node):216        for arg in node.get_arguments().get_argument_list():217            arg.accept(self)218        if node.identifier.get_identifier() in _builtin_functions:219            raise CompilerException("Built in functions can not be called with the async modifier", node.getsourcepos())220        node.identifier.accept(self)221        self.context.emit([Bytecode.INVOKE_ASYNC], sourceposition=node.getsourcepos())222        return False223    def visit_functioncall(self, node):224        for arg in node.get_arguments().get_argument_list():225            arg.accept(self)226        if node.identifier.get_identifier() in _builtin_functions:227            function = _builtin_functions[node.identifier.get_identifier()]228            self.context.emit([Bytecode.INVOKE_GLOBAL, function[1]], sourceposition=node.getsourcepos())229        else:230            node.identifier.accept(self)231            self.context.emit([Bytecode.INVOKE], sourceposition=node.getsourcepos())232        return False233    def visit_returnstatement(self, node):234        if node.expression is not None:235            node.expression.accept(self)236            self.context.emit([Bytecode.RETURN], sourceposition=node.getsourcepos())237        else:238            self.context.emit([Bytecode.HALT])239        return False240    def visit_identifierexpression(self, node):241        if self.context.has_local(node.identifier):242            local = self.context.register_local(node.identifier)243            self.context.emit([Bytecode.LOAD, local], sourceposition=node.getsourcepos())244        else:245            slot, level = self.context.register_dynamic(node.identifier)246            if slot == FunctionCompilerContext.REGISTER_DYNAMIC_FAILED:247                raise CompilerException(248                    "'%s' has not been defined in any scope. You should use `let %s = ...` to initialise a variable" %249                    (node.identifier, node.identifier), node.getsourcepos())250            self.context.emit([Bytecode.LOAD_DYNAMIC, slot, level], sourceposition=node.getsourcepos())251        return True252    def visit_arrayaccess(self, node):253        node.identifier.accept(self)254        node.index.accept(self)255        self.context.emit([Bytecode.ARRAY_LOAD], sourceposition=node.getsourcepos())256        return False257    def visit_arrayassignment(self, node):258        assert isinstance(node, ast.ArrayAssignment)  # RPython259        node.get_array_access().get_identifier().accept(self)260        node.array_access.index.accept(self)261        node.expression.accept(self)262        self.context.emit([Bytecode.ARRAY_STORE], sourceposition=node.getsourcepos())263        return False264    def visit_scopedassignment(self, node):265        local = self.context.register_local(node.varname)266        node.expression.accept(self)267        self.context.emit([Bytecode.STORE, local], sourceposition=node.getsourcepos())268        return False269    def visit_channelout(self, node):270        node.channel.accept(self)271        self.context.emit([Bytecode.CHAN_OUT], sourceposition=node.getsourcepos())272        return False273    def visit_channelin(self, node):274        node.get_channel().accept(self)275        node.get_expression().accept(self)...context.py
Source:context.py  
1from naulang.interpreter.objectspace.method import Method2from naulang.interpreter.bytecode import Bytecode, get_stack_effect, stack_effect_depends_on_args, get_bytecode_length3from naulang.compiler.sourcemap import SourceMap4class FunctionCompilerContext(object):5    """ Context used for compiling a function """6    REGISTER_DYNAMIC_FAILED = -17    def __init__(self, object_space, outer=None, optimise=False):8        self.space = object_space9        self.literals = []10        self.locals = []11        self.parameter_count = 012        self.bytecode = []13        self.outer = outer14        # This maintains the symbol table. When an identifier is encountered15        # it is entered into this dictionary with a unique numeric identifier16        self.id_to_number = {}17        self.inner_contexts = []18        self.labels = []19        # A stack, the top contains a 2-tuple of current labels for the20        # current loop value 1 being the label for the top of the loop (pre-condition)21        # value 2 being the label for the block after the loop.22        self.loop_control = []23        self.sourcemap = SourceMap()24        self.should_optimise = optimise25        self.last_bytecode_seq = []26    def get_top_position(self):27        """ Returns:28            The position of the last operation, 0 if none29        """30        return len(self.bytecode) - 131    def add_label(self, initial_value=-1):32        """ Returns:33            A new label.34            Labels are represented by integers.35            Keyword Arguments:36            initial_value -- Set an initial value for this label, default is -1 representing an unassigned label37        """38        self.labels.append(initial_value)39        return len(self.labels) - 140    def set_label(self, label, value):41        """42            Updates the value of a label43            Arguments:44            label -- The label number to update (should be an integer)45            value -- The value to assign to this label (should be an integer)46        """47        self.labels[label] = value48    def get_label_value(self, label):49        """50            Returns the value of a label51            Arguments:52            label -- The label number to retrieve (expects an integer)53        """54        return self.labels[label]55    def push_loop_control(self, label_start, label_end):56        """57            Pushes the label representing the top of the loop and the tail of the loop to the loop control stack.58            This is useful for implementing statements such as 'break' and 'continue'59            Arguments:60            label_start -- The Label representing the start of the loop61            label_end   -- The label representing the end of the loop62        """63        self.loop_control.append((label_start, label_end))64    def peek_loop_control(self):65        """66            Returns the current loop control 2-tuple67        """68        return self.loop_control[len(self.loop_control) - 1]69    def pop_loop_control(self):70        """71            Returns the current loop control 2-tuple and removes it from the stack.72        """73        return self.loop_control.pop()74    def add_inner_context(self, context):75        """76            Add an inner function context to this context.77        """78        self.inner_contexts.append(context)79    def get_inner_contexts(self):80        """81            Get a list of inner function contexts.82        """83        return self.inner_contexts84    def get_outer_context(self):85        """86            Get the context enclosing this function context87        """88        return self.outer89    def objspace(self):90        """91            Get object space92        """93        return self.space94    def generate_method(self):95        """96            Generate a method object from this function context.97        """98        # First replace bytecode labels with actual values99        bytecode = self.get_bytecode()100        stack_depth = self._calculate_stack_depth(bytecode)101        # finalize locals and literals102        literals = [None] * len(self.literals)103        locals = [None] * len(self.locals)104        for i in range(0, len(literals)):105            literals[i] = self.literals[i]106        return Method(literals, len(locals), bytecode,107                      stack_depth, argument_count=self.parameter_count,108                      source_map=self.sourcemap)109    def _calculate_stack_depth(self, finalized_bytecode):110        max_depth = 0111        depth = 0112        i = 0113        while i < len(finalized_bytecode):114            bc = finalized_bytecode[i]115            if stack_effect_depends_on_args(bc):116                # HACK: It's difficult to find the arguments of a dynamically117                # loaded method therefore the arguments consumed by this118                # argument are assumed to be none.  Having a slightly larger119                # stack size than necessary shouldn't have a huge effect on120                # performance, although not ideal.121                # Adding one for the return value122                depth += 1123            else:124                depth += get_stack_effect(bc)125            if depth > max_depth:126                max_depth = depth127            i += get_bytecode_length(bc)128        return max_depth129    def get_bytecode(self):130        """131            Get the bytecode representation of this function context with any132            optimisations or labels applied.133        """134        return self._add_labels(self.bytecode)135    def set_outer(self, outer_context):136        """137            Set the outer context of this function context138        """139        self.outer = outer_context140    def set_parameter_count(self, value):141        """142            Set the number of arguments this function takes143        """144        self.parameter_count = value145    def get_parameter_count(self):146        """147            Get the parameter count148        """149        return self.parameter_count150    def register_dynamic(self, identifier):151        """152            Register lookup of a non local scoped variable153        """154        if self.outer is None:155            return self.REGISTER_DYNAMIC_FAILED, 0156        outer_context = self.outer157        level = 1158        while outer_context is not None:159            if outer_context.has_local(identifier):160                return outer_context.register_local(identifier), level161            outer_context = outer_context.outer162            level += 1163        return self.REGISTER_DYNAMIC_FAILED, 0164    def register_local(self, identifier):165        """ Register a local variable in this method context166        and retrieve an offset that will be used in the stack167        to retrieve this variables value. """168        if identifier in self.id_to_number:169            return self.id_to_number[identifier]170        # If we don't have a mapping for this identifier yet create one171        # and create some space in the _locals list for it172        num = len(self.locals)173        self.id_to_number[identifier] = num174        self.locals.append(None)175        return num176    def has_local(self, identifier):177        """ Get whether this function context has the identifier registered """178        if identifier in self.id_to_number:179            return True180        return False181    def register_literal(self, constant_value):182        """ Register a constant value within this function context """183        if constant_value in self.literals:184            return self.literals.index(constant_value)185        self.literals.append(constant_value)186        return len(self.literals) - 1187    def emit(self, bytecode_sequence, sourceposition=None):188        """ Emit a bytecode into this function context """189        if sourceposition is not None:190            self.sourcemap.add(len(self.bytecode), sourceposition)191        if self.should_optimise:192            try:193                # TODO put this stuff in a module194                if bytecode_sequence[0] is Bytecode.LOAD_CONST:195                    if self.last_bytecode_seq[0] is Bytecode.LOAD_CONST:196                        if bytecode_sequence[1] is self.last_bytecode_seq[1]:197                            self.bytecode.append(Bytecode.DUP)198                            return199                if bytecode_sequence[0] is Bytecode.LOAD:200                    if self.last_bytecode_seq[0] is Bytecode.LOAD:201                        if bytecode_sequence[1] is self.last_bytecode_seq[1]:202                            self.bytecode.append(Bytecode.DUP)203                            return204            except IndexError:205                pass206        for bytecode in bytecode_sequence:207            self.bytecode.append(bytecode)208        self.last_bytecode_seq = bytecode_sequence209    def _add_labels(self, bytecode):210        """211            Update the bytecode with added labels212        """213        # TODO: This is a bit of a mess: we should use the Bytecode size214        # information in Bytecode here215        bytecodes = [0] * len(bytecode)216        i = 0217        while i < len(self.bytecode):218            bytecodes[i] = self.bytecode[i]219            if bytecode[i] == Bytecode.LOAD_CONST or bytecode[i] == Bytecode.STORE or bytecode[220                    i] == Bytecode.LOAD or bytecode[i] == Bytecode.INVOKE_GLOBAL:221                i += 1222                bytecodes[i] = bytecode[i]223                i += 1224            elif bytecode[i] == Bytecode.LOAD_DYNAMIC or bytecode[i] == Bytecode.STORE_DYNAMIC:225                i += 1226                bytecodes[i] = bytecode[i]227                i += 1228                bytecodes[i] = bytecode[i]229                i += 1230            elif bytecode[i] == Bytecode.JUMP or bytecode[i] == Bytecode.JUMP_IF_FALSE:231                bytecodes[i + 1] = self.get_label_value(bytecode[i + 1])232                i += 2233            else:234                i += 1...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
