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,221 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from abc import ABC
|
|
3
|
+
from collections.abc import Hashable
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import TYPE_CHECKING, Generic, TypeVar
|
|
6
|
+
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
9
|
+
from guppylang_internals.ast_util import AstNode, name_nodes_in_ast
|
|
10
|
+
from guppylang_internals.nodes import (
|
|
11
|
+
ComptimeExpr,
|
|
12
|
+
DesugaredArrayComp,
|
|
13
|
+
DesugaredGenerator,
|
|
14
|
+
DesugaredGeneratorExpr,
|
|
15
|
+
DesugaredListComp,
|
|
16
|
+
NestedFunctionDef,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from guppylang_internals.cfg.cfg import BaseCFG
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Type variable for ids of entities which we may wish to track during program analysis
|
|
24
|
+
# (generally ids for program variables or parts thereof)
|
|
25
|
+
VId = TypeVar("VId", bound=Hashable)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class VariableStats(Generic[VId]):
|
|
30
|
+
"""Stores variable usage information for a basic block."""
|
|
31
|
+
|
|
32
|
+
# Variables that are assigned in the BB
|
|
33
|
+
assigned: dict[VId, AstNode] = field(default_factory=dict)
|
|
34
|
+
|
|
35
|
+
# The (external) variables used in the BB, i.e. usages of variables that are
|
|
36
|
+
# created in the BB are not included here.
|
|
37
|
+
used: dict[VId, AstNode] = field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
BBStatement = (
|
|
41
|
+
ast.Assign
|
|
42
|
+
| ast.AugAssign
|
|
43
|
+
| ast.AnnAssign
|
|
44
|
+
| ast.Expr
|
|
45
|
+
| ast.Return
|
|
46
|
+
| NestedFunctionDef
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(eq=False) # Disable equality to recover hash from `object`
|
|
51
|
+
class BB(ABC):
|
|
52
|
+
"""A basic block in a control flow graph."""
|
|
53
|
+
|
|
54
|
+
idx: int
|
|
55
|
+
|
|
56
|
+
# Pointer to the CFG that contains this node
|
|
57
|
+
containing_cfg: "BaseCFG[Self]"
|
|
58
|
+
|
|
59
|
+
# AST statements contained in this BB
|
|
60
|
+
statements: list[BBStatement] = field(default_factory=list)
|
|
61
|
+
|
|
62
|
+
# Predecessor and successor BBs
|
|
63
|
+
predecessors: list[Self] = field(default_factory=list)
|
|
64
|
+
successors: list[Self] = field(default_factory=list)
|
|
65
|
+
|
|
66
|
+
# Whether this BB is reachable from the entry
|
|
67
|
+
reachable: bool = False
|
|
68
|
+
|
|
69
|
+
# Dummy predecessors and successors that correspond to branches that are provably
|
|
70
|
+
# never taken. For example, `if False: ...` statements emit only dummy control-flow
|
|
71
|
+
# links.
|
|
72
|
+
dummy_predecessors: list[Self] = field(default_factory=list)
|
|
73
|
+
dummy_successors: list[Self] = field(default_factory=list)
|
|
74
|
+
|
|
75
|
+
# If the BB has multiple successors, we need a predicate to decide to which one to
|
|
76
|
+
# jump to
|
|
77
|
+
branch_pred: ast.expr | None = None
|
|
78
|
+
|
|
79
|
+
# Information about assigned/used variables in the BB
|
|
80
|
+
_vars: VariableStats[str] | None = None
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def vars(self) -> VariableStats[str]:
|
|
84
|
+
"""Returns variable usage information for this BB.
|
|
85
|
+
|
|
86
|
+
Note that `compute_variable_stats` must be called before this property can be
|
|
87
|
+
accessed.
|
|
88
|
+
"""
|
|
89
|
+
assert self._vars is not None
|
|
90
|
+
return self._vars
|
|
91
|
+
|
|
92
|
+
def compute_variable_stats(self) -> VariableStats[str]:
|
|
93
|
+
"""Determines which variables are assigned/used in this BB."""
|
|
94
|
+
visitor = VariableVisitor(self)
|
|
95
|
+
for s in self.statements:
|
|
96
|
+
visitor.visit(s)
|
|
97
|
+
if self.branch_pred is not None:
|
|
98
|
+
visitor.visit(self.branch_pred)
|
|
99
|
+
self._vars = visitor.stats
|
|
100
|
+
return visitor.stats
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_exit(self) -> bool:
|
|
104
|
+
"""Whether this is the exit BB."""
|
|
105
|
+
return self == self.containing_cfg.exit_bb
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class VariableVisitor(ast.NodeVisitor):
|
|
109
|
+
"""Visitor that computes used and assigned variables in a BB."""
|
|
110
|
+
|
|
111
|
+
bb: BB
|
|
112
|
+
stats: VariableStats[str]
|
|
113
|
+
|
|
114
|
+
def __init__(self, bb: BB):
|
|
115
|
+
self.bb = bb
|
|
116
|
+
self.stats = VariableStats()
|
|
117
|
+
|
|
118
|
+
def _update_used(self, node: ast.AST) -> None:
|
|
119
|
+
"""Marks the variables occurring in a statement as used.
|
|
120
|
+
|
|
121
|
+
This method should be called whenever an expression is used in the BB.
|
|
122
|
+
"""
|
|
123
|
+
for name in name_nodes_in_ast(node):
|
|
124
|
+
# Should point to first use, so also check that the name is not already
|
|
125
|
+
# contained
|
|
126
|
+
x = name.id
|
|
127
|
+
if x not in self.stats.assigned and x not in self.stats.used:
|
|
128
|
+
self.stats.used[x] = name
|
|
129
|
+
|
|
130
|
+
def visit_Name(self, node: ast.Name) -> None:
|
|
131
|
+
self._update_used(node)
|
|
132
|
+
|
|
133
|
+
def visit_Assign(self, node: ast.Assign) -> None:
|
|
134
|
+
self.visit(node.value)
|
|
135
|
+
for t in node.targets:
|
|
136
|
+
self._handle_assign_target(t, node)
|
|
137
|
+
|
|
138
|
+
def visit_AugAssign(self, node: ast.AugAssign) -> None:
|
|
139
|
+
self.visit(node.value)
|
|
140
|
+
self._update_used(node.target) # The target is also used
|
|
141
|
+
self._handle_assign_target(node.target, node)
|
|
142
|
+
|
|
143
|
+
def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
|
|
144
|
+
if node.value:
|
|
145
|
+
self.visit(node.value)
|
|
146
|
+
self._handle_assign_target(node.target, node)
|
|
147
|
+
|
|
148
|
+
def _handle_assign_target(self, lhs: ast.expr, node: ast.stmt) -> None:
|
|
149
|
+
match lhs:
|
|
150
|
+
case ast.Name(id=name):
|
|
151
|
+
self.stats.assigned[name] = node
|
|
152
|
+
case ast.Tuple(elts=elts) | ast.List(elts=elts):
|
|
153
|
+
for elt in elts:
|
|
154
|
+
self._handle_assign_target(elt, node)
|
|
155
|
+
case ast.Attribute(value=value):
|
|
156
|
+
# Setting attributes counts as a use of the value, so we do a regular
|
|
157
|
+
# visit instead of treating it like a LHS
|
|
158
|
+
self.visit(value)
|
|
159
|
+
case ast.Subscript(value=value, slice=slice):
|
|
160
|
+
# Setting subscripts counts as a use of the value in the implicit,
|
|
161
|
+
# `__setitem__` call, so we do a regular visit
|
|
162
|
+
self.visit(slice)
|
|
163
|
+
self.visit(value)
|
|
164
|
+
case ast.Starred(value=value):
|
|
165
|
+
self._handle_assign_target(value, node)
|
|
166
|
+
|
|
167
|
+
def visit_DesugaredListComp(self, node: DesugaredListComp) -> None:
|
|
168
|
+
self._handle_comprehension(node.generators, node.elt)
|
|
169
|
+
|
|
170
|
+
def visit_DesugaredArrayComp(self, node: DesugaredArrayComp) -> None:
|
|
171
|
+
self._handle_comprehension([node.generator], node.elt)
|
|
172
|
+
|
|
173
|
+
def visit_DesugaredGeneratorExpr(self, node: DesugaredGeneratorExpr) -> None:
|
|
174
|
+
self._handle_comprehension(node.generators, node.elt)
|
|
175
|
+
|
|
176
|
+
def _handle_comprehension(
|
|
177
|
+
self, generators: list[DesugaredGenerator], elt: ast.expr
|
|
178
|
+
) -> None:
|
|
179
|
+
# Names bound in the comprehension are only available inside, so we shouldn't
|
|
180
|
+
# update `self.stats` with assignments
|
|
181
|
+
inner_visitor = VariableVisitor(self.bb)
|
|
182
|
+
inner_stats = inner_visitor.stats
|
|
183
|
+
|
|
184
|
+
# The generators are evaluated left to right
|
|
185
|
+
for gen in generators:
|
|
186
|
+
inner_visitor.visit(gen.iter_assign)
|
|
187
|
+
inner_visitor.visit(gen.next_call)
|
|
188
|
+
inner_visitor._handle_assign_target(gen.target, gen.iter_assign)
|
|
189
|
+
for cond in gen.ifs:
|
|
190
|
+
inner_visitor.visit(cond)
|
|
191
|
+
inner_visitor.visit(elt)
|
|
192
|
+
|
|
193
|
+
self.stats.used |= {
|
|
194
|
+
x: n for x, n in inner_stats.used.items() if x not in self.stats.assigned
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
def visit_ComptimeExpr(self, node: ComptimeExpr) -> None:
|
|
198
|
+
# Don't look into `comptime(...)` expressions
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
def visit_NestedFunctionDef(self, node: NestedFunctionDef) -> None:
|
|
202
|
+
# In order to compute the used external variables in a nested function
|
|
203
|
+
# definition, we have to run live variable analysis first
|
|
204
|
+
from guppylang_internals.cfg.analysis import LivenessAnalysis
|
|
205
|
+
|
|
206
|
+
stats = {bb: bb.compute_variable_stats() for bb in node.cfg.bbs}
|
|
207
|
+
live = LivenessAnalysis(stats).run(node.cfg.bbs)
|
|
208
|
+
|
|
209
|
+
# Only store used *external* variables: things defined in the current BB, as
|
|
210
|
+
# well as the function name and argument names should not be included
|
|
211
|
+
assigned_before_in_bb = (
|
|
212
|
+
self.stats.assigned.keys() | {node.name} | {a.arg for a in node.args.args}
|
|
213
|
+
)
|
|
214
|
+
self.stats.used |= {
|
|
215
|
+
x: using_bb.vars.used[x]
|
|
216
|
+
for x, using_bb in live[node.cfg.entry_bb].items()
|
|
217
|
+
if x not in assigned_before_in_bb
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
# The name of the function is now assigned
|
|
221
|
+
self.stats.assigned[node.name] = node
|