def visit(self, node: cil.DynamicCallNode):
        meth_offset = self.get_method_index(node.method)
        dest_address = self.get_address(node.dest)
        args_space = self.cil_root.get_function(
            f"{node.type or node.dtype}_{node.method}").args_space

        if node.type is None:
            obj_address = self.get_address(node.obj)
            get_type_inst = (
                mips.LWNode(
                    t0, (obj_address, fp)).with_comm("Get instance pointer"),
                mips.LWNode(t0,
                            (0, t0)).with_comm("Get type pointer at offset 0"),
            )
        else:
            get_type_inst = (mips.LANode(t0, node.type), )

        self.add_inst(
            mips.CommentNode(
                f"<dynamiccall:{node.obj}-{node.method}-{node.dest}>"),
            *get_type_inst,
            mips.LWNode(
                t0, (meth_offset, t0)).with_comm(f"Get method: {node.method}"),
            mips.JALRNode(t0).with_comm(f"Jump to {node.method}"),
            mips.SWNode(v0, dest_address, fp),
            mips.ADDINode(sp, sp, args_space).with_comm("Pop args pushed"),
            mips.CommentNode(
                f"</dynamiccall:{node.obj}-{node.method}-{node.dest}>"),
        )
    def visit(self, node: cil.ArgNode):
        address = self.get_address(node.name)

        self.add_inst(
            mips.CommentNode(f"<arg:{node.name}>"),
            mips.LWNode(t0, (address, fp)),
            mips.ADDINode(sp, sp, -4),
            mips.SWNode(t0, 0, sp),
            mips.CommentNode(f"</arg:{node.name}>"),
        )
    def visit(self, node: cil.FunctionNode):
        params = [x.name for x in node.params]
        local_vars = [x.name for x in node.local_vars]

        local_vars_size = len(local_vars) * dw

        self.cur_function = mips.FunctionNode(node.name, params, local_vars)
        self.functions[node.name] = self.cur_function

        # Push local vars
        push_instructions = (mips.push_register_instructions(ra) +
                             mips.push_register_instructions(fp) +
                             [mips.ADDINode(fp, sp, 8)] +
                             [mips.ADDINode(sp, sp, -local_vars_size)])

        self.add_inst(
            mips.CommentNode(f"<function:{node.name}>"),
            *push_instructions,
        )

        for instruction in node.instructions:
            self.visit(instruction)

        # Pop local vars
        pop_instructions = ([mips.ADDINode(sp, sp, local_vars_size)] +
                            mips.pop_register_instructions(fp) +
                            mips.pop_register_instructions(ra))

        return_instructions = ([mips.LINode(v0, 10),
                                mips.SysCallNode()] if self.cur_function.name
                               == "main" else [mips.JRNode(ra)])

        self.add_inst(
            *pop_instructions,
            *return_instructions,
            mips.CommentNode(f"</function:{node.name}>"),
        )
    def visit(self, node: cil.ComplementNode):
        src = self.get_address(node.src)
        dest = self.get_address(node.dest)

        self.add_inst(mips.CommentNode(f"</complement:{node.dest}>"), )

        self.visit(cil.StaticCallNode('Int__init', node.dest))

        self.add_inst(
            mips.LWNode(t0, (src, fp)),
            mips.LWNode(t0, (4, t0)),
            mips.NOTNode(t0, t0),
            mips.ADDINode(t0, t0, 1),
            mips.LWNode(t1, (dest, fp)),
            mips.SWNode(t0, 4, t1),
            mips.CommentNode(f"</complement:{node.dest}>"),
        )
    def visit(self, node: cil.TypeNameNode):
        name_offset = self.types['Object'].name_offset
        src_offset = self.get_address(node.src)

        self.add_inst(mips.CommentNode(f"<typename:{node.dest}-{node.src}>"), )

        self.visit(cil.StaticCallNode('String__init', node.dest))

        self.add_inst(
            mips.LWNode(t0,
                        (src_offset, fp)).with_comm('Load pointer to self'),
            mips.LWNode(t0, (0, t0)).with_comm('Load pointer to type of self'),
            mips.ADDINode(t0, t0,
                          name_offset).with_comm('Point to name of type'),
            mips.SWNode(
                t0, 4,
                v0).with_comm('Save name of the type in the new string'),
            mips.CommentNode(f"</typename:{node.dest}-{node.src}>"),
        )