kirin-toolchain 0.13.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- kirin/__init__.py +7 -0
- kirin/analysis/__init__.py +24 -0
- kirin/analysis/callgraph.py +61 -0
- kirin/analysis/cfg.py +112 -0
- kirin/analysis/const/__init__.py +20 -0
- kirin/analysis/const/_visitor.py +2 -0
- kirin/analysis/const/_visitor.pyi +8 -0
- kirin/analysis/const/lattice.py +219 -0
- kirin/analysis/const/prop.py +116 -0
- kirin/analysis/forward.py +100 -0
- kirin/analysis/typeinfer/__init__.py +5 -0
- kirin/analysis/typeinfer/analysis.py +90 -0
- kirin/analysis/typeinfer/solve.py +141 -0
- kirin/decl/__init__.py +108 -0
- kirin/decl/base.py +65 -0
- kirin/decl/camel2snake.py +2 -0
- kirin/decl/emit/__init__.py +0 -0
- kirin/decl/emit/_create_fn.py +29 -0
- kirin/decl/emit/_set_new_attribute.py +22 -0
- kirin/decl/emit/dialect.py +8 -0
- kirin/decl/emit/init.py +277 -0
- kirin/decl/emit/name.py +10 -0
- kirin/decl/emit/property.py +182 -0
- kirin/decl/emit/repr.py +31 -0
- kirin/decl/emit/traits.py +13 -0
- kirin/decl/emit/typecheck.py +77 -0
- kirin/decl/emit/verify.py +51 -0
- kirin/decl/info.py +346 -0
- kirin/decl/scan_fields.py +157 -0
- kirin/decl/verify.py +69 -0
- kirin/dialects/__init__.py +14 -0
- kirin/dialects/_pprint_helper.py +53 -0
- kirin/dialects/cf/__init__.py +20 -0
- kirin/dialects/cf/constprop.py +51 -0
- kirin/dialects/cf/dialect.py +3 -0
- kirin/dialects/cf/emit.py +58 -0
- kirin/dialects/cf/interp.py +24 -0
- kirin/dialects/cf/stmts.py +68 -0
- kirin/dialects/cf/typeinfer.py +27 -0
- kirin/dialects/eltype.py +23 -0
- kirin/dialects/func/__init__.py +20 -0
- kirin/dialects/func/attrs.py +39 -0
- kirin/dialects/func/constprop.py +138 -0
- kirin/dialects/func/dialect.py +3 -0
- kirin/dialects/func/emit.py +80 -0
- kirin/dialects/func/interp.py +68 -0
- kirin/dialects/func/stmts.py +233 -0
- kirin/dialects/func/typeinfer.py +124 -0
- kirin/dialects/ilist/__init__.py +33 -0
- kirin/dialects/ilist/_dialect.py +3 -0
- kirin/dialects/ilist/_wrapper.py +51 -0
- kirin/dialects/ilist/interp.py +85 -0
- kirin/dialects/ilist/lowering.py +25 -0
- kirin/dialects/ilist/passes.py +32 -0
- kirin/dialects/ilist/rewrite/__init__.py +3 -0
- kirin/dialects/ilist/rewrite/const.py +45 -0
- kirin/dialects/ilist/rewrite/list.py +38 -0
- kirin/dialects/ilist/rewrite/unroll.py +131 -0
- kirin/dialects/ilist/runtime.py +63 -0
- kirin/dialects/ilist/stmts.py +102 -0
- kirin/dialects/ilist/typeinfer.py +120 -0
- kirin/dialects/lowering/__init__.py +7 -0
- kirin/dialects/lowering/call.py +48 -0
- kirin/dialects/lowering/cf.py +206 -0
- kirin/dialects/lowering/func.py +134 -0
- kirin/dialects/math/__init__.py +41 -0
- kirin/dialects/math/_gen.py +176 -0
- kirin/dialects/math/dialect.py +3 -0
- kirin/dialects/math/interp.py +190 -0
- kirin/dialects/math/stmts.py +369 -0
- kirin/dialects/module.py +139 -0
- kirin/dialects/py/__init__.py +40 -0
- kirin/dialects/py/assertion.py +91 -0
- kirin/dialects/py/assign.py +103 -0
- kirin/dialects/py/attr.py +59 -0
- kirin/dialects/py/base.py +34 -0
- kirin/dialects/py/binop/__init__.py +23 -0
- kirin/dialects/py/binop/_dialect.py +3 -0
- kirin/dialects/py/binop/interp.py +60 -0
- kirin/dialects/py/binop/julia.py +33 -0
- kirin/dialects/py/binop/lowering.py +22 -0
- kirin/dialects/py/binop/stmts.py +79 -0
- kirin/dialects/py/binop/typeinfer.py +108 -0
- kirin/dialects/py/boolop.py +84 -0
- kirin/dialects/py/builtin.py +78 -0
- kirin/dialects/py/cmp/__init__.py +16 -0
- kirin/dialects/py/cmp/_dialect.py +3 -0
- kirin/dialects/py/cmp/interp.py +48 -0
- kirin/dialects/py/cmp/julia.py +33 -0
- kirin/dialects/py/cmp/lowering.py +45 -0
- kirin/dialects/py/cmp/stmts.py +62 -0
- kirin/dialects/py/constant.py +79 -0
- kirin/dialects/py/indexing.py +251 -0
- kirin/dialects/py/iterable.py +90 -0
- kirin/dialects/py/len.py +57 -0
- kirin/dialects/py/list/__init__.py +15 -0
- kirin/dialects/py/list/_dialect.py +3 -0
- kirin/dialects/py/list/interp.py +21 -0
- kirin/dialects/py/list/lowering.py +25 -0
- kirin/dialects/py/list/stmts.py +22 -0
- kirin/dialects/py/list/typeinfer.py +54 -0
- kirin/dialects/py/range.py +76 -0
- kirin/dialects/py/slice.py +120 -0
- kirin/dialects/py/tuple.py +109 -0
- kirin/dialects/py/unary/__init__.py +24 -0
- kirin/dialects/py/unary/_dialect.py +3 -0
- kirin/dialects/py/unary/constprop.py +20 -0
- kirin/dialects/py/unary/interp.py +24 -0
- kirin/dialects/py/unary/julia.py +21 -0
- kirin/dialects/py/unary/lowering.py +22 -0
- kirin/dialects/py/unary/stmts.py +33 -0
- kirin/dialects/py/unary/typeinfer.py +23 -0
- kirin/dialects/py/unpack.py +90 -0
- kirin/dialects/scf/__init__.py +23 -0
- kirin/dialects/scf/_dialect.py +3 -0
- kirin/dialects/scf/absint.py +64 -0
- kirin/dialects/scf/constprop.py +140 -0
- kirin/dialects/scf/interp.py +35 -0
- kirin/dialects/scf/lowering.py +123 -0
- kirin/dialects/scf/stmts.py +250 -0
- kirin/dialects/scf/trim.py +36 -0
- kirin/dialects/scf/typeinfer.py +58 -0
- kirin/dialects/scf/unroll.py +92 -0
- kirin/emit/__init__.py +3 -0
- kirin/emit/abc.py +89 -0
- kirin/emit/abc.pyi +38 -0
- kirin/emit/exceptions.py +5 -0
- kirin/emit/julia.py +63 -0
- kirin/emit/str.py +51 -0
- kirin/exceptions.py +59 -0
- kirin/graph.py +34 -0
- kirin/idtable.py +57 -0
- kirin/interp/__init__.py +39 -0
- kirin/interp/abstract.py +253 -0
- kirin/interp/base.py +438 -0
- kirin/interp/concrete.py +62 -0
- kirin/interp/exceptions.py +26 -0
- kirin/interp/frame.py +151 -0
- kirin/interp/impl.py +197 -0
- kirin/interp/result.py +93 -0
- kirin/interp/state.py +71 -0
- kirin/interp/table.py +40 -0
- kirin/interp/value.py +73 -0
- kirin/ir/__init__.py +46 -0
- kirin/ir/attrs/__init__.py +20 -0
- kirin/ir/attrs/_types.py +8 -0
- kirin/ir/attrs/_types.pyi +13 -0
- kirin/ir/attrs/abc.py +46 -0
- kirin/ir/attrs/py.py +45 -0
- kirin/ir/attrs/types.py +522 -0
- kirin/ir/dialect.py +125 -0
- kirin/ir/group.py +249 -0
- kirin/ir/method.py +118 -0
- kirin/ir/nodes/__init__.py +7 -0
- kirin/ir/nodes/base.py +149 -0
- kirin/ir/nodes/block.py +458 -0
- kirin/ir/nodes/region.py +337 -0
- kirin/ir/nodes/stmt.py +713 -0
- kirin/ir/nodes/view.py +142 -0
- kirin/ir/ssa.py +204 -0
- kirin/ir/traits/__init__.py +36 -0
- kirin/ir/traits/abc.py +42 -0
- kirin/ir/traits/basic.py +78 -0
- kirin/ir/traits/callable.py +51 -0
- kirin/ir/traits/lowering/__init__.py +2 -0
- kirin/ir/traits/lowering/call.py +37 -0
- kirin/ir/traits/lowering/context.py +120 -0
- kirin/ir/traits/region/__init__.py +2 -0
- kirin/ir/traits/region/ssacfg.py +22 -0
- kirin/ir/traits/symbol.py +57 -0
- kirin/ir/use.py +17 -0
- kirin/lattice/__init__.py +13 -0
- kirin/lattice/abc.py +128 -0
- kirin/lattice/empty.py +25 -0
- kirin/lattice/mixin.py +51 -0
- kirin/lowering/__init__.py +7 -0
- kirin/lowering/binding.py +65 -0
- kirin/lowering/core.py +72 -0
- kirin/lowering/dialect.py +35 -0
- kirin/lowering/dialect.pyi +183 -0
- kirin/lowering/frame.py +171 -0
- kirin/lowering/result.py +68 -0
- kirin/lowering/state.py +441 -0
- kirin/lowering/stream.py +53 -0
- kirin/passes/__init__.py +3 -0
- kirin/passes/abc.py +44 -0
- kirin/passes/aggressive/__init__.py +1 -0
- kirin/passes/aggressive/fold.py +43 -0
- kirin/passes/fold.py +45 -0
- kirin/passes/inline.py +25 -0
- kirin/passes/typeinfer.py +25 -0
- kirin/prelude.py +197 -0
- kirin/print/__init__.py +15 -0
- kirin/print/printable.py +141 -0
- kirin/print/printer.py +415 -0
- kirin/py.typed +0 -0
- kirin/registry.py +105 -0
- kirin/registry.pyi +52 -0
- kirin/rewrite/__init__.py +14 -0
- kirin/rewrite/abc.py +43 -0
- kirin/rewrite/aggressive/__init__.py +1 -0
- kirin/rewrite/aggressive/fold.py +43 -0
- kirin/rewrite/alias.py +16 -0
- kirin/rewrite/apply_type.py +47 -0
- kirin/rewrite/call2invoke.py +34 -0
- kirin/rewrite/chain.py +39 -0
- kirin/rewrite/compactify.py +288 -0
- kirin/rewrite/cse.py +48 -0
- kirin/rewrite/dce.py +19 -0
- kirin/rewrite/fixpoint.py +34 -0
- kirin/rewrite/fold.py +57 -0
- kirin/rewrite/getfield.py +21 -0
- kirin/rewrite/getitem.py +37 -0
- kirin/rewrite/inline.py +143 -0
- kirin/rewrite/result.py +15 -0
- kirin/rewrite/walk.py +83 -0
- kirin/rewrite/wrap_const.py +55 -0
- kirin/source.py +21 -0
- kirin/symbol_table.py +27 -0
- kirin/types.py +34 -0
- kirin/worklist.py +30 -0
- kirin_toolchain-0.13.0.dist-info/METADATA +42 -0
- kirin_toolchain-0.13.0.dist-info/RECORD +225 -0
- kirin_toolchain-0.13.0.dist-info/WHEEL +4 -0
- kirin_toolchain-0.13.0.dist-info/licenses/LICENSE +234 -0
kirin/decl/info.py
ADDED
@@ -0,0 +1,346 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from types import GenericAlias
|
3
|
+
from typing import Any, Callable, Optional
|
4
|
+
from functools import cached_property
|
5
|
+
from dataclasses import MISSING, field, dataclass
|
6
|
+
|
7
|
+
from kirin import types
|
8
|
+
from kirin.ir import Block, Region, Attribute
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass
|
12
|
+
class Field:
|
13
|
+
name: Optional[str] = field(default=None, init=False)
|
14
|
+
annotation: Any = field(default=None, init=False)
|
15
|
+
kw_only: bool
|
16
|
+
alias: Optional[str]
|
17
|
+
|
18
|
+
__class_getitem__ = classmethod(GenericAlias)
|
19
|
+
|
20
|
+
@abstractmethod
|
21
|
+
def has_no_default(self) -> bool: ...
|
22
|
+
|
23
|
+
|
24
|
+
@dataclass
|
25
|
+
class AttributeField(Field):
|
26
|
+
default: Any
|
27
|
+
init: bool
|
28
|
+
repr: bool
|
29
|
+
default_factory: Optional[Callable[[], Attribute]]
|
30
|
+
type: types.TypeAttribute
|
31
|
+
pytype: bool = False
|
32
|
+
"if `True`, annotation is a python type hint instead of `TypeAttribute`"
|
33
|
+
|
34
|
+
def has_no_default(self):
|
35
|
+
return self.default is MISSING and self.default_factory is None
|
36
|
+
|
37
|
+
|
38
|
+
def attribute(
|
39
|
+
type: types.TypeAttribute = types.Any,
|
40
|
+
*,
|
41
|
+
init: bool = True,
|
42
|
+
repr: bool = True,
|
43
|
+
default: Any = MISSING,
|
44
|
+
default_factory: Optional[Callable[[], Any]] = None,
|
45
|
+
kw_only: bool = True,
|
46
|
+
alias: Optional[str] = None,
|
47
|
+
) -> Any:
|
48
|
+
if kw_only is False:
|
49
|
+
raise TypeError("attribute fields must be keyword-only")
|
50
|
+
|
51
|
+
return AttributeField(
|
52
|
+
type=type,
|
53
|
+
init=init,
|
54
|
+
repr=repr,
|
55
|
+
default=default,
|
56
|
+
default_factory=default_factory,
|
57
|
+
kw_only=kw_only,
|
58
|
+
alias=alias,
|
59
|
+
)
|
60
|
+
|
61
|
+
|
62
|
+
@dataclass
|
63
|
+
class ArgumentField(Field):
|
64
|
+
type: types.TypeAttribute
|
65
|
+
"""type of the argument, will be used in validation.
|
66
|
+
"""
|
67
|
+
print: bool = True
|
68
|
+
"""if `True`, this argument name is printed in the signature.
|
69
|
+
"""
|
70
|
+
group: bool = False # NOTE: this cannot be set by user
|
71
|
+
"""if `True`, this argument is annotated with Tuple[SSAValue, ...]
|
72
|
+
"""
|
73
|
+
|
74
|
+
def has_no_default(self):
|
75
|
+
return True
|
76
|
+
|
77
|
+
|
78
|
+
# NOTE: argument must appear in init and repr
|
79
|
+
def argument(
|
80
|
+
type: types.TypeAttribute = types.Any,
|
81
|
+
*,
|
82
|
+
print: bool = True,
|
83
|
+
kw_only: bool = False,
|
84
|
+
alias: Optional[str] = None,
|
85
|
+
) -> Any:
|
86
|
+
"""Field specifier for arguments.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
type(TypeAttribute): type of the argument, will be used in validation.
|
90
|
+
print(bool): if `True`, this argument name is printed in the signature.
|
91
|
+
kw_only(bool): if `True`, this argument is keyword-only.
|
92
|
+
alias(Optional[str]): an alias for the argument name in the `__init__` method.
|
93
|
+
"""
|
94
|
+
return ArgumentField(
|
95
|
+
type=type,
|
96
|
+
print=print,
|
97
|
+
kw_only=kw_only,
|
98
|
+
alias=alias,
|
99
|
+
)
|
100
|
+
|
101
|
+
|
102
|
+
@dataclass
|
103
|
+
class ResultField(Field):
|
104
|
+
init: bool
|
105
|
+
repr: bool
|
106
|
+
type: types.TypeAttribute = field(default_factory=types.AnyType)
|
107
|
+
|
108
|
+
def has_no_default(self):
|
109
|
+
return True
|
110
|
+
|
111
|
+
|
112
|
+
def result(
|
113
|
+
type: types.TypeAttribute = types.Any,
|
114
|
+
*,
|
115
|
+
# NOTE: init is false, use other hooks to set custom results
|
116
|
+
# or just mutate the statement after creation
|
117
|
+
init: bool = False,
|
118
|
+
repr: bool = True,
|
119
|
+
kw_only: bool = True,
|
120
|
+
alias: Optional[str] = None,
|
121
|
+
) -> Any:
|
122
|
+
"""Field specifier for results.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
type(TypeAttribute): type of the result.
|
126
|
+
init(bool): if `True`, this result field is included in the `__init__` method.
|
127
|
+
repr(bool): if `True`, this result field is included in the `__repr__` and pretty printing.
|
128
|
+
kw_only(bool): if `True`, this result field is keyword-only.
|
129
|
+
alias(Optional[str]): an alias for the result field name in the `__init__` method.
|
130
|
+
"""
|
131
|
+
if kw_only is False: # for linting
|
132
|
+
raise TypeError("result fields must be keyword-only")
|
133
|
+
|
134
|
+
if init is True:
|
135
|
+
raise TypeError("result fields cannot appear in __init__")
|
136
|
+
|
137
|
+
return ResultField(
|
138
|
+
type=type,
|
139
|
+
init=init,
|
140
|
+
repr=repr,
|
141
|
+
kw_only=kw_only,
|
142
|
+
alias=alias,
|
143
|
+
)
|
144
|
+
|
145
|
+
|
146
|
+
@dataclass
|
147
|
+
class RegionField(Field):
|
148
|
+
init: bool
|
149
|
+
repr: bool
|
150
|
+
multi: bool
|
151
|
+
default_factory: Callable[[], Region]
|
152
|
+
|
153
|
+
def has_no_default(self):
|
154
|
+
return False
|
155
|
+
|
156
|
+
|
157
|
+
def region(
|
158
|
+
*,
|
159
|
+
init: bool = True, # so we can use the default_factory
|
160
|
+
repr: bool = True,
|
161
|
+
kw_only: bool = True,
|
162
|
+
alias: Optional[str] = None,
|
163
|
+
multi: bool = False,
|
164
|
+
default_factory: Callable[[], Region] = Region,
|
165
|
+
) -> Any:
|
166
|
+
"""Field specifier for regions.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
init(bool): if `True`, this region field is included in the `__init__` method.
|
170
|
+
repr(bool): if `True`, this region field is included in the `__repr__` and pretty printing.
|
171
|
+
kw_only(bool): if `True`, this region field is keyword-only.
|
172
|
+
alias(Optional[str]): an alias for the region field name in the `__init__` method.
|
173
|
+
multi(bool): if `True`, this region can contain multiple blocks.
|
174
|
+
default_factory(Callable[[], Region]): a factory function to create a default region.
|
175
|
+
"""
|
176
|
+
if kw_only is False:
|
177
|
+
raise TypeError("region fields must be keyword-only")
|
178
|
+
|
179
|
+
return RegionField(
|
180
|
+
init=init,
|
181
|
+
repr=repr,
|
182
|
+
kw_only=kw_only,
|
183
|
+
alias=alias,
|
184
|
+
multi=multi,
|
185
|
+
default_factory=default_factory,
|
186
|
+
)
|
187
|
+
|
188
|
+
|
189
|
+
@dataclass
|
190
|
+
class BlockField(Field):
|
191
|
+
init: bool
|
192
|
+
repr: bool
|
193
|
+
default_factory: Callable[[], Block]
|
194
|
+
|
195
|
+
def has_no_default(self):
|
196
|
+
return False
|
197
|
+
|
198
|
+
|
199
|
+
def block(
|
200
|
+
*,
|
201
|
+
init: bool = True,
|
202
|
+
repr: bool = True,
|
203
|
+
kw_only: bool = True,
|
204
|
+
alias: Optional[str] = None,
|
205
|
+
default_factory: Callable[[], Block] = Block,
|
206
|
+
) -> Any:
|
207
|
+
"""Field specifier for blocks.
|
208
|
+
|
209
|
+
Args:
|
210
|
+
init(bool): if `True`, this block field is included in the `__init__` method.
|
211
|
+
repr(bool): if `True`, this block field is included in the `__repr__` and pretty printing.
|
212
|
+
kw_only(bool): if `True`, this block field is keyword-only.
|
213
|
+
alias(Optional[str]): an alias for the block field name in the `__init__` method.
|
214
|
+
default_factory(Callable[[], Block]): a factory function to create a default block.
|
215
|
+
"""
|
216
|
+
if kw_only is False:
|
217
|
+
raise TypeError("block fields must be keyword-only")
|
218
|
+
|
219
|
+
return BlockField(
|
220
|
+
init=init,
|
221
|
+
repr=repr,
|
222
|
+
kw_only=kw_only,
|
223
|
+
alias=alias,
|
224
|
+
default_factory=default_factory,
|
225
|
+
)
|
226
|
+
|
227
|
+
|
228
|
+
@dataclass
|
229
|
+
class StatementFields:
|
230
|
+
std_args: dict[str, ArgumentField] = field(default_factory=dict)
|
231
|
+
"""standard arguments of the statement."""
|
232
|
+
kw_args: dict[str, ArgumentField] = field(default_factory=dict)
|
233
|
+
"""keyword-only arguments of the statement."""
|
234
|
+
results: dict[str, ResultField] = field(default_factory=dict)
|
235
|
+
"""results of the statement."""
|
236
|
+
regions: dict[str, RegionField] = field(default_factory=dict)
|
237
|
+
"""regions of the statement."""
|
238
|
+
blocks: dict[str, BlockField] = field(default_factory=dict)
|
239
|
+
"""blocks of the statement."""
|
240
|
+
attributes: dict[str, AttributeField] = field(default_factory=dict)
|
241
|
+
"""attributes of the statement."""
|
242
|
+
|
243
|
+
class Args:
|
244
|
+
def __init__(self, fields: "StatementFields"):
|
245
|
+
self.fields = fields
|
246
|
+
|
247
|
+
def __len__(self):
|
248
|
+
return len(self.fields.std_args) + len(self.fields.kw_args)
|
249
|
+
|
250
|
+
def __getitem__(self, name):
|
251
|
+
if (value := self.fields.std_args.get(name)) is not None:
|
252
|
+
return value
|
253
|
+
elif (value := self.fields.kw_args.get(name)) is not None:
|
254
|
+
return value
|
255
|
+
raise KeyError(name)
|
256
|
+
|
257
|
+
def __setitem__(self, name: str, value: ArgumentField):
|
258
|
+
if value.kw_only:
|
259
|
+
self.fields.kw_args[name] = value
|
260
|
+
else:
|
261
|
+
self.fields.std_args[name] = value
|
262
|
+
|
263
|
+
def __contains__(self, name):
|
264
|
+
return name in self.fields.std_args or name in self.fields.kw_args
|
265
|
+
|
266
|
+
def values(self):
|
267
|
+
yield from self.fields.std_args.values()
|
268
|
+
yield from self.fields.kw_args.values()
|
269
|
+
|
270
|
+
def items(self):
|
271
|
+
yield from self.fields.std_args.items()
|
272
|
+
yield from self.fields.kw_args.items()
|
273
|
+
|
274
|
+
def keys(self):
|
275
|
+
yield from self.fields.std_args.keys()
|
276
|
+
yield from self.fields.kw_args.keys()
|
277
|
+
|
278
|
+
@property
|
279
|
+
def args(self):
|
280
|
+
"""iterable of all argument fields."""
|
281
|
+
return self.Args(self)
|
282
|
+
|
283
|
+
@classmethod
|
284
|
+
def from_fields(cls, fields: dict[str, Field]):
|
285
|
+
ret = cls()
|
286
|
+
for name, f in fields.items():
|
287
|
+
ret[name] = f
|
288
|
+
return ret
|
289
|
+
|
290
|
+
def __contains__(self, name):
|
291
|
+
return (
|
292
|
+
name in self.args
|
293
|
+
or name in self.results
|
294
|
+
or name in self.regions
|
295
|
+
or name in self.blocks
|
296
|
+
or name in self.attributes
|
297
|
+
)
|
298
|
+
|
299
|
+
def __setitem__(self, name, value):
|
300
|
+
if isinstance(value, ArgumentField):
|
301
|
+
self.args[name] = value
|
302
|
+
elif isinstance(value, ResultField):
|
303
|
+
self.results[name] = value
|
304
|
+
elif isinstance(value, RegionField):
|
305
|
+
self.regions[name] = value
|
306
|
+
elif isinstance(value, BlockField):
|
307
|
+
self.blocks[name] = value
|
308
|
+
elif isinstance(value, AttributeField):
|
309
|
+
self.attributes[name] = value
|
310
|
+
else:
|
311
|
+
raise TypeError(f"unknown field type {value}")
|
312
|
+
|
313
|
+
def __iter__(self):
|
314
|
+
yield from self.args.values()
|
315
|
+
yield from self.kw_args.values()
|
316
|
+
yield from self.results.values()
|
317
|
+
yield from self.regions.values()
|
318
|
+
yield from self.blocks.values()
|
319
|
+
yield from self.attributes.values()
|
320
|
+
|
321
|
+
def __len__(self):
|
322
|
+
return (
|
323
|
+
len(self.args)
|
324
|
+
+ len(self.results)
|
325
|
+
+ len(self.regions)
|
326
|
+
+ len(self.blocks)
|
327
|
+
+ len(self.attributes)
|
328
|
+
)
|
329
|
+
|
330
|
+
@cached_property
|
331
|
+
def attr_or_props(self):
|
332
|
+
return set(self.attributes.keys())
|
333
|
+
|
334
|
+
@cached_property
|
335
|
+
def required_names(self):
|
336
|
+
"""set of all fields that do not have a default value."""
|
337
|
+
return set(
|
338
|
+
list(self.args.keys())
|
339
|
+
+ [name for name, f in self.attributes.items() if f.has_no_default()]
|
340
|
+
+ [name for name, f in self.blocks.items() if f.has_no_default()]
|
341
|
+
+ [name for name, f in self.regions.items() if f.has_no_default()]
|
342
|
+
)
|
343
|
+
|
344
|
+
@cached_property
|
345
|
+
def group_arg_names(self):
|
346
|
+
return set([name for name, f in self.args.items() if f.group])
|
@@ -0,0 +1,157 @@
|
|
1
|
+
import re
|
2
|
+
import sys
|
3
|
+
import inspect
|
4
|
+
import dataclasses
|
5
|
+
from types import ModuleType
|
6
|
+
from typing import Callable, get_args
|
7
|
+
from dataclasses import KW_ONLY
|
8
|
+
|
9
|
+
from beartype.door import is_subhint
|
10
|
+
|
11
|
+
from kirin import ir, types
|
12
|
+
|
13
|
+
from .base import BaseModifier
|
14
|
+
from .info import Field, ArgumentField, AttributeField, StatementFields, argument
|
15
|
+
|
16
|
+
|
17
|
+
class ScanFields(BaseModifier):
|
18
|
+
_FIELDS = "__kirin_stmt_fields"
|
19
|
+
# String regex that string annotations for ClassVar or InitVar must match.
|
20
|
+
# Allows "identifier.identifier[" or "identifier[".
|
21
|
+
# https://bugs.python.org/issue33453 for details.
|
22
|
+
_MODULE_IDENTIFIER_RE = re.compile(r"^(?:\s*(\w+)\s*\.)?\s*(\w+)")
|
23
|
+
|
24
|
+
def scan_fields(self):
|
25
|
+
self._scan_base_fields()
|
26
|
+
self._scan_annotations()
|
27
|
+
setattr(self.cls, self._FIELDS, self.fields)
|
28
|
+
return
|
29
|
+
|
30
|
+
def _scan_base_fields(self):
|
31
|
+
# let's just assume dict preserve insertion order in python 3.7+
|
32
|
+
for b in self.cls.__mro__[-1:0:-1]: # taken from dataclass impl
|
33
|
+
base_fields: StatementFields | None = getattr(b, self._FIELDS, None)
|
34
|
+
if base_fields is not None:
|
35
|
+
self.has_statement_bases = True
|
36
|
+
for f in base_fields:
|
37
|
+
assert f.name is not None, "field name must be set"
|
38
|
+
self.fields[f.name] = f
|
39
|
+
|
40
|
+
def _scan_annotations(self):
|
41
|
+
cls_fields: list[Field] = []
|
42
|
+
cls_annotations = inspect.get_annotations(self.cls, eval_str=True)
|
43
|
+
for name, typ in cls_annotations.items():
|
44
|
+
# See if this is a marker to change the value of kw_only.
|
45
|
+
if self._is_kw_only(typ) or (
|
46
|
+
isinstance(typ, str)
|
47
|
+
and self._is_type(typ, dataclasses, KW_ONLY, self._is_kw_only)
|
48
|
+
):
|
49
|
+
if self.KW_ONLY_seen:
|
50
|
+
raise TypeError(
|
51
|
+
f"{name!r} is KW_ONLY, but KW_ONLY "
|
52
|
+
"has already been specified"
|
53
|
+
)
|
54
|
+
self.KW_ONLY_seen = True
|
55
|
+
self.kw_only = True
|
56
|
+
else:
|
57
|
+
cls_fields.append(self._get_field(name, typ))
|
58
|
+
|
59
|
+
for f in cls_fields:
|
60
|
+
name: str = f.name # type: ignore # name has been set
|
61
|
+
self.fields[name] = f
|
62
|
+
if hasattr(self.cls, name):
|
63
|
+
# remove the field from the class
|
64
|
+
# unlike dataclass, we don't actually
|
65
|
+
# store any values in the class, they
|
66
|
+
# are stored inside the IR node.
|
67
|
+
delattr(self.cls, name)
|
68
|
+
|
69
|
+
def _get_field(self, name: str, typ):
|
70
|
+
"""Return a Field object for this field name and type."""
|
71
|
+
guess = self._guess_type(typ)
|
72
|
+
default = getattr(self.cls, name, dataclasses.MISSING)
|
73
|
+
if isinstance(default, Field):
|
74
|
+
f = default
|
75
|
+
# no default descriptor, create a new one
|
76
|
+
elif is_subhint(typ, ir.SSAValue) or is_subhint(typ, tuple[ir.SSAValue, ...]):
|
77
|
+
f: Field = (
|
78
|
+
argument()
|
79
|
+
) # only argument can have default, others must use field specifiers
|
80
|
+
elif typ is ir.ResultValue:
|
81
|
+
raise ValueError(
|
82
|
+
f"expect field specifiers for `ir.ResultValue` fields: {name}"
|
83
|
+
)
|
84
|
+
elif typ is ir.Region:
|
85
|
+
raise ValueError(f"expect field specifiers for `ir.Region` fields: {name}")
|
86
|
+
elif typ is ir.Block:
|
87
|
+
raise ValueError(f"expect field specifiers for `ir.Block` fields: {name}")
|
88
|
+
else:
|
89
|
+
# could be a wrong SSAValue field, e.g list[SSAValue], try check args
|
90
|
+
if typ_args := get_args(typ):
|
91
|
+
if any(is_subhint(arg, ir.SSAValue) for arg in typ_args):
|
92
|
+
raise ValueError(
|
93
|
+
f"unsupported SSAValue field: {name},"
|
94
|
+
f" expect `SSAValue` or `tuple[SSAValue, ...]`, got {typ}"
|
95
|
+
)
|
96
|
+
raise ValueError(f"expect field specifiers for attribute fields: {name}")
|
97
|
+
|
98
|
+
f.name = name
|
99
|
+
f.annotation = typ
|
100
|
+
self._post_init_field(f, guess)
|
101
|
+
return f
|
102
|
+
|
103
|
+
def _post_init_field(self, f: Field, guess: type | None):
|
104
|
+
if isinstance(f, ArgumentField) and is_subhint(guess, tuple[ir.SSAValue, ...]):
|
105
|
+
f.group = True
|
106
|
+
# try to narrow the type based on the guess
|
107
|
+
elif isinstance(f, AttributeField):
|
108
|
+
if guess and not is_subhint(
|
109
|
+
guess, ir.Attribute
|
110
|
+
): # not specified, and using python type
|
111
|
+
if f.type is types.Any: # not set or too generic
|
112
|
+
f.type = types.hint2type(guess)
|
113
|
+
f.pytype = True
|
114
|
+
|
115
|
+
@staticmethod
|
116
|
+
def _is_kw_only(a_type):
|
117
|
+
return a_type is KW_ONLY
|
118
|
+
|
119
|
+
def _is_type(
|
120
|
+
self,
|
121
|
+
annotation: type | str,
|
122
|
+
obj_module: ModuleType,
|
123
|
+
obj_type: type,
|
124
|
+
is_type_predicate: Callable[[type], bool],
|
125
|
+
):
|
126
|
+
"""Given a type annotation string, does it refer to `obj_type` in
|
127
|
+
`obj_module`? For example, when checking that annotation denotes a
|
128
|
+
`ClassVar`, then `obj_module` is typing, and a_type is
|
129
|
+
`typing.ClassVar`.
|
130
|
+
|
131
|
+
Taken from dataclasses.py/is_type.
|
132
|
+
"""
|
133
|
+
guess = self._guess_type(annotation)
|
134
|
+
if guess is not None:
|
135
|
+
return guess.__module__ is obj_module and is_type_predicate(guess)
|
136
|
+
return False
|
137
|
+
|
138
|
+
def _guess_type(self, annotation: type | str) -> type | None:
|
139
|
+
"""Guess the type/hint object from a string annotation."""
|
140
|
+
if not isinstance(annotation, str):
|
141
|
+
return annotation
|
142
|
+
|
143
|
+
match = self._MODULE_IDENTIFIER_RE.match(annotation)
|
144
|
+
ns = None
|
145
|
+
if match:
|
146
|
+
module_name = match.group(1)
|
147
|
+
if not module_name:
|
148
|
+
# No module name, assume the class's module did
|
149
|
+
# "from dataclasses import InitVar".
|
150
|
+
ns = sys.modules.get(self.cls.__module__).__dict__
|
151
|
+
else:
|
152
|
+
# Look up module_name in the class's module.
|
153
|
+
if self.cls_module:
|
154
|
+
ns = self.cls_module.__dict__.get(module_name).__dict__
|
155
|
+
if ns:
|
156
|
+
return ns.get(match.group(2))
|
157
|
+
return None
|
kirin/decl/verify.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
import inspect
|
2
|
+
import textwrap
|
3
|
+
|
4
|
+
from beartype.door import is_subhint
|
5
|
+
|
6
|
+
from kirin import ir
|
7
|
+
|
8
|
+
from .base import BaseModifier
|
9
|
+
from .info import Field, ResultField, ArgumentField
|
10
|
+
|
11
|
+
|
12
|
+
class Verify(BaseModifier):
|
13
|
+
RESERVED_NAMES = {
|
14
|
+
"name",
|
15
|
+
"traits",
|
16
|
+
"dialect",
|
17
|
+
"args",
|
18
|
+
"parent",
|
19
|
+
"parent_node",
|
20
|
+
"parent_region",
|
21
|
+
"parent_block",
|
22
|
+
"next_stmt",
|
23
|
+
"prev_stmt",
|
24
|
+
"results",
|
25
|
+
"regions",
|
26
|
+
"successors",
|
27
|
+
"attributes",
|
28
|
+
}
|
29
|
+
|
30
|
+
def verify_mro(self):
|
31
|
+
if not issubclass(self.cls, ir.Statement):
|
32
|
+
raise TypeError(
|
33
|
+
f"expected {self.cls.__name__} to be a subclass of ir.Statement"
|
34
|
+
)
|
35
|
+
|
36
|
+
def verify_fields(self):
|
37
|
+
# Do we have any Field members that don't also have annotations?
|
38
|
+
cls_annotations = inspect.get_annotations(self.cls)
|
39
|
+
for name, value in self.cls.__dict__.items():
|
40
|
+
if isinstance(value, Field) and name not in cls_annotations:
|
41
|
+
raise ValueError(f"{name!r} is a field but has no type annotation")
|
42
|
+
|
43
|
+
for f in self.fields:
|
44
|
+
if f.name in self.RESERVED_NAMES:
|
45
|
+
raise ValueError(f"{f.name!r} is a reserved name")
|
46
|
+
|
47
|
+
if isinstance(f, ArgumentField):
|
48
|
+
if not (
|
49
|
+
is_subhint(f.annotation, ir.SSAValue)
|
50
|
+
or is_subhint(f.annotation, tuple[ir.SSAValue, ...])
|
51
|
+
):
|
52
|
+
raise ValueError(
|
53
|
+
f"{f.name!r} is an argument field but has an invalid type annotation"
|
54
|
+
)
|
55
|
+
|
56
|
+
if is_subhint(f.annotation, ir.ResultValue):
|
57
|
+
raise ValueError(
|
58
|
+
textwrap.dedent(
|
59
|
+
f"{f.name!r} is an argument field but has an invalid type annotation {f.annotation}"
|
60
|
+
" (did you mean to use `info.result` instead?)"
|
61
|
+
)
|
62
|
+
)
|
63
|
+
|
64
|
+
if isinstance(f, ResultField) and not is_subhint(
|
65
|
+
f.annotation, ir.ResultValue
|
66
|
+
):
|
67
|
+
raise ValueError(
|
68
|
+
f"{f.name!r} is a result field but has an invalid type annotation"
|
69
|
+
)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
"""Built-in dialects for Kirin.
|
2
|
+
|
3
|
+
This module contains the built-in dialects for Kirin. Each dialect is an
|
4
|
+
instance of the `Dialect` class. Each submodule contains a `dialect` variable
|
5
|
+
that is an instance of the corresponding `Dialect` class.
|
6
|
+
|
7
|
+
The modules can be directly used as dialects. For example, you can write
|
8
|
+
|
9
|
+
```python
|
10
|
+
from kirin.dialects import py, func
|
11
|
+
```
|
12
|
+
|
13
|
+
to import the Python and function dialects.
|
14
|
+
"""
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from kirin import ir
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from kirin.ir import Statement
|
7
|
+
from kirin.print.printer import Printer
|
8
|
+
|
9
|
+
|
10
|
+
def pprint_calllike(
|
11
|
+
invoke_or_call: "Statement", callee: str, printer: "Printer"
|
12
|
+
) -> None:
|
13
|
+
with printer.rich(style="red"):
|
14
|
+
printer.print_name(invoke_or_call)
|
15
|
+
printer.plain_print(" ")
|
16
|
+
|
17
|
+
n_total = len(invoke_or_call.args)
|
18
|
+
printer.plain_print(callee)
|
19
|
+
if (inputs := getattr(invoke_or_call, "inputs", None)) is None:
|
20
|
+
raise ValueError(f"{invoke_or_call} does not have inputs")
|
21
|
+
|
22
|
+
if not isinstance(inputs, tuple):
|
23
|
+
raise ValueError(f"inputs of {invoke_or_call} is not a tuple")
|
24
|
+
|
25
|
+
if (kwargs := getattr(invoke_or_call, "kwargs", None)) is None:
|
26
|
+
raise ValueError(f"{invoke_or_call} does not have kwargs")
|
27
|
+
|
28
|
+
if not isinstance(kwargs, tuple):
|
29
|
+
raise ValueError(f"kwargs of {invoke_or_call} is not a tuple")
|
30
|
+
|
31
|
+
positional = inputs[: n_total - len(kwargs)]
|
32
|
+
kwargs = dict(
|
33
|
+
zip(
|
34
|
+
kwargs,
|
35
|
+
inputs[n_total - len(kwargs) :],
|
36
|
+
)
|
37
|
+
)
|
38
|
+
|
39
|
+
printer.plain_print("(")
|
40
|
+
printer.print_seq(positional)
|
41
|
+
if kwargs and positional:
|
42
|
+
printer.plain_print(", ")
|
43
|
+
printer.print_mapping(kwargs, delim=", ")
|
44
|
+
printer.plain_print(")")
|
45
|
+
|
46
|
+
with printer.rich(style="comment"):
|
47
|
+
printer.plain_print(" : ")
|
48
|
+
printer.print_seq(
|
49
|
+
[result.type for result in invoke_or_call._results],
|
50
|
+
delim=", ",
|
51
|
+
)
|
52
|
+
if trait := invoke_or_call.get_trait(ir.MaybePure):
|
53
|
+
printer.plain_print(f" maybe_pure={trait.is_pure(invoke_or_call)}")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"""Control flow dialect.
|
2
|
+
|
3
|
+
This dialect provides a low-level control flow representation.
|
4
|
+
|
5
|
+
This dialect does not provide any lowering strategies, to lowering
|
6
|
+
a Python AST to this dialect, use the `kirin.dialects.lowering.cf` dialect
|
7
|
+
with this dialect.
|
8
|
+
"""
|
9
|
+
|
10
|
+
from kirin.dialects.cf import (
|
11
|
+
emit as emit,
|
12
|
+
constprop as constprop,
|
13
|
+
typeinfer as typeinfer,
|
14
|
+
)
|
15
|
+
from kirin.dialects.cf.stmts import (
|
16
|
+
Branch as Branch,
|
17
|
+
ConditionalBranch as ConditionalBranch,
|
18
|
+
)
|
19
|
+
from kirin.dialects.cf.interp import CfInterpreter as CfInterpreter
|
20
|
+
from kirin.dialects.cf.dialect import dialect as dialect
|