Skip to content

unary_ops

Classes:

UnaryOpVisitorMixin

Bases: VisitorMixinBase

Methods:

visit

visit(node: UnaryOp) -> None
Source code in src/irx/builder/lowering/unary_ops.py
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
@VisitorCore.visit.dispatch  # type: ignore[attr-defined,untyped-decorator]
def visit(self, node: astx.UnaryOp) -> None:
    """
    title: Visit UnaryOp nodes.
    parameters:
      node:
        type: astx.UnaryOp
    """
    if node.op_code == "++":
        self.visit_child(node.operand)
        operand_val = safe_pop(self.result_stack)
        if operand_val is None:
            raise Exception("codegen: Invalid unary operand.")
        operand_name = (
            node.operand.name
            if isinstance(node.operand, astx.Identifier)
            else getattr(node.operand, "field_name", "field")
        )
        operand_key = semantic_assignment_key(node, operand_name)

        one = ir.Constant(operand_val.type, 1)
        if is_fp_type(operand_val.type):
            result = self._llvm.ir_builder.fadd(operand_val, one, "inctmp")
        else:
            result = self._llvm.ir_builder.add(operand_val, one, "inctmp")

        if (
            isinstance(node.operand, astx.Identifier)
            and operand_key in self.const_vars
        ):
            raise Exception(
                f"Cannot mutate '{operand_name}': declared as constant"
            )
        target_addr = self._lvalue_address(node.operand)
        self._llvm.ir_builder.store(result, target_addr)

        self.result_stack.append(result)
        return

    if node.op_code == "--":
        self.visit_child(node.operand)
        operand_val = safe_pop(self.result_stack)
        if operand_val is None:
            raise Exception("codegen: Invalid unary operand.")
        operand_name = (
            node.operand.name
            if isinstance(node.operand, astx.Identifier)
            else getattr(node.operand, "field_name", "field")
        )
        operand_key = semantic_assignment_key(node, operand_name)
        one = ir.Constant(operand_val.type, 1)
        if is_fp_type(operand_val.type):
            result = self._llvm.ir_builder.fsub(operand_val, one, "dectmp")
        else:
            result = self._llvm.ir_builder.sub(operand_val, one, "dectmp")

        if (
            isinstance(node.operand, astx.Identifier)
            and operand_key in self.const_vars
        ):
            raise Exception(
                f"Cannot mutate '{operand_name}': declared as constant"
            )
        target_addr = self._lvalue_address(node.operand)
        self._llvm.ir_builder.store(result, target_addr)

        self.result_stack.append(result)
        return

    if node.op_code == "!":
        self.visit_child(node.operand)
        val = safe_pop(self.result_stack)
        if val is None:
            raise Exception("codegen: Invalid unary operand.")
        if not is_int_type(val.type) or val.type.width != 1:
            raise Exception(
                "codegen: unary operator '!' must lower a Boolean operand."
            )

        result = self._llvm.ir_builder.xor(
            val,
            ir.Constant(self._llvm.BOOLEAN_TYPE, 1),
            "nottmp",
        )

        self.result_stack.append(result)
        return

    raise Exception(f"Unary operator {node.op_code} not implemented yet.")