def visit_while_statement(self, obj: WhileStatement):
     obj.condition.accept(self)
     condition_label = Label.get_next_enumerated_label()
     exit_label = Label.get_next_enumerated_label()
     condition = self.main_subtree.to_conditional(JumpTypeEnum.NEQ, exit_label)
     condition_part = Seq(LabelStm(condition_label, obj.position),
                          condition, obj.position)
     obj.action.accept(self)
     body_part = Seq(
         self.main_subtree.to_stm(),
         Jump(condition_label, obj.position),
         obj.position
     )
     self.main_subtree = StmWrapper(
         Seq(
             Seq(
                 condition_part,
                 body_part,
                 obj.position
             ),
             LabelStm(
                 exit_label,
                 obj.position
             ),
             obj.position
         )
     )
    def visit_method_decl(self, obj: MethodDecl):
        method_info = self.table.get_method(obj.id.name, obj.position)
        switcher = MethodScopeSwitcher(
            method_info,
            None,
            self.table,
            obj.position
        )
        self.current_frame = method_info.get_frame()
        stm = None
        if len(obj.statement_list) > 0:
            statements = []
            for statement in obj.statement_list:
                statement.accept(self)
                statements.append(self.main_subtree.to_stm())
            assert len(statements) > 0
            if len(statements) == 1:
                self.main_subtree = StmWrapper(statements[0])
            else:
                seq = Seq(statements[0], statements[1], obj.position)
                for i in range(2, len(statements), 1):
                    seq = Seq(seq, statements[i], obj.position)
                self.main_subtree = StmWrapper(seq)
            stm = StmList(self.main_subtree.to_stm(), None, obj.position)

        obj.return_statement.accept(self)
        if stm is not None:
            stm = StmList(stm, self.main_subtree.to_stm(), obj.position)
        else:
            stm = self.main_subtree.to_stm()
        name = method_info.get_full_name()
        self.trees[name] = StmWrapper(stm)
        switcher.destroy()
 def visit_return_statement(self, obj: ReturnStatement):
     obj.expression.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     return_address = self.current_frame.return_address.get_exp(
         Temp(fp_name, None, None, obj.position),
         obj.position
     )
     self.main_subtree = StmWrapper(Move(return_address, self.main_subtree.to_exp(), obj.position))
 def visit_statements(self, obj: Statements):
     statements = []
     for statement in obj.statement_list:
         statement.accept(self)
         statements.append(self.main_subtree.to_stm())
     assert len(statements) > 0
     if len(statements) == 1:
         self.main_subtree = StmWrapper(statements[0])
     else:
         seq = Seq(statements[0], statements[1], obj.position)
         for i in range(2, len(statements), 1):
             seq = Seq(seq, statements[i], obj.position)
         self.main_subtree = StmWrapper(seq)
 def visit_id(self, obj: Id):
     var_access: IAccess = self.current_frame.find_local_or_formal(obj.name)
     if var_access is not None:
         var_exp = var_access.get_exp(
             Temp(
                 fp_name,
                 None, None,
                 obj.position
             ),
             obj.position
         )
     else:
         assert self.table.get_scoped_class() is not None
         var_exp = self.table.get_scoped_class().class_struct.get_field_from(
             obj.name,
             self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                 Temp(
                     fp_name,
                     None, None,
                     obj.position
                 ),
                 obj.position
             ),
             obj.position
         )
     self.type_stack_visitor.visit(obj)
     self.main_subtree = ExpWrapper(var_exp)
 def visit_random_access_expr(self, obj: RandomAccessExpr):
     obj.object.accept(self)
     array_base = self.main_subtree.to_exp()
     obj.position_in_arr.accept(self)
     element_number = self.main_subtree.to_exp()
     self.main_subtree = ExpWrapper(array_struct.get_element(array_base, element_number, obj.position))
     self.type_stack_visitor.visit(obj)
 def visit_assign_statement(self, obj: AssignStatement):
     obj.right.accept(self)
     access = self.current_frame.find_local_or_formal(obj.left.name)
     if access is not None:
         base_address = access.get_exp(
             Temp(fp_name, None, None, obj.position),
             obj.position
         )
     else:
         base_address = self.table.get_scoped_class().class_struct.get_field_from(
             obj.left.name,
             self.current_frame.find_local_or_formal(
                 THIS_NAME,
             ).get_exp(Temp(fp_name, None, None, obj.position), obj.position),
             obj.position
         )
     self.main_subtree = StmWrapper(Move(base_address, self.main_subtree.to_exp(), obj.position))
 def visit_random_access_assign_statement(self, obj: RandomAccessAssignStatement):
     obj.position_in_arr.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     position_in_arr_expr = self.main_subtree
     self.main_subtree = None
     obj.expr.accept(self)
     access = self.current_frame.find_local_or_formal(obj.id.name)
     if access is not None:
         base_address = access.get_exp(
             Temp(
                 fp_name, None, None,
                 obj.position
             ),
             obj.position
         )
     else:
         base_address = self.table.get_scoped_class().class_struct.get_field_from(
             obj.id.name,
             self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                 Temp(fp_name, None, None, obj.position),
                 obj.position
             ),
             obj.position
         )
     address = Mem(
         Binop(
             BinopEnum.PLUS,
             base_address,
             Binop(
                 BinopEnum.MUL,
                 Const(
                     self.current_frame.type_size(self.current_frame.word_type().type_enum),
                     obj.position
                 ),
                 position_in_arr_expr.to_exp(),
                 obj.position
             ),
             obj.position
         ),
         obj.position
     )
     self.main_subtree = StmWrapper(Move(address, self.main_subtree.to_exp(), obj.position))
 def visit_this_expr(self, obj: ThisExpr):
     self.main_subtree = ExpWrapper(
         Mem(
             self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                 Temp(fp_name, None, None, obj.position),
                 obj.position
             ),
             obj.position
         )
     )
     self.type_stack_visitor.visit(obj)
 def visit_print_line_statement(self, obj: PrintLineStatement):
     obj.obj.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     self.main_subtree = ExpWrapper(
         Call(
             Name(
                 println_name,
                 obj.position
             ),
             ExpList(self.main_subtree.to_exp(), None, obj.position),
             obj.position
         )
     )
 def visit_if_statement(self, obj: IfStatement):
     obj.condition.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     else_branch_label = Label.get_next_enumerated_label()
     exit_label = Label.get_next_enumerated_label()
     condition = self.main_subtree.to_conditional(JumpTypeEnum.NEQ, else_branch_label)
     obj.if_true.accept(self)
     if_part = Seq(
         self.main_subtree.to_stm(),
         Jump(exit_label, obj.position),
         obj.position
     )
     obj.if_false.accept(self)
     else_part = Seq(
         Seq(
             LabelStm(else_branch_label, obj.position),
             self.main_subtree.to_stm(),
             obj.position
         ),
         Jump(exit_label, obj.position),
         obj.position
     )
     self.main_subtree = StmWrapper(
         Seq(
             Seq(
                 condition,
                 Seq(
                     if_part,
                     else_part,
                     obj.position
                 ),
                 obj.position
             ),
             LabelStm(exit_label, obj.position),
             obj.position
         )
     )
 def visit_new_int_array_expr(self, obj: NewIntArrExpr):
     obj.size.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     number_of_elements = self.main_subtree.to_exp()
     args = ExpList(
         Binop(
             BinopEnum.MUL,
             number_of_elements,
             Const(
                 self.current_frame.type_size(TypeEnum.INT),
                 obj.position
             ),
             obj.position
         )
     )
     self.main_subtree = ExpWrapper(Call(Name(MALLOC_NAME, obj.position), args, obj.position))
     self.type_stack_visitor.visit(obj)
    def visit_call_method_expr(self, obj: CallMethodExpr):
        obj.expr.accept(self)
        base_address = Temp(None, 0, None, obj.position)
        base_exp = Eseq(
            Move(
                base_address,
                self.main_subtree.to_exp(),
                obj.position
            ),
            Mem(
                Temp(
                    None, None, base_address, obj.position
                ),
                obj.position
            )
        )
        info: TypeInfo = self.type_stack_visitor.get_type_from_stack()
        assert info is not None
        assert info.type_enum == TypeEnum.USER_CLASS
        type_switcher = TypeScopeSwitcher(info, None, self.table, obj.position)
        arguments = ExpList(base_exp, None, obj.position)
        for expr in obj.expr_list:
            expr.accept(self)
            arguments = ExpList(
                self.main_subtree.to_exp(),
                arguments,
                obj.position
            )
            self.type_stack_visitor.pop_type_from_stack()

        class_info = self.table.get_class(info.user_class_name)
        method_address = class_info.class_struct.get_virtual_method_address(
            obj.id.name,
            Temp(None, None, base_address),
            obj.position,
        )
        self.main_subtree = ExpWrapper(Call(method_address, arguments, obj.position))
        self.type_stack_visitor.visit(obj)
        type_switcher.destroy()
 def canonize(self, wrapper: ISubtreeWrapper):
     self.last_eseq = Eseq(None, None)
     wrapper.accept(self)
     stm_wrapper = StmWrapper(self.last_eseq.statement)
     self.last_eseq.statement = None
     return stm_wrapper
