guppylang-internals 0.21.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- guppylang_internals/__init__.py +3 -0
- guppylang_internals/ast_util.py +350 -0
- guppylang_internals/cfg/__init__.py +0 -0
- guppylang_internals/cfg/analysis.py +230 -0
- guppylang_internals/cfg/bb.py +221 -0
- guppylang_internals/cfg/builder.py +606 -0
- guppylang_internals/cfg/cfg.py +117 -0
- guppylang_internals/checker/__init__.py +0 -0
- guppylang_internals/checker/cfg_checker.py +388 -0
- guppylang_internals/checker/core.py +550 -0
- guppylang_internals/checker/errors/__init__.py +0 -0
- guppylang_internals/checker/errors/comptime_errors.py +106 -0
- guppylang_internals/checker/errors/generic.py +45 -0
- guppylang_internals/checker/errors/linearity.py +300 -0
- guppylang_internals/checker/errors/type_errors.py +344 -0
- guppylang_internals/checker/errors/wasm.py +34 -0
- guppylang_internals/checker/expr_checker.py +1413 -0
- guppylang_internals/checker/func_checker.py +269 -0
- guppylang_internals/checker/linearity_checker.py +821 -0
- guppylang_internals/checker/stmt_checker.py +447 -0
- guppylang_internals/compiler/__init__.py +0 -0
- guppylang_internals/compiler/cfg_compiler.py +233 -0
- guppylang_internals/compiler/core.py +613 -0
- guppylang_internals/compiler/expr_compiler.py +989 -0
- guppylang_internals/compiler/func_compiler.py +97 -0
- guppylang_internals/compiler/hugr_extension.py +224 -0
- guppylang_internals/compiler/qtm_platform_extension.py +0 -0
- guppylang_internals/compiler/stmt_compiler.py +212 -0
- guppylang_internals/decorator.py +246 -0
- guppylang_internals/definition/__init__.py +0 -0
- guppylang_internals/definition/common.py +214 -0
- guppylang_internals/definition/const.py +74 -0
- guppylang_internals/definition/custom.py +492 -0
- guppylang_internals/definition/declaration.py +171 -0
- guppylang_internals/definition/extern.py +89 -0
- guppylang_internals/definition/function.py +302 -0
- guppylang_internals/definition/overloaded.py +150 -0
- guppylang_internals/definition/parameter.py +82 -0
- guppylang_internals/definition/pytket_circuits.py +405 -0
- guppylang_internals/definition/struct.py +392 -0
- guppylang_internals/definition/traced.py +151 -0
- guppylang_internals/definition/ty.py +51 -0
- guppylang_internals/definition/value.py +115 -0
- guppylang_internals/definition/wasm.py +61 -0
- guppylang_internals/diagnostic.py +523 -0
- guppylang_internals/dummy_decorator.py +76 -0
- guppylang_internals/engine.py +295 -0
- guppylang_internals/error.py +107 -0
- guppylang_internals/experimental.py +92 -0
- guppylang_internals/ipython_inspect.py +28 -0
- guppylang_internals/nodes.py +427 -0
- guppylang_internals/py.typed +0 -0
- guppylang_internals/span.py +150 -0
- guppylang_internals/std/__init__.py +0 -0
- guppylang_internals/std/_internal/__init__.py +0 -0
- guppylang_internals/std/_internal/checker.py +573 -0
- guppylang_internals/std/_internal/compiler/__init__.py +0 -0
- guppylang_internals/std/_internal/compiler/arithmetic.py +136 -0
- guppylang_internals/std/_internal/compiler/array.py +569 -0
- guppylang_internals/std/_internal/compiler/either.py +131 -0
- guppylang_internals/std/_internal/compiler/frozenarray.py +68 -0
- guppylang_internals/std/_internal/compiler/futures.py +30 -0
- guppylang_internals/std/_internal/compiler/list.py +348 -0
- guppylang_internals/std/_internal/compiler/mem.py +13 -0
- guppylang_internals/std/_internal/compiler/option.py +78 -0
- guppylang_internals/std/_internal/compiler/prelude.py +271 -0
- guppylang_internals/std/_internal/compiler/qsystem.py +48 -0
- guppylang_internals/std/_internal/compiler/quantum.py +118 -0
- guppylang_internals/std/_internal/compiler/tket_bool.py +55 -0
- guppylang_internals/std/_internal/compiler/tket_exts.py +59 -0
- guppylang_internals/std/_internal/compiler/wasm.py +135 -0
- guppylang_internals/std/_internal/compiler.py +0 -0
- guppylang_internals/std/_internal/debug.py +95 -0
- guppylang_internals/std/_internal/util.py +271 -0
- guppylang_internals/tracing/__init__.py +0 -0
- guppylang_internals/tracing/builtins_mock.py +62 -0
- guppylang_internals/tracing/frozenlist.py +57 -0
- guppylang_internals/tracing/function.py +186 -0
- guppylang_internals/tracing/object.py +551 -0
- guppylang_internals/tracing/state.py +69 -0
- guppylang_internals/tracing/unpacking.py +194 -0
- guppylang_internals/tracing/util.py +86 -0
- guppylang_internals/tys/__init__.py +0 -0
- guppylang_internals/tys/arg.py +115 -0
- guppylang_internals/tys/builtin.py +382 -0
- guppylang_internals/tys/common.py +110 -0
- guppylang_internals/tys/const.py +114 -0
- guppylang_internals/tys/errors.py +178 -0
- guppylang_internals/tys/param.py +251 -0
- guppylang_internals/tys/parsing.py +425 -0
- guppylang_internals/tys/printing.py +174 -0
- guppylang_internals/tys/subst.py +112 -0
- guppylang_internals/tys/ty.py +876 -0
- guppylang_internals/tys/var.py +49 -0
- guppylang_internals-0.21.0.dist-info/METADATA +253 -0
- guppylang_internals-0.21.0.dist-info/RECORD +98 -0
- guppylang_internals-0.21.0.dist-info/WHEEL +4 -0
- guppylang_internals-0.21.0.dist-info/licenses/LICENCE +201 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
"""Custom AST nodes used by Guppy"""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from guppylang_internals.ast_util import AstNode
|
|
9
|
+
from guppylang_internals.tys.const import Const
|
|
10
|
+
from guppylang_internals.tys.subst import Inst
|
|
11
|
+
from guppylang_internals.tys.ty import FunctionType, StructType, TupleType, Type
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from guppylang_internals.cfg.cfg import CFG
|
|
15
|
+
from guppylang_internals.checker.cfg_checker import CheckedCFG
|
|
16
|
+
from guppylang_internals.checker.core import Place, Variable
|
|
17
|
+
from guppylang_internals.definition.common import DefId
|
|
18
|
+
from guppylang_internals.definition.struct import StructField
|
|
19
|
+
from guppylang_internals.tys.param import ConstParam
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PlaceNode(ast.expr):
|
|
23
|
+
place: "Place"
|
|
24
|
+
|
|
25
|
+
_fields = ("place",)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GlobalName(ast.Name):
|
|
29
|
+
id: str
|
|
30
|
+
def_id: "DefId"
|
|
31
|
+
|
|
32
|
+
_fields = (
|
|
33
|
+
"id",
|
|
34
|
+
"def_id",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class GenericParamValue(ast.Name):
|
|
39
|
+
id: str
|
|
40
|
+
param: "ConstParam"
|
|
41
|
+
|
|
42
|
+
_fields = (
|
|
43
|
+
"id",
|
|
44
|
+
"param",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class LocalCall(ast.expr):
|
|
49
|
+
func: ast.expr
|
|
50
|
+
args: list[ast.expr]
|
|
51
|
+
|
|
52
|
+
_fields = (
|
|
53
|
+
"func",
|
|
54
|
+
"args",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class GlobalCall(ast.expr):
|
|
59
|
+
def_id: "DefId"
|
|
60
|
+
args: list[ast.expr]
|
|
61
|
+
type_args: Inst # Inferred type arguments
|
|
62
|
+
|
|
63
|
+
_fields = (
|
|
64
|
+
"def_id",
|
|
65
|
+
"args",
|
|
66
|
+
"type_args",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TensorCall(ast.expr):
|
|
71
|
+
"""A call to a tuple of functions. Behaves like a local call, but more
|
|
72
|
+
unpacking of tuples is required at compilation"""
|
|
73
|
+
|
|
74
|
+
func: ast.expr
|
|
75
|
+
args: list[ast.expr]
|
|
76
|
+
tensor_ty: FunctionType
|
|
77
|
+
|
|
78
|
+
_fields = (
|
|
79
|
+
"func",
|
|
80
|
+
"args",
|
|
81
|
+
"tensor_ty",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class TypeApply(ast.expr):
|
|
86
|
+
value: ast.expr
|
|
87
|
+
inst: Inst
|
|
88
|
+
|
|
89
|
+
_fields = (
|
|
90
|
+
"value",
|
|
91
|
+
"inst",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PartialApply(ast.expr):
|
|
96
|
+
"""A partial function application.
|
|
97
|
+
|
|
98
|
+
This node is emitted when methods are loaded as values, since this requires
|
|
99
|
+
partially applying the `self` argument.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
func: ast.expr
|
|
103
|
+
args: list[ast.expr]
|
|
104
|
+
|
|
105
|
+
_fields = (
|
|
106
|
+
"func",
|
|
107
|
+
"args",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class FieldAccessAndDrop(ast.expr):
|
|
112
|
+
"""A field access on a struct, dropping all the remaining other fields."""
|
|
113
|
+
|
|
114
|
+
value: ast.expr
|
|
115
|
+
struct_ty: "StructType"
|
|
116
|
+
field: "StructField"
|
|
117
|
+
|
|
118
|
+
_fields = (
|
|
119
|
+
"value",
|
|
120
|
+
"struct_ty",
|
|
121
|
+
"field",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class SubscriptAccessAndDrop(ast.expr):
|
|
126
|
+
"""A subscript element access on an object, dropping all the remaining items."""
|
|
127
|
+
|
|
128
|
+
item: "Variable"
|
|
129
|
+
item_expr: ast.expr
|
|
130
|
+
getitem_expr: ast.expr
|
|
131
|
+
original_expr: ast.Subscript
|
|
132
|
+
|
|
133
|
+
_fields = ("item", "item_expr", "getitem_expr", "original_expr")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TupleAccessAndDrop(ast.expr):
|
|
137
|
+
"""A subscript element access on a tuple, dropping all the remaining items."""
|
|
138
|
+
|
|
139
|
+
value: ast.expr
|
|
140
|
+
tuple_ty: TupleType
|
|
141
|
+
index: int
|
|
142
|
+
|
|
143
|
+
_fields = ("value", "tuple_ty", "index")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class MakeIter(ast.expr):
|
|
147
|
+
"""Creates an iterator using the `__iter__` magic method.
|
|
148
|
+
|
|
149
|
+
This node is inserted in `for` loops and list comprehensions.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
value: ast.expr
|
|
153
|
+
unwrap_size_hint: bool
|
|
154
|
+
|
|
155
|
+
# Node that triggered the creation of this iterator. For example, a for loop stmt.
|
|
156
|
+
# It is not mentioned in `_fields` so that it is not visible to AST visitors
|
|
157
|
+
origin_node: ast.AST
|
|
158
|
+
|
|
159
|
+
_fields = ("value",)
|
|
160
|
+
|
|
161
|
+
def __init__(
|
|
162
|
+
self, value: ast.expr, origin_node: ast.AST, unwrap_size_hint: bool = True
|
|
163
|
+
) -> None:
|
|
164
|
+
super().__init__(value)
|
|
165
|
+
self.origin_node = origin_node
|
|
166
|
+
self.unwrap_size_hint = unwrap_size_hint
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class IterHasNext(ast.expr):
|
|
170
|
+
"""Checks if an iterator has a next element using the `__hasnext__` magic method.
|
|
171
|
+
|
|
172
|
+
This node is inserted in `for` loops and list comprehensions.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
value: ast.expr
|
|
176
|
+
|
|
177
|
+
_fields = ("value",)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class IterNext(ast.expr):
|
|
181
|
+
"""Obtains the next element of an iterator using the `__next__` magic method.
|
|
182
|
+
|
|
183
|
+
This node is inserted in `for` loops and list comprehensions.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
value: ast.expr
|
|
187
|
+
|
|
188
|
+
_fields = ("value",)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class IterEnd(ast.expr):
|
|
192
|
+
"""Finalises an iterator using the `__end__` magic method.
|
|
193
|
+
|
|
194
|
+
This node is inserted in `for` loops and list comprehensions. It is needed to
|
|
195
|
+
consume linear iterators once they are finished.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
value: ast.expr
|
|
199
|
+
|
|
200
|
+
_fields = ("value",)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class DesugaredGenerator(ast.expr):
|
|
204
|
+
"""A single desugared generator in a list comprehension.
|
|
205
|
+
|
|
206
|
+
Stores assignments of the original generator targets as well as dummy variables for
|
|
207
|
+
the iterator and hasnext test.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
iter_assign: ast.Assign
|
|
211
|
+
next_call: ast.expr
|
|
212
|
+
iter: ast.expr
|
|
213
|
+
target: ast.expr
|
|
214
|
+
ifs: list[ast.expr]
|
|
215
|
+
|
|
216
|
+
used_outer_places: "list[Place]"
|
|
217
|
+
|
|
218
|
+
_fields = (
|
|
219
|
+
"iter_assign",
|
|
220
|
+
"next_call",
|
|
221
|
+
"iter",
|
|
222
|
+
"target",
|
|
223
|
+
"ifs",
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class DesugaredGeneratorExpr(ast.expr):
|
|
228
|
+
"""A desugared generator expression."""
|
|
229
|
+
|
|
230
|
+
elt: ast.expr
|
|
231
|
+
generators: list[DesugaredGenerator]
|
|
232
|
+
|
|
233
|
+
_fields = (
|
|
234
|
+
"elt",
|
|
235
|
+
"generators",
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class DesugaredListComp(ast.expr):
|
|
240
|
+
"""A desugared list comprehension."""
|
|
241
|
+
|
|
242
|
+
elt: ast.expr
|
|
243
|
+
generators: list[DesugaredGenerator]
|
|
244
|
+
|
|
245
|
+
_fields = (
|
|
246
|
+
"elt",
|
|
247
|
+
"generators",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class DesugaredArrayComp(ast.expr):
|
|
252
|
+
"""A desugared array comprehension."""
|
|
253
|
+
|
|
254
|
+
elt: ast.expr
|
|
255
|
+
generator: DesugaredGenerator
|
|
256
|
+
length: Const
|
|
257
|
+
elt_ty: Type
|
|
258
|
+
|
|
259
|
+
_fields = (
|
|
260
|
+
"elt",
|
|
261
|
+
"generator",
|
|
262
|
+
"length",
|
|
263
|
+
"elt_ty",
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class ComptimeExpr(ast.expr):
|
|
268
|
+
"""A compile-time evaluated `py(...)` expression."""
|
|
269
|
+
|
|
270
|
+
value: ast.expr
|
|
271
|
+
|
|
272
|
+
_fields = ("value",)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class ResultExpr(ast.expr):
|
|
276
|
+
"""A `result(tag, value)` expression."""
|
|
277
|
+
|
|
278
|
+
value: ast.expr
|
|
279
|
+
base_ty: Type
|
|
280
|
+
#: Array length in case this is an array result, otherwise `None`
|
|
281
|
+
array_len: Const | None
|
|
282
|
+
tag: str
|
|
283
|
+
|
|
284
|
+
_fields = ("value", "base_ty", "array_len", "tag")
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def args(self) -> list[ast.expr]:
|
|
288
|
+
return [self.value]
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class ExitKind(Enum):
|
|
292
|
+
ExitShot = 0 # Exit the current shot
|
|
293
|
+
Panic = 1 # Panic the program ending all shots
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class PanicExpr(ast.expr):
|
|
297
|
+
"""A `panic(msg, *args)` or `exit(msg, *args)` expression ."""
|
|
298
|
+
|
|
299
|
+
kind: ExitKind
|
|
300
|
+
signal: int
|
|
301
|
+
msg: str
|
|
302
|
+
values: list[ast.expr]
|
|
303
|
+
|
|
304
|
+
_fields = ("kind", "signal", "msg", "values")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class BarrierExpr(ast.expr):
|
|
308
|
+
"""A `barrier(*args)` expression."""
|
|
309
|
+
|
|
310
|
+
args: list[ast.expr]
|
|
311
|
+
func_ty: FunctionType
|
|
312
|
+
_fields = ("args", "func_ty")
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class StateResultExpr(ast.expr):
|
|
316
|
+
"""A `state_result(tag, *args)` expression."""
|
|
317
|
+
|
|
318
|
+
tag: str
|
|
319
|
+
args: list[ast.expr]
|
|
320
|
+
func_ty: FunctionType
|
|
321
|
+
#: Array length in case this is an array result, otherwise `None`
|
|
322
|
+
array_len: Const | None
|
|
323
|
+
_fields = ("tag", "args", "func_ty", "has_array_input")
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
AnyCall = (
|
|
327
|
+
LocalCall | GlobalCall | TensorCall | BarrierExpr | ResultExpr | StateResultExpr
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class InoutReturnSentinel(ast.expr):
|
|
332
|
+
"""An invisible expression corresponding to an implicit use of borrowed vars
|
|
333
|
+
whenever a function returns."""
|
|
334
|
+
|
|
335
|
+
var: "Place | str"
|
|
336
|
+
|
|
337
|
+
_fields = ("var",)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class UnpackPattern(ast.expr):
|
|
341
|
+
"""The LHS of an unpacking assignment like `a, *bs, c = ...` or
|
|
342
|
+
`[a, *bs, c] = ...`."""
|
|
343
|
+
|
|
344
|
+
#: Patterns occurring on the left of the starred target
|
|
345
|
+
left: list[ast.expr]
|
|
346
|
+
|
|
347
|
+
#: The starred target or `None` if there is none
|
|
348
|
+
starred: ast.expr | None
|
|
349
|
+
|
|
350
|
+
#: Patterns occurring on the right of the starred target. This will be an empty list
|
|
351
|
+
#: if there is no starred target
|
|
352
|
+
right: list[ast.expr]
|
|
353
|
+
|
|
354
|
+
_fields = ("left", "starred", "right")
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class TupleUnpack(ast.expr):
|
|
358
|
+
"""The LHS of an unpacking assignment of a tuple."""
|
|
359
|
+
|
|
360
|
+
#: The (possibly starred) unpacking pattern
|
|
361
|
+
pattern: UnpackPattern
|
|
362
|
+
|
|
363
|
+
_fields = ("pattern",)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class IterableUnpack(ast.expr):
|
|
367
|
+
"""The LHS of an unpacking assignment of an iterable type."""
|
|
368
|
+
|
|
369
|
+
#: The (possibly starred) unpacking pattern
|
|
370
|
+
pattern: UnpackPattern
|
|
371
|
+
|
|
372
|
+
#: Comprehension that collects the RHS iterable into an array
|
|
373
|
+
compr: DesugaredArrayComp
|
|
374
|
+
|
|
375
|
+
#: Dummy variable that the RHS should be bound to. This variable is referenced in
|
|
376
|
+
#: `compr`
|
|
377
|
+
rhs_var: PlaceNode
|
|
378
|
+
|
|
379
|
+
# Don't mention the comprehension in _fields to avoid visitors recursing it
|
|
380
|
+
_fields = ("pattern",)
|
|
381
|
+
|
|
382
|
+
def __init__(
|
|
383
|
+
self, pattern: UnpackPattern, compr: DesugaredArrayComp, rhs_var: PlaceNode
|
|
384
|
+
) -> None:
|
|
385
|
+
super().__init__(pattern)
|
|
386
|
+
self.compr = compr
|
|
387
|
+
self.rhs_var = rhs_var
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
#: Any unpacking operation.
|
|
391
|
+
AnyUnpack = TupleUnpack | IterableUnpack
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class NestedFunctionDef(ast.FunctionDef):
|
|
395
|
+
cfg: "CFG"
|
|
396
|
+
ty: FunctionType
|
|
397
|
+
docstring: str | None
|
|
398
|
+
|
|
399
|
+
def __init__(self, cfg: "CFG", ty: FunctionType, *args: Any, **kwargs: Any) -> None:
|
|
400
|
+
super().__init__(*args, **kwargs)
|
|
401
|
+
self.cfg = cfg
|
|
402
|
+
self.ty = ty
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class CheckedNestedFunctionDef(ast.FunctionDef):
|
|
406
|
+
def_id: "DefId"
|
|
407
|
+
cfg: "CheckedCFG[Place]"
|
|
408
|
+
ty: FunctionType
|
|
409
|
+
|
|
410
|
+
#: Mapping from names to variables captured by this function, together with an AST
|
|
411
|
+
#: node witnessing a use of the captured variable in the function body.
|
|
412
|
+
captured: Mapping[str, tuple["Variable", AstNode]]
|
|
413
|
+
|
|
414
|
+
def __init__(
|
|
415
|
+
self,
|
|
416
|
+
def_id: "DefId",
|
|
417
|
+
cfg: "CheckedCFG[Place]",
|
|
418
|
+
ty: FunctionType,
|
|
419
|
+
captured: Mapping[str, tuple["Variable", AstNode]],
|
|
420
|
+
*args: Any,
|
|
421
|
+
**kwargs: Any,
|
|
422
|
+
) -> None:
|
|
423
|
+
super().__init__(*args, **kwargs)
|
|
424
|
+
self.def_id = def_id
|
|
425
|
+
self.cfg = cfg
|
|
426
|
+
self.ty = ty
|
|
427
|
+
self.captured = captured
|
|
File without changes
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Source spans representing locations in the code being compiled."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import linecache
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TypeAlias
|
|
7
|
+
|
|
8
|
+
from guppylang_internals.ast_util import get_file, get_line_offset
|
|
9
|
+
from guppylang_internals.error import InternalGuppyError
|
|
10
|
+
from guppylang_internals.ipython_inspect import normalize_ipython_dummy_files
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True, order=True)
|
|
14
|
+
class Loc:
|
|
15
|
+
"""A location in a source file."""
|
|
16
|
+
|
|
17
|
+
file: str
|
|
18
|
+
|
|
19
|
+
#: Line number starting at 1
|
|
20
|
+
line: int
|
|
21
|
+
|
|
22
|
+
#: Column number starting at 1
|
|
23
|
+
column: int
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
"""Returns the string representation of this source location."""
|
|
27
|
+
file = normalize_ipython_dummy_files(self.file)
|
|
28
|
+
return f"{file}:{self.line}:{self.column}"
|
|
29
|
+
|
|
30
|
+
def shift_left(self, cols: int) -> "Loc":
|
|
31
|
+
"""Returns a new location shifted to left by the given number of columns."""
|
|
32
|
+
assert self.column >= cols
|
|
33
|
+
return Loc(self.file, self.line, self.column - cols)
|
|
34
|
+
|
|
35
|
+
def shift_right(self, cols: int) -> "Loc":
|
|
36
|
+
"""Returns a new location shifted to right by the given number of columns."""
|
|
37
|
+
return Loc(self.file, self.line, self.column + cols)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class Span:
|
|
42
|
+
"""A continuous sequence of source code within a file."""
|
|
43
|
+
|
|
44
|
+
#: Starting location of the span (inclusive)
|
|
45
|
+
start: Loc
|
|
46
|
+
|
|
47
|
+
# Ending location of the span (exclusive)
|
|
48
|
+
end: Loc
|
|
49
|
+
|
|
50
|
+
def __post_init__(self) -> None:
|
|
51
|
+
if self.start.file != self.end.file:
|
|
52
|
+
raise InternalGuppyError("Span: Source spans multiple files")
|
|
53
|
+
if self.start > self.end:
|
|
54
|
+
raise InternalGuppyError("Span: Start after end")
|
|
55
|
+
|
|
56
|
+
def __contains__(self, x: "Span | Loc") -> bool:
|
|
57
|
+
"""Determines whether another span or location is completely contained in this
|
|
58
|
+
span."""
|
|
59
|
+
if self.file != x.file:
|
|
60
|
+
return False
|
|
61
|
+
if isinstance(x, Span):
|
|
62
|
+
return self.start <= x.start <= self.end <= x.end
|
|
63
|
+
return self.start <= x <= self.end
|
|
64
|
+
|
|
65
|
+
def __and__(self, other: "Span") -> "Span | None":
|
|
66
|
+
"""Returns the intersection with the given span or `None` if they don't
|
|
67
|
+
intersect."""
|
|
68
|
+
if self.file != other.file:
|
|
69
|
+
return None
|
|
70
|
+
if self.start > other.end or other.start > self.end:
|
|
71
|
+
return None
|
|
72
|
+
return Span(max(self.start, other.start), min(self.end, other.end))
|
|
73
|
+
|
|
74
|
+
def __len__(self) -> int:
|
|
75
|
+
"""Returns the length of a single-line span in columns.
|
|
76
|
+
|
|
77
|
+
Querying the length of multiline spans raises an `InternalGuppyError`.
|
|
78
|
+
"""
|
|
79
|
+
if self.is_multiline:
|
|
80
|
+
raise InternalGuppyError("Span: Tried to compute length of multi-line span")
|
|
81
|
+
return self.end.column - self.start.column
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def file(self) -> str:
|
|
85
|
+
"""The file containing this span."""
|
|
86
|
+
return self.start.file
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def is_multiline(self) -> bool:
|
|
90
|
+
"""Whether this source sequence spans multiple lines."""
|
|
91
|
+
return self.start.line != self.end.line
|
|
92
|
+
|
|
93
|
+
def shift_left(self, cols: int) -> "Span":
|
|
94
|
+
"""Returns a new span that is shifted to the left by the given number of
|
|
95
|
+
columns."""
|
|
96
|
+
return Span(self.start.shift_left(cols), self.end.shift_left(cols))
|
|
97
|
+
|
|
98
|
+
def shift_right(self, cols: int) -> "Span":
|
|
99
|
+
"""Returns a new span that is shifted to the right by the given number of
|
|
100
|
+
columns."""
|
|
101
|
+
return Span(self.start.shift_right(cols), self.end.shift_right(cols))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
#: Objects in the compiler that are associated with a source span
|
|
105
|
+
ToSpan: TypeAlias = ast.AST | Span
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def to_span(x: ToSpan) -> Span:
|
|
109
|
+
"""Extracts a source span from an object."""
|
|
110
|
+
if isinstance(x, Span):
|
|
111
|
+
return x
|
|
112
|
+
file, line_offset = get_file(x), get_line_offset(x)
|
|
113
|
+
assert file is not None
|
|
114
|
+
assert line_offset is not None
|
|
115
|
+
# x.lineno and line_offset both start at 1, so we have to subtract 1
|
|
116
|
+
start = Loc(file, x.lineno + line_offset - 1, x.col_offset)
|
|
117
|
+
end = Loc(
|
|
118
|
+
file,
|
|
119
|
+
(x.end_lineno or x.lineno) + line_offset - 1,
|
|
120
|
+
x.end_col_offset or x.col_offset,
|
|
121
|
+
)
|
|
122
|
+
return Span(start, end)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
#: List of source lines in a file
|
|
126
|
+
SourceLines: TypeAlias = list[str]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class SourceMap:
|
|
130
|
+
"""Map holding the source code for all files accessed by the compiler.
|
|
131
|
+
|
|
132
|
+
Can be used to look up the source code associated with a span.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
sources: dict[str, SourceLines]
|
|
136
|
+
|
|
137
|
+
def __init__(self) -> None:
|
|
138
|
+
self.sources = {}
|
|
139
|
+
|
|
140
|
+
def add_file(self, file: str, content: str | None = None) -> None:
|
|
141
|
+
"""Registers a new source file."""
|
|
142
|
+
if content is None:
|
|
143
|
+
self.sources[file] = [line.rstrip() for line in linecache.getlines(file)]
|
|
144
|
+
else:
|
|
145
|
+
self.sources[file] = content.splitlines(keepends=False)
|
|
146
|
+
|
|
147
|
+
def span_lines(self, span: Span, prefix_lines: int = 0) -> list[str]:
|
|
148
|
+
return self.sources[span.file][
|
|
149
|
+
span.start.line - prefix_lines - 1 : span.end.line
|
|
150
|
+
]
|
|
File without changes
|
|
File without changes
|