Skip to content

Warning

This page is under construction. The content may be incomplete or incorrect. Submit an issue on GitHub if you need help or want to contribute.

Core Python Dialects

This page contains the core Python dialects that are used most frequently when designing an embedded DSL in Python.

Reference

Base

kirin.dialects.py.base

Base dialect for Python.

This dialect does not contain statements. It only contains lowering rules for ast.Name and ast.Expr.

dialect module-attribute

dialect = Dialect('py.base')

PythonLowering dataclass

PythonLowering()

Bases: FromPythonAST

lower_Expr

lower_Expr(
    state: lowering.State, node: ast.Expr
) -> lowering.Result
Source code in src/kirin/dialects/py/base.py
29
30
def lower_Expr(self, state: lowering.State, node: ast.Expr) -> lowering.Result:
    return state.parent.visit(state, node.value)

lower_Name

lower_Name(
    state: lowering.State, node: ast.Name
) -> lowering.Result
Source code in src/kirin/dialects/py/base.py
17
18
19
20
21
22
23
24
25
26
27
def lower_Name(self, state: lowering.State, node: ast.Name) -> lowering.Result:
    name = node.id
    if isinstance(node.ctx, ast.Load):
        value = state.current_frame.get(name)
        if value is None:
            raise lowering.BuildError(f"{name} is not defined")
        return value
    elif isinstance(node.ctx, ast.Store):
        raise lowering.BuildError("unhandled store operation")
    else:  # Del
        raise lowering.BuildError("unhandled del operation")

Constant

kirin.dialects.py.constant

Constant statement for Python dialect.

This module contains the dialect for the Python constant statement, including:

  • The Constant statement class.
  • The lowering pass for the constant statement.
  • The concrete implementation of the constant statement.
  • The Julia emitter for the constant statement.

This dialect maps ast.Constant nodes to the Constant statement.

T module-attribute

T = TypeVar('T', covariant=True)

dialect module-attribute

dialect = Dialect('py.constant')

Concrete dataclass

Concrete()

Bases: MethodTable

constant

constant(interp, frame: interp.Frame, stmt: Constant)
Source code in src/kirin/dialects/py/constant.py
74
75
76
@interp.impl(Constant)
def constant(self, interp, frame: interp.Frame, stmt: Constant):
    return (stmt.value.unwrap(),)

Constant kirin-statement

Constant(value: T | ir.Data[T])

Bases: Statement, Generic[T]

Source code in src/kirin/dialects/py/constant.py
34
35
36
37
38
39
40
def __init__(self, value: T | ir.Data[T]) -> None:
    if not isinstance(value, ir.Data):
        value = ir.PyAttr(value)
    super().__init__(
        attributes={"value": value},
        result_types=(value.type,),
    )

name class-attribute instance-attribute

name = 'constant'

result kirin-result

result: ResultValue = result()

traits class-attribute instance-attribute

traits = frozenset(
    {Pure(), ConstantLike(), FromPythonCall()}
)

value kirin-attribute kw-only

value: Data[T] = attribute()

check_type

check_type() -> None

Check the types of the Block. Raises Exception if the types are not correct. This method is called by the verify_type method, which will detect the source of the error in the IR. One should always call the verify_type method to verify the types of the IR.

Note

This method is generated by the @statement decorator. But can be overridden if needed.

Source code in src/kirin/dialects/py/constant.py
53
54
55
56
57
def check_type(self) -> None:
    if not isinstance(self.result.type, types.TypeAttribute):
        raise TypeError(
            f"Expected result type to be PyType, got {self.result.type}"
        )

print_impl

print_impl(printer: Printer) -> None
Source code in src/kirin/dialects/py/constant.py
42
43
44
45
46
47
48
49
50
51
def print_impl(self, printer: Printer) -> None:
    printer.print_name(self)
    printer.plain_print(" ")
    if isinstance(self.value, ir.PyAttr):
        printer.plain_print(repr(self.value.data))
    else:  # other attributes
        printer.plain_print(repr(self.value))
    with printer.rich(style="comment"):
        printer.plain_print(" : ")
        printer.print(self.result.type)

JuliaTable dataclass

JuliaTable()

Bases: MethodTable

emit_Constant

emit_Constant(
    emit: EmitJulia, frame: EmitStrFrame, stmt: Constant
)
Source code in src/kirin/dialects/py/constant.py
82
83
84
@interp.impl(Constant)
def emit_Constant(self, emit: EmitJulia, frame: EmitStrFrame, stmt: Constant):
    return (emit.emit_attribute(stmt.value),)

Lowering dataclass

Lowering()

Bases: FromPythonAST

lower_Constant

lower_Constant(
    state: lowering.State, node: ast.Constant
) -> lowering.Result
Source code in src/kirin/dialects/py/constant.py
63
64
65
66
67
68
def lower_Constant(
    self, state: lowering.State, node: ast.Constant
) -> lowering.Result:
    return state.current_frame.push(
        Constant(node.value),
    )

UnaryOp

kirin.dialects.py.unary.stmts

T module-attribute

T = TypeVar('T')

Invert kirin-statement

Invert(value: ir.SSAValue)

Bases: UnaryOp

name class-attribute instance-attribute

name = 'invert'

Not kirin-statement

Not(value: ir.SSAValue)

Bases: UnaryOp

name class-attribute instance-attribute

name = 'not'

UAdd kirin-statement

UAdd(value: ir.SSAValue)

Bases: UnaryOp

name class-attribute instance-attribute

name = 'uadd'

USub kirin-statement

USub(value: ir.SSAValue)

Bases: UnaryOp

name class-attribute instance-attribute

name = 'usub'

UnaryOp kirin-statement

UnaryOp(value: ir.SSAValue)

Bases: Statement

result kirin-result

result: ResultValue = result(T)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

value kirin-argument

value: SSAValue = argument(T, print=False)

BinOp

kirin.dialects.py.binop.stmts

T module-attribute

T = TypeVar('T')

Add kirin-statement

Add(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'add'

BinOp kirin-statement

BinOp(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Statement

lhs kirin-argument

lhs: SSAValue = argument(T, print=False)

result kirin-result

result: ResultValue = result(T)

rhs kirin-argument

rhs: SSAValue = argument(T, print=False)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

BitAnd kirin-statement

BitAnd(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'bitand'

BitOr kirin-statement

BitOr(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'bitor'

BitXor kirin-statement

BitXor(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'bitxor'

Div kirin-statement

Div(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'div'

FloorDiv kirin-statement

FloorDiv(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'floordiv'

LShift kirin-statement

LShift(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'lshift'

MatMult kirin-statement

MatMult(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'matmult'

Mod kirin-statement

Mod(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'mod'

Mult kirin-statement

Mult(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'mult'

Pow kirin-statement

Pow(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'pow'

RShift kirin-statement

RShift(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'rshift'

Sub kirin-statement

Sub(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BinOp

name class-attribute instance-attribute

name = 'sub'

Assertion

kirin.dialects.py.assertion

Assertion dialect for Python.

This module contains the dialect for the Python assert statement, including:

  • The Assert statement class.
  • The lowering pass for the assert statement.
  • The concrete implementation of the assert statement.
  • The type inference implementation of the assert statement.
  • The Julia emitter for the assert statement.

This dialect maps ast.Assert nodes to the Assert statement.

dialect module-attribute

dialect = Dialect('py.assert')

Assert kirin-statement

Assert(message: ir.SSAValue)

Bases: Statement

condition instance-attribute

condition: SSAValue

message kirin-argument

message: SSAValue = argument(String)

print_impl

print_impl(printer: Printer) -> None
Source code in src/kirin/dialects/py/assertion.py
29
30
31
32
33
34
35
36
37
38
def print_impl(self, printer: Printer) -> None:
    with printer.rich(style="keyword"):
        printer.print_name(self)

    printer.plain_print(" ")
    printer.print(self.condition)

    if self.message:
        printer.plain_print(", ")
        printer.print(self.message)

Concrete dataclass

Concrete()

Bases: MethodTable

assert_stmt

assert_stmt(
    interp_: interp.Interpreter,
    frame: interp.Frame,
    stmt: Assert,
)
Source code in src/kirin/dialects/py/assertion.py
61
62
63
64
65
66
67
68
69
70
71
@interp.impl(Assert)
def assert_stmt(
    self, interp_: interp.Interpreter, frame: interp.Frame, stmt: Assert
):
    if frame.get(stmt.condition) is True:
        return ()

    if stmt.message:
        raise AssertionError(frame.get(stmt.message))
    else:
        raise AssertionError("Assertion failed")

EmitJulia dataclass

EmitJulia()

Bases: MethodTable

emit_assert

emit_assert(
    interp: julia.EmitJulia,
    frame: EmitStrFrame,
    stmt: Assert,
)
Source code in src/kirin/dialects/py/assertion.py
85
86
87
88
89
90
@interp.impl(Assert)
def emit_assert(self, interp: julia.EmitJulia, frame: EmitStrFrame, stmt: Assert):
    interp.writeln(
        frame, f"@assert {frame.get(stmt.condition)} {frame.get(stmt.message)}"
    )
    return ()

Lowering dataclass

Lowering()

Bases: FromPythonAST

lower_Assert

lower_Assert(
    state: lowering.State, node: ast.Assert
) -> lowering.Result
Source code in src/kirin/dialects/py/assertion.py
44
45
46
47
48
49
50
51
52
53
54
55
def lower_Assert(self, state: lowering.State, node: ast.Assert) -> lowering.Result:
    from kirin.dialects.py.constant import Constant

    cond = state.lower(node.test).expect_one()
    if node.msg:
        message = state.lower(node.msg).expect_one()
        state.current_frame.push(Assert(condition=cond, message=message))
    else:
        message_stmt = state.current_frame.push(Constant(""))
        state.current_frame.push(
            Assert(condition=cond, message=message_stmt.result)
        )

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

assert_stmt

assert_stmt(interp, frame, stmt: Assert)
Source code in src/kirin/dialects/py/assertion.py
77
78
79
@interp.impl(Assert)
def assert_stmt(self, interp, frame, stmt: Assert):
    return (types.Bottom,)

Assignment

kirin.dialects.py.assign

Assignment dialect for Python.

This module contains the dialect for the Python assignment statement, including:

  • Statements: Alias, SetItem.
  • The lowering pass for the assignments.
  • The concrete implementation of the assignment statements.

This dialects maps Python assignment syntax.

T module-attribute

T = TypeVar('T')

dialect module-attribute

dialect = Dialect('py.assign')

Alias kirin-statement

Alias(value: ir.SSAValue, *, target: ir.PyAttr[str])

Bases: Statement

name class-attribute instance-attribute

name = 'alias'

result kirin-result

result: ResultValue = result(T)

target kirin-attribute kw-only

target: PyAttr[str] = attribute()

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

value kirin-argument

value: SSAValue = argument(T)

print_impl

print_impl(printer: Printer) -> None
Source code in src/kirin/dialects/py/assign.py
31
32
33
34
35
36
37
38
39
40
def print_impl(self, printer: Printer) -> None:
    printer.print_name(self)
    printer.plain_print(" ")
    with printer.rich(style="symbol"):
        printer.plain_print(self.target.data)

    with printer.rich(style="keyword"):
        printer.plain_print(" = ")

    printer.print(self.value)

Concrete dataclass

Concrete()

Bases: MethodTable

alias

alias(interp, frame: interp.Frame, stmt: Alias)
Source code in src/kirin/dialects/py/assign.py
80
81
82
@interp.impl(Alias)
def alias(self, interp, frame: interp.Frame, stmt: Alias):
    return (frame.get(stmt.value),)

set_attribute

set_attribute(
    interp, frame: interp.Frame, stmt: SetAttribute
)
Source code in src/kirin/dialects/py/assign.py
88
89
90
91
92
@interp.impl(SetAttribute)
def set_attribute(self, interp, frame: interp.Frame, stmt: SetAttribute):
    obj = frame.get(stmt.obj)
    value = frame.get(stmt.value)
    setattr(obj, stmt.attr, value)

setindex

setindex(interp, frame: interp.Frame, stmt: SetItem)
Source code in src/kirin/dialects/py/assign.py
84
85
86
@interp.impl(SetItem)
def setindex(self, interp, frame: interp.Frame, stmt: SetItem):
    frame.get(stmt.obj)[frame.get(stmt.index)] = frame.get(stmt.value)

type_assert

type_assert(interp_, frame: interp.Frame, stmt: TypeAssert)
Source code in src/kirin/dialects/py/assign.py
 97
 98
 99
100
101
102
103
@interp.impl(TypeAssert)
def type_assert(self, interp_, frame: interp.Frame, stmt: TypeAssert):
    got = frame.get(stmt.got)
    got_type = types.PyClass(type(got))
    if not got_type.is_subseteq(stmt.expected):
        raise TypeError(f"Expected {stmt.expected}, got {got_type}")
    return (frame.get(stmt.got),)

Lowering dataclass

Lowering()

Bases: FromPythonAST

assign_item classmethod

assign_item(
    state: lowering.State,
    target,
    result: lowering.State.Result,
)
Source code in src/kirin/dialects/py/assign.py
189
190
191
192
193
194
195
196
197
198
199
200
@classmethod
def assign_item(cls, state: lowering.State, target, result: lowering.State.Result):
    match target:
        case ast.Tuple(elts, ast.Store()):
            if len(elts) != len(result.data):
                raise lowering.BuildError(
                    f"tuple assignment length mismatch: {len(elts)} != {len(result.data)}"
                )
            for target, value in zip(elts, result.data):
                cls.assign_item_value(state, target, value)
        case _:
            cls.assign_item_value(state, target, result.expect_one())

assign_item_value classmethod

assign_item_value(
    state: lowering.State, target, value: ir.SSAValue
)
Source code in src/kirin/dialects/py/assign.py
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
@classmethod
def assign_item_value(cls, state: lowering.State, target, value: ir.SSAValue):
    current_frame = state.current_frame
    match target:
        case ast.Name(name, ast.Store()):
            value.name = name
            current_frame.defs[name] = value
        case ast.Attribute(obj, attr, ast.Store()):
            obj = state.lower(obj).expect_one()
            stmt = SetAttribute(obj, value, attr=attr)
            current_frame.push(stmt)
        case ast.Subscript(obj, slice, ast.Store()):
            obj = state.lower(obj).expect_one()
            slice = state.lower(slice).expect_one()
            stmt = SetItem(obj=obj, index=slice, value=value)
            current_frame.push(stmt)
        case _:
            raise lowering.BuildError(f"unsupported target {target}")

lower_AnnAssign

lower_AnnAssign(
    state: lowering.State, node: ast.AnnAssign
) -> lowering.Result
Source code in src/kirin/dialects/py/assign.py
137
138
139
140
141
142
143
def lower_AnnAssign(
    self, state: lowering.State, node: ast.AnnAssign
) -> lowering.Result:
    type_hint = self.get_hint(state, node.annotation)
    value = state.lower(node.value).expect_one()
    stmt = state.current_frame.push(TypeAssert(got=value, expected=type_hint))
    self.assign_item_value(state, node.target, stmt.result)

lower_Assign

lower_Assign(
    state: lowering.State, node: ast.Assign
) -> lowering.Result
Source code in src/kirin/dialects/py/assign.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def lower_Assign(self, state: lowering.State, node: ast.Assign) -> lowering.Result:
    result = state.lower(node.value)
    current_frame = state.current_frame
    match node:
        case ast.Assign(
            targets=[ast.Name(lhs_name, ast.Store())], value=ast.Name(_, ast.Load())
        ):
            stmt = Alias(
                value=result.data[0], target=ir.PyAttr(lhs_name)
            )  # NOTE: this is guaranteed to be one result
            stmt.result.name = lhs_name
            current_frame.defs[lhs_name] = current_frame.push(stmt).result
        case _:
            for target in node.targets:
                self.assign_item(state, target, result)

lower_AugAssign

lower_AugAssign(
    state: lowering.State, node: ast.AugAssign
) -> lowering.Result
Source code in src/kirin/dialects/py/assign.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def lower_AugAssign(
    self, state: lowering.State, node: ast.AugAssign
) -> lowering.Result:
    match node.target:
        case ast.Name(name, ast.Store()):
            rhs = ast.Name(name, ast.Load())
        case ast.Attribute(obj, attr, ast.Store()):
            rhs = ast.Attribute(obj, attr, ast.Load())
        case ast.Subscript(obj, slice, ast.Store()):
            rhs = ast.Subscript(obj, slice, ast.Load())
        case _:
            raise lowering.BuildError(f"unsupported target {node.target}")
    self.assign_item_value(
        state,
        node.target,
        state.lower(ast.BinOp(rhs, node.op, node.value)).expect_one(),
    )

lower_NamedExpr

lower_NamedExpr(
    state: lowering.State, node: ast.NamedExpr
) -> lowering.Result
Source code in src/kirin/dialects/py/assign.py
163
164
165
166
167
168
def lower_NamedExpr(
    self, state: lowering.State, node: ast.NamedExpr
) -> lowering.Result:
    value = state.lower(node.value).expect_one()
    self.assign_item_value(state, node.target, value)
    return value

SetAttribute kirin-statement

SetAttribute(
    obj: ir.SSAValue, value: ir.SSAValue, *, attr: str
)

Bases: Statement

attr kirin-attribute kw-only

attr: str = attribute()

name class-attribute instance-attribute

name = 'setattr'

obj kirin-argument

obj: SSAValue = argument(print=False)

traits class-attribute instance-attribute

traits = frozenset({FromPythonCall()})

value kirin-argument

value: SSAValue = argument(print=False)

SetItem kirin-statement

SetItem(
    obj: ir.SSAValue, value: ir.SSAValue, index: ir.SSAValue
)

Bases: Statement

index kirin-argument

index: SSAValue = argument(print=False)

name class-attribute instance-attribute

name = 'setitem'

obj kirin-argument

obj: SSAValue = argument(print=False)

traits class-attribute instance-attribute

traits = frozenset({FromPythonCall()})

value kirin-argument

value: SSAValue = argument(print=False)

TypeAssert kirin-statement

TypeAssert(
    got: ir.SSAValue, *, expected: types.TypeAttribute
)

Bases: Statement

Source code in src/kirin/dialects/py/assign.py
68
69
70
71
72
73
74
def __init__(self, got: ir.SSAValue, *, expected: types.TypeAttribute):
    super().__init__(
        args=(got,),
        attributes={"expected": expected},
        result_types=(expected,),
        args_slice={"got": 0},
    )

expected kirin-attribute kw-only

expected: TypeAttribute = attribute()

got kirin-argument

got: SSAValue = argument(print=False)

result kirin-result

result: ResultValue = result()

traits class-attribute instance-attribute

traits = frozenset({FromPythonCall()})

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

type_assert

type_assert(
    interp_,
    frame: interp.Frame[types.TypeAttribute],
    stmt: TypeAssert,
)
Source code in src/kirin/dialects/py/assign.py
108
109
110
111
112
113
114
115
@interp.impl(TypeAssert)
def type_assert(
    self, interp_, frame: interp.Frame[types.TypeAttribute], stmt: TypeAssert
):
    got = frame.get(stmt.got)
    if got.is_subseteq(stmt.expected):
        return (got.meet(stmt.expected),)
    return (types.Bottom,)

Unpack

kirin.dialects.py.unpack

The unpack dialect for Python.

This module contains the dialect for the Python unpack semantics, including:

  • The Unpack statement class.
  • The lowering pass for the unpack statement.
  • The concrete implementation of the unpack statement.
  • The type inference implementation of the unpack statement.
  • A helper function unpacking for unpacking Python AST nodes during lowering.

dialect module-attribute

dialect = Dialect('py.unpack')

Concrete dataclass

Concrete()

Bases: MethodTable

unpack

unpack(
    interp: interp.Interpreter,
    frame: interp.Frame,
    stmt: Unpack,
)
Source code in src/kirin/dialects/py/unpack.py
46
47
48
@interp.impl(Unpack)
def unpack(self, interp: interp.Interpreter, frame: interp.Frame, stmt: Unpack):
    return tuple(frame.get(stmt.value))

TypeInfer dataclass

TypeInfer()

Bases: MethodTable

unpack

unpack(
    interp,
    frame: interp.Frame[types.TypeAttribute],
    stmt: Unpack,
)
Source code in src/kirin/dialects/py/unpack.py
54
55
56
57
58
59
60
61
62
63
64
@interp.impl(Unpack)
def unpack(self, interp, frame: interp.Frame[types.TypeAttribute], stmt: Unpack):
    value = frame.get(stmt.value)
    if isinstance(value, types.Generic) and value.is_subseteq(types.Tuple):
        if value.vararg:
            rest = tuple(value.vararg.typ for _ in stmt.names[len(value.vars) :])
            return tuple(value.vars) + rest
        else:
            return value.vars
    # TODO: support unpacking other types
    return tuple(types.Any for _ in stmt.names)

Unpack kirin-statement

Unpack(value: ir.SSAValue, names: tuple[str | None, ...])

Bases: Statement

Source code in src/kirin/dialects/py/unpack.py
26
27
28
29
30
31
32
33
34
35
def __init__(self, value: ir.SSAValue, names: tuple[str | None, ...]):
    result_types = [types.Any] * len(names)
    super().__init__(
        args=(value,),
        result_types=result_types,
        args_slice={"value": 0},
        attributes={"names": ir.PyAttr(names)},
    )
    for result, name in zip(self.results, names):
        result.name = name

names kirin-attribute kw-only

names: tuple[str | None, ...] = attribute()

value kirin-argument

value: SSAValue = argument(Any)

print_impl

print_impl(printer: Printer) -> None
Source code in src/kirin/dialects/py/unpack.py
37
38
39
40
def print_impl(self, printer: Printer) -> None:
    printer.print_name(self)
    printer.plain_print(" ")
    printer.print(self.value)

unpacking

unpacking(
    state: lowering.State,
    node: ast.expr,
    value: ir.SSAValue,
)
Source code in src/kirin/dialects/py/unpack.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def unpacking(state: lowering.State, node: ast.expr, value: ir.SSAValue):
    if isinstance(node, ast.Name):
        state.current_frame.defs[node.id] = value
        value.name = node.id
        return
    elif not isinstance(node, ast.Tuple):
        raise lowering.BuildError(f"unsupported unpack node {node}")

    names: list[str | None] = []
    continue_unpack: list[int] = []
    for idx, item in enumerate(node.elts):
        if isinstance(item, ast.Name):
            names.append(item.id)
        else:
            names.append(None)
            continue_unpack.append(idx)
    stmt = state.current_frame.push(Unpack(value, tuple(names)))
    for name, result in zip(names, stmt.results):
        if name is not None:
            state.current_frame.defs[name] = result

    for idx in continue_unpack:
        unpacking(state, node.elts[idx], stmt.results[idx])

Boolean Operation

kirin.dialects.py.boolop

Boolean operators for Python dialect.

This module contains the dialect for the Python boolean operators, including:

  • The And and Or statement classes.
  • The lowering pass for the boolean operators.
  • The concrete implementation of the boolean operators.
  • The Julia emitter for the boolean operators.

This dialect maps ast.BoolOp nodes to the And and Or statements.

dialect module-attribute

dialect = Dialect('py.boolop')

And kirin-statement

And(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BoolOp

name class-attribute instance-attribute

name = 'and'

BoolOp kirin-statement

BoolOp(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Statement

lhs kirin-argument

lhs: SSAValue = argument(print=False)

result kirin-result

result: ResultValue = result(Bool)

rhs kirin-argument

rhs: SSAValue = argument(print=False)

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

BoolOpMethod dataclass

BoolOpMethod()

Bases: MethodTable

and_

and_(interp, frame: interp.Frame, stmt: And)
Source code in src/kirin/dialects/py/boolop.py
63
64
65
@interp.impl(And)
def and_(self, interp, frame: interp.Frame, stmt: And):
    return (frame.get(stmt.lhs) and frame.get(stmt.rhs),)

or_

or_(interp, frame: interp.Frame, stmt: Or)
Source code in src/kirin/dialects/py/boolop.py
67
68
69
@interp.impl(Or)
def or_(self, interp, frame: interp.Frame, stmt: Or):
    return (frame.get(stmt.lhs) or frame.get(stmt.rhs),)

JuliaTable dataclass

JuliaTable()

Bases: MethodTable

emit_And

emit_And(emit: EmitJulia, frame: EmitStrFrame, stmt: And)
Source code in src/kirin/dialects/py/boolop.py
75
76
77
@interp.impl(And)
def emit_And(self, emit: EmitJulia, frame: EmitStrFrame, stmt: And):
    return emit.emit_binaryop(frame, "&&", stmt.lhs, stmt.rhs, stmt.result)

emit_Or

emit_Or(emit: EmitJulia, frame: EmitStrFrame, stmt: Or)
Source code in src/kirin/dialects/py/boolop.py
79
80
81
@interp.impl(Or)
def emit_Or(self, emit: EmitJulia, frame: EmitStrFrame, stmt: Or):
    return emit.emit_binaryop(frame, "||", stmt.lhs, stmt.rhs, stmt.result)

Or kirin-statement

Or(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: BoolOp

name class-attribute instance-attribute

name = 'or'

PythonLowering dataclass

PythonLowering()

Bases: FromPythonAST

lower_BoolOp

lower_BoolOp(
    state: lowering.State, node: ast.BoolOp
) -> lowering.Result
Source code in src/kirin/dialects/py/boolop.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def lower_BoolOp(self, state: lowering.State, node: ast.BoolOp) -> lowering.Result:
    lhs = state.lower(node.values[0]).expect_one()
    match node.op:
        case ast.And():
            boolop = And
        case ast.Or():
            boolop = Or
        case _:
            raise lowering.BuildError(f"unsupported boolop {node.op}")

    for value in node.values[1:]:
        lhs = state.current_frame.push(
            boolop(lhs=lhs, rhs=state.lower(value).expect_one())
        ).result
    return lhs

Comparison

kirin.dialects.py.cmp.stmts

Cmp kirin-statement

Cmp(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Statement

lhs kirin-argument

lhs: SSAValue = argument()

result kirin-result

result: ResultValue = result(Bool)

rhs kirin-argument

rhs: SSAValue = argument()

traits class-attribute instance-attribute

traits = frozenset({Pure(), FromPythonCall()})

Eq kirin-statement

Eq(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'eq'

Gt kirin-statement

Gt(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'gt'

GtE kirin-statement

GtE(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'gte'

In kirin-statement

In(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'in'

Is kirin-statement

Is(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'is'

IsNot kirin-statement

IsNot(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'is_not'

Lt kirin-statement

Lt(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'lt'

LtE kirin-statement

LtE(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'lte'

NotEq kirin-statement

NotEq(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'ne'

NotIn kirin-statement

NotIn(lhs: ir.SSAValue, rhs: ir.SSAValue)

Bases: Cmp

name class-attribute instance-attribute

name = 'not_in'