Exemple #15
0
 def visit_stm_wrapper(self, obj: StmWrapper):
     stm = obj.to_stm()
     stm.accept(self)
    def visit_binary_expr(self, obj: BinaryExpr):
        obj.left.accept(self)
        left = self.main_subtree.to_exp()
        self.type_stack_visitor.pop_type_from_stack()
        obj.right.accept(self)
        right = self.main_subtree.to_exp()
        self.type_stack_visitor.pop_type_from_stack()
        if obj.binary_enum == BinaryEnum.MINUS:
            result = Binop(BinopEnum.MINUS, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.MULT:
            result = Binop(BinopEnum.MUL, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.PLUS:
            result = Binop(BinopEnum.PLUS, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.MOD:
            result = Binop(BinopEnum.MOD, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.LESS:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            condition = JumpC(JumpTypeEnum.LT, left, right, true_label, obj.position)
            exp_value = Temp('exp_value', None, None, obj.position)
            true_branch = Seq(
                Seq(
                    LabelStm(
                        true_label,
                        obj.position
                    ),
                    Move(
                        exp_value,
                        Const(
                            1,
                            obj.position
                        ),
                        obj.position
                    ),
                    obj.position
                ),
                Jump(
                    return_label,
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                Seq(
                    LabelStm(
                        false_label,
                        obj.position
                    ),
                    Move(
                        Temp(None, None, exp_value),
                        Const(
                            0,
                            obj.position
                        ),
                        obj.position
                    ),
                    obj.position
                ),
                Jump(
                    return_label,
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            false_branch,
                            obj.position
                        ),
                        true_branch,
                        obj.position
                    ),
                    LabelStm(
                        return_label,
                        obj.position
                    ),
                    obj.position
                ),
                Mem(
                    Temp(None, None, exp_value),
                    obj.position
                ),
                obj.position
            )
        elif obj.binary_enum == BinaryEnum.AND:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            exp_value = Temp('exp_value', None, None, obj.position)
            condition = JumpC(JumpTypeEnum.NEQ, left, Const(1, obj.position), false_label, obj.position)
            true_branch = Seq(
                JumpC(JumpTypeEnum.NEQ, right, Const(1, obj.position), false_label, obj.position),
                Seq(
                    Move(exp_value, Const(1, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                LabelStm(false_label, obj.position),
                Seq(
                    Move(Temp(None, None, exp_value), Const(0, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            true_branch,
                            obj.position
                        ),
                        false_branch,
                        obj.position
                    ),
                    LabelStm(return_label, obj.position),
                    obj.position
                ),
                Mem(Temp(None, None, exp_value), obj.position),
                obj.position
            )
        elif obj.binary_enum == BinaryEnum.OR:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            exp_value = Temp('exp_value', None, None, obj.position)
            condition = JumpC(JumpTypeEnum.EQ, left, Const(1, obj.position), true_label, obj.position)
            true_branch = Seq(
                JumpC(JumpTypeEnum.NEQ, right, Const(1, obj.position), false_label, obj.position),
                Seq(
                    LabelStm(true_label, obj.position),
                    Seq(
                        Move(exp_value, Const(1, obj.position), obj.position),
                        Jump(return_label, obj.position),
                        obj.position
                    ),
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                LabelStm(false_label, obj.position),
                Seq(
                    Move(Temp(None, None, exp_value), Const(0, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            true_branch,
                            obj.position
                        ),
                        false_branch,
                        obj.position
                    ),
                    LabelStm(return_label, obj.position),
                    obj.position
                ),
                Mem(Temp(None, None, exp_value), obj.position),
                obj.position
            )
        else:
            raise Exception('Hello there! - General Kenobi!')

        self.main_subtree = ExpWrapper(result)
        self.type_stack_visitor.visit(obj)
class IRBuilder(Visitor):
    def __init__(self, table: Table):
        Visitor.__init__(self)
        self.table = table
        self.main_subtree = None
        self.trees = dict()
        self.current_frame: IFrame = None
        self.type_stack_visitor = TypeStackVisitor(table)

    def parse(self, program: Program):
        program.accept(self)

    def get_parse_result(self):
        return self.trees

    def visit(self, obj: Visitable):
        if isinstance(obj, BinaryExpr):
            self.visit_binary_expr(obj)
        elif isinstance(obj, Id):
            self.visit_id(obj)
        elif isinstance(obj, ClassDecl):
            self.visit_class_decl(obj)
        elif isinstance(obj, MainClass):
            self.visit_main_class(obj)
        elif isinstance(obj, MethodDecl):
            self.visit_method_decl(obj)
        elif isinstance(obj, Program):
            self.visit_program(obj)
        elif isinstance(obj, ValueExpr):
            self.visit_value_expr(obj)
        elif isinstance(obj, AssignStatement):
            self.visit_assign_statement(obj)
        elif isinstance(obj, IfStatement):
            self.visit_if_statement(obj)
        elif isinstance(obj, NotExpr):
            self.visit_not_expr(obj)
        elif isinstance(obj, CallMethodExpr):
            self.visit_call_method_expr(obj)
        elif isinstance(obj, NewIntArrExpr):
            self.visit_new_int_array_expr(obj)
        elif isinstance(obj, NewObjectExpr):
            self.visit_new_object_expr(obj)
        elif isinstance(obj, RandomAccessAssignStatement):
            self.visit_random_access_assign_statement(obj)
        elif isinstance(obj, LengthExpr):
            self.visit_length_expr(obj)
        elif isinstance(obj, PrintLineStatement):
            self.visit_print_line_statement(obj)
        elif isinstance(obj, WhileStatement):
            self.visit_while_statement(obj)
        elif isinstance(obj, Statements):
            self.visit_statements(obj)
        elif isinstance(obj, RandomAccessExpr):
            self.visit_random_access_expr(obj)
        elif isinstance(obj, ThisExpr):
            self.visit_this_expr(obj)
        elif isinstance(obj, ReturnStatement):
            self.visit_return_statement(obj)

    def visit_program(self, obj: Program):
        obj.main.accept(self)
        for class_decl in obj.class_decl_list:
            class_decl.accept(self)

    def visit_main_class(self, obj: MainClass):
        for statement in obj.statement_list:
            statement.accept(self)
        assert self.main_subtree is not None
        self.trees[obj.id.name + '@MAIN'] = self.main_subtree
        self.main_subtree = None

    def visit_class_decl(self, obj: ClassDecl):
        switcher = TypeScopeSwitcher(
            self.table.get_class(obj.id.name).type_info,
            None,
            self.table,
            obj.position
        )
        for method_decl in obj.method_decl_list:
            method_decl.accept(self)
        switcher.destroy()

    def visit_method_decl(self, obj: MethodDecl):
        method_info = self.table.get_method(obj.id.name, obj.position)
        switcher = MethodScopeSwitcher(
            method_info,
            None,
            self.table,
            obj.position
        )
        self.current_frame = method_info.get_frame()
        stm = None
        if len(obj.statement_list) > 0:
            statements = []
            for statement in obj.statement_list:
                statement.accept(self)
                statements.append(self.main_subtree.to_stm())
            assert len(statements) > 0
            if len(statements) == 1:
                self.main_subtree = StmWrapper(statements[0])
            else:
                seq = Seq(statements[0], statements[1], obj.position)
                for i in range(2, len(statements), 1):
                    seq = Seq(seq, statements[i], obj.position)
                self.main_subtree = StmWrapper(seq)
            stm = StmList(self.main_subtree.to_stm(), None, obj.position)

        obj.return_statement.accept(self)
        if stm is not None:
            stm = StmList(stm, self.main_subtree.to_stm(), obj.position)
        else:
            stm = self.main_subtree.to_stm()
        name = method_info.get_full_name()
        self.trees[name] = StmWrapper(stm)
        switcher.destroy()

    def visit_binary_expr(self, obj: BinaryExpr):
        obj.left.accept(self)
        left = self.main_subtree.to_exp()
        self.type_stack_visitor.pop_type_from_stack()
        obj.right.accept(self)
        right = self.main_subtree.to_exp()
        self.type_stack_visitor.pop_type_from_stack()
        if obj.binary_enum == BinaryEnum.MINUS:
            result = Binop(BinopEnum.MINUS, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.MULT:
            result = Binop(BinopEnum.MUL, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.PLUS:
            result = Binop(BinopEnum.PLUS, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.MOD:
            result = Binop(BinopEnum.MOD, left, right, obj.position)
        elif obj.binary_enum == BinaryEnum.LESS:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            condition = JumpC(JumpTypeEnum.LT, left, right, true_label, obj.position)
            exp_value = Temp('exp_value', None, None, obj.position)
            true_branch = Seq(
                Seq(
                    LabelStm(
                        true_label,
                        obj.position
                    ),
                    Move(
                        exp_value,
                        Const(
                            1,
                            obj.position
                        ),
                        obj.position
                    ),
                    obj.position
                ),
                Jump(
                    return_label,
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                Seq(
                    LabelStm(
                        false_label,
                        obj.position
                    ),
                    Move(
                        Temp(None, None, exp_value),
                        Const(
                            0,
                            obj.position
                        ),
                        obj.position
                    ),
                    obj.position
                ),
                Jump(
                    return_label,
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            false_branch,
                            obj.position
                        ),
                        true_branch,
                        obj.position
                    ),
                    LabelStm(
                        return_label,
                        obj.position
                    ),
                    obj.position
                ),
                Mem(
                    Temp(None, None, exp_value),
                    obj.position
                ),
                obj.position
            )
        elif obj.binary_enum == BinaryEnum.AND:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            exp_value = Temp('exp_value', None, None, obj.position)
            condition = JumpC(JumpTypeEnum.NEQ, left, Const(1, obj.position), false_label, obj.position)
            true_branch = Seq(
                JumpC(JumpTypeEnum.NEQ, right, Const(1, obj.position), false_label, obj.position),
                Seq(
                    Move(exp_value, Const(1, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                LabelStm(false_label, obj.position),
                Seq(
                    Move(Temp(None, None, exp_value), Const(0, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            true_branch,
                            obj.position
                        ),
                        false_branch,
                        obj.position
                    ),
                    LabelStm(return_label, obj.position),
                    obj.position
                ),
                Mem(Temp(None, None, exp_value), obj.position),
                obj.position
            )
        elif obj.binary_enum == BinaryEnum.OR:
            true_label = Label.get_next_enumerated_label()
            false_label = Label.get_next_enumerated_label()
            return_label = Label.get_next_enumerated_label()
            exp_value = Temp('exp_value', None, None, obj.position)
            condition = JumpC(JumpTypeEnum.EQ, left, Const(1, obj.position), true_label, obj.position)
            true_branch = Seq(
                JumpC(JumpTypeEnum.NEQ, right, Const(1, obj.position), false_label, obj.position),
                Seq(
                    LabelStm(true_label, obj.position),
                    Seq(
                        Move(exp_value, Const(1, obj.position), obj.position),
                        Jump(return_label, obj.position),
                        obj.position
                    ),
                    obj.position
                ),
                obj.position
            )
            false_branch = Seq(
                LabelStm(false_label, obj.position),
                Seq(
                    Move(Temp(None, None, exp_value), Const(0, obj.position), obj.position),
                    Jump(return_label, obj.position),
                    obj.position
                ),
                obj.position
            )
            result = Eseq(
                Seq(
                    Seq(
                        Seq(
                            condition,
                            true_branch,
                            obj.position
                        ),
                        false_branch,
                        obj.position
                    ),
                    LabelStm(return_label, obj.position),
                    obj.position
                ),
                Mem(Temp(None, None, exp_value), obj.position),
                obj.position
            )
        else:
            raise Exception('Hello there! - General Kenobi!')

        self.main_subtree = ExpWrapper(result)
        self.type_stack_visitor.visit(obj)

    def visit_id(self, obj: Id):
        var_access: IAccess = self.current_frame.find_local_or_formal(obj.name)
        if var_access is not None:
            var_exp = var_access.get_exp(
                Temp(
                    fp_name,
                    None, None,
                    obj.position
                ),
                obj.position
            )
        else:
            assert self.table.get_scoped_class() is not None
            var_exp = self.table.get_scoped_class().class_struct.get_field_from(
                obj.name,
                self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                    Temp(
                        fp_name,
                        None, None,
                        obj.position
                    ),
                    obj.position
                ),
                obj.position
            )
        self.type_stack_visitor.visit(obj)
        self.main_subtree = ExpWrapper(var_exp)

    def visit_value_expr(self, obj: ValueExpr):
        self.main_subtree = ExpWrapper(Const(obj.value, obj.position))
        self.type_stack_visitor.visit(obj)

    def visit_assign_statement(self, obj: AssignStatement):
        obj.right.accept(self)
        access = self.current_frame.find_local_or_formal(obj.left.name)
        if access is not None:
            base_address = access.get_exp(
                Temp(fp_name, None, None, obj.position),
                obj.position
            )
        else:
            base_address = self.table.get_scoped_class().class_struct.get_field_from(
                obj.left.name,
                self.current_frame.find_local_or_formal(
                    THIS_NAME,
                ).get_exp(Temp(fp_name, None, None, obj.position), obj.position),
                obj.position
            )
        self.main_subtree = StmWrapper(Move(base_address, self.main_subtree.to_exp(), obj.position))

    def visit_not_expr(self, obj: NotExpr):
        obj.right.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        self.main_subtree = ExpWrapper(UnaryOp(UnaryOpEnum.NOT, self.main_subtree.to_exp(), obj.position))
        self.type_stack_visitor.visit(obj)

    def visit_call_method_expr(self, obj: CallMethodExpr):
        obj.expr.accept(self)
        base_address = Temp(None, 0, None, obj.position)
        base_exp = Eseq(
            Move(
                base_address,
                self.main_subtree.to_exp(),
                obj.position
            ),
            Mem(
                Temp(
                    None, None, base_address, obj.position
                ),
                obj.position
            )
        )
        info: TypeInfo = self.type_stack_visitor.get_type_from_stack()
        assert info is not None
        assert info.type_enum == TypeEnum.USER_CLASS
        type_switcher = TypeScopeSwitcher(info, None, self.table, obj.position)
        arguments = ExpList(base_exp, None, obj.position)
        for expr in obj.expr_list:
            expr.accept(self)
            arguments = ExpList(
                self.main_subtree.to_exp(),
                arguments,
                obj.position
            )
            self.type_stack_visitor.pop_type_from_stack()

        class_info = self.table.get_class(info.user_class_name)
        method_address = class_info.class_struct.get_virtual_method_address(
            obj.id.name,
            Temp(None, None, base_address),
            obj.position,
        )
        self.main_subtree = ExpWrapper(Call(method_address, arguments, obj.position))
        self.type_stack_visitor.visit(obj)
        type_switcher.destroy()

    def visit_new_int_array_expr(self, obj: NewIntArrExpr):
        obj.size.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        number_of_elements = self.main_subtree.to_exp()
        args = ExpList(
            Binop(
                BinopEnum.MUL,
                number_of_elements,
                Const(
                    self.current_frame.type_size(TypeEnum.INT),
                    obj.position
                ),
                obj.position
            )
        )
        self.main_subtree = ExpWrapper(Call(Name(MALLOC_NAME, obj.position), args, obj.position))
        self.type_stack_visitor.visit(obj)

    def visit_new_object_expr(self, obj: NewObjectExpr):
        class_info = self.table.get_class(obj.id.name)
        alloc_actions = class_info.class_struct.allocate_new(obj.position)
        self.main_subtree = ExpWrapper(alloc_actions)
        self.type_stack_visitor.visit(obj)

    def visit_random_access_assign_statement(self, obj: RandomAccessAssignStatement):
        obj.position_in_arr.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        position_in_arr_expr = self.main_subtree
        self.main_subtree = None
        obj.expr.accept(self)
        access = self.current_frame.find_local_or_formal(obj.id.name)
        if access is not None:
            base_address = access.get_exp(
                Temp(
                    fp_name, None, None,
                    obj.position
                ),
                obj.position
            )
        else:
            base_address = self.table.get_scoped_class().class_struct.get_field_from(
                obj.id.name,
                self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                    Temp(fp_name, None, None, obj.position),
                    obj.position
                ),
                obj.position
            )
        address = Mem(
            Binop(
                BinopEnum.PLUS,
                base_address,
                Binop(
                    BinopEnum.MUL,
                    Const(
                        self.current_frame.type_size(self.current_frame.word_type().type_enum),
                        obj.position
                    ),
                    position_in_arr_expr.to_exp(),
                    obj.position
                ),
                obj.position
            ),
            obj.position
        )
        self.main_subtree = StmWrapper(Move(address, self.main_subtree.to_exp(), obj.position))

    def visit_length_expr(self, obj: LengthExpr):
        obj.obj.accept(self)
        array_base = self.main_subtree.to_exp()
        self.main_subtree = ExpWrapper(array_struct.get_length(array_base, obj.position))
        self.type_stack_visitor.visit(obj)

    def visit_print_line_statement(self, obj: PrintLineStatement):
        obj.obj.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        self.main_subtree = ExpWrapper(
            Call(
                Name(
                    println_name,
                    obj.position
                ),
                ExpList(self.main_subtree.to_exp(), None, obj.position),
                obj.position
            )
        )

    def visit_if_statement(self, obj: IfStatement):
        obj.condition.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        else_branch_label = Label.get_next_enumerated_label()
        exit_label = Label.get_next_enumerated_label()
        condition = self.main_subtree.to_conditional(JumpTypeEnum.NEQ, else_branch_label)
        obj.if_true.accept(self)
        if_part = Seq(
            self.main_subtree.to_stm(),
            Jump(exit_label, obj.position),
            obj.position
        )
        obj.if_false.accept(self)
        else_part = Seq(
            Seq(
                LabelStm(else_branch_label, obj.position),
                self.main_subtree.to_stm(),
                obj.position
            ),
            Jump(exit_label, obj.position),
            obj.position
        )
        self.main_subtree = StmWrapper(
            Seq(
                Seq(
                    condition,
                    Seq(
                        if_part,
                        else_part,
                        obj.position
                    ),
                    obj.position
                ),
                LabelStm(exit_label, obj.position),
                obj.position
            )
        )

    def visit_while_statement(self, obj: WhileStatement):
        obj.condition.accept(self)
        condition_label = Label.get_next_enumerated_label()
        exit_label = Label.get_next_enumerated_label()
        condition = self.main_subtree.to_conditional(JumpTypeEnum.NEQ, exit_label)
        condition_part = Seq(LabelStm(condition_label, obj.position),
                             condition, obj.position)
        obj.action.accept(self)
        body_part = Seq(
            self.main_subtree.to_stm(),
            Jump(condition_label, obj.position),
            obj.position
        )
        self.main_subtree = StmWrapper(
            Seq(
                Seq(
                    condition_part,
                    body_part,
                    obj.position
                ),
                LabelStm(
                    exit_label,
                    obj.position
                ),
                obj.position
            )
        )

    def visit_statements(self, obj: Statements):
        statements = []
        for statement in obj.statement_list:
            statement.accept(self)
            statements.append(self.main_subtree.to_stm())
        assert len(statements) > 0
        if len(statements) == 1:
            self.main_subtree = StmWrapper(statements[0])
        else:
            seq = Seq(statements[0], statements[1], obj.position)
            for i in range(2, len(statements), 1):
                seq = Seq(seq, statements[i], obj.position)
            self.main_subtree = StmWrapper(seq)

    def visit_random_access_expr(self, obj: RandomAccessExpr):
        obj.object.accept(self)
        array_base = self.main_subtree.to_exp()
        obj.position_in_arr.accept(self)
        element_number = self.main_subtree.to_exp()
        self.main_subtree = ExpWrapper(array_struct.get_element(array_base, element_number, obj.position))
        self.type_stack_visitor.visit(obj)

    def visit_this_expr(self, obj: ThisExpr):
        self.main_subtree = ExpWrapper(
            Mem(
                self.current_frame.find_local_or_formal(THIS_NAME).get_exp(
                    Temp(fp_name, None, None, obj.position),
                    obj.position
                ),
                obj.position
            )
        )
        self.type_stack_visitor.visit(obj)

    def visit_return_statement(self, obj: ReturnStatement):
        obj.expression.accept(self)
        self.type_stack_visitor.pop_type_from_stack()
        return_address = self.current_frame.return_address.get_exp(
            Temp(fp_name, None, None, obj.position),
            obj.position
        )
        self.main_subtree = StmWrapper(Move(return_address, self.main_subtree.to_exp(), obj.position))
 def visit_value_expr(self, obj: ValueExpr):
     self.main_subtree = ExpWrapper(Const(obj.value, obj.position))
     self.type_stack_visitor.visit(obj)
 def visit_not_expr(self, obj: NotExpr):
     obj.right.accept(self)
     self.type_stack_visitor.pop_type_from_stack()
     self.main_subtree = ExpWrapper(UnaryOp(UnaryOpEnum.NOT, self.main_subtree.to_exp(), obj.position))
     self.type_stack_visitor.visit(obj)
 def visit_length_expr(self, obj: LengthExpr):
     obj.obj.accept(self)
     array_base = self.main_subtree.to_exp()
     self.main_subtree = ExpWrapper(array_struct.get_length(array_base, obj.position))
     self.type_stack_visitor.visit(obj)
 def visit_stm_wrapper(self, obj: StmWrapper):
     obj.to_stm().accept(self)
 def visit_new_object_expr(self, obj: NewObjectExpr):
     class_info = self.table.get_class(obj.id.name)
     alloc_actions = class_info.class_struct.allocate_new(obj.position)
     self.main_subtree = ExpWrapper(alloc_actions)
     self.type_stack_visitor.visit(obj)