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.
Files changed (98) hide show
  1. guppylang_internals/__init__.py +3 -0
  2. guppylang_internals/ast_util.py +350 -0
  3. guppylang_internals/cfg/__init__.py +0 -0
  4. guppylang_internals/cfg/analysis.py +230 -0
  5. guppylang_internals/cfg/bb.py +221 -0
  6. guppylang_internals/cfg/builder.py +606 -0
  7. guppylang_internals/cfg/cfg.py +117 -0
  8. guppylang_internals/checker/__init__.py +0 -0
  9. guppylang_internals/checker/cfg_checker.py +388 -0
  10. guppylang_internals/checker/core.py +550 -0
  11. guppylang_internals/checker/errors/__init__.py +0 -0
  12. guppylang_internals/checker/errors/comptime_errors.py +106 -0
  13. guppylang_internals/checker/errors/generic.py +45 -0
  14. guppylang_internals/checker/errors/linearity.py +300 -0
  15. guppylang_internals/checker/errors/type_errors.py +344 -0
  16. guppylang_internals/checker/errors/wasm.py +34 -0
  17. guppylang_internals/checker/expr_checker.py +1413 -0
  18. guppylang_internals/checker/func_checker.py +269 -0
  19. guppylang_internals/checker/linearity_checker.py +821 -0
  20. guppylang_internals/checker/stmt_checker.py +447 -0
  21. guppylang_internals/compiler/__init__.py +0 -0
  22. guppylang_internals/compiler/cfg_compiler.py +233 -0
  23. guppylang_internals/compiler/core.py +613 -0
  24. guppylang_internals/compiler/expr_compiler.py +989 -0
  25. guppylang_internals/compiler/func_compiler.py +97 -0
  26. guppylang_internals/compiler/hugr_extension.py +224 -0
  27. guppylang_internals/compiler/qtm_platform_extension.py +0 -0
  28. guppylang_internals/compiler/stmt_compiler.py +212 -0
  29. guppylang_internals/decorator.py +246 -0
  30. guppylang_internals/definition/__init__.py +0 -0
  31. guppylang_internals/definition/common.py +214 -0
  32. guppylang_internals/definition/const.py +74 -0
  33. guppylang_internals/definition/custom.py +492 -0
  34. guppylang_internals/definition/declaration.py +171 -0
  35. guppylang_internals/definition/extern.py +89 -0
  36. guppylang_internals/definition/function.py +302 -0
  37. guppylang_internals/definition/overloaded.py +150 -0
  38. guppylang_internals/definition/parameter.py +82 -0
  39. guppylang_internals/definition/pytket_circuits.py +405 -0
  40. guppylang_internals/definition/struct.py +392 -0
  41. guppylang_internals/definition/traced.py +151 -0
  42. guppylang_internals/definition/ty.py +51 -0
  43. guppylang_internals/definition/value.py +115 -0
  44. guppylang_internals/definition/wasm.py +61 -0
  45. guppylang_internals/diagnostic.py +523 -0
  46. guppylang_internals/dummy_decorator.py +76 -0
  47. guppylang_internals/engine.py +295 -0
  48. guppylang_internals/error.py +107 -0
  49. guppylang_internals/experimental.py +92 -0
  50. guppylang_internals/ipython_inspect.py +28 -0
  51. guppylang_internals/nodes.py +427 -0
  52. guppylang_internals/py.typed +0 -0
  53. guppylang_internals/span.py +150 -0
  54. guppylang_internals/std/__init__.py +0 -0
  55. guppylang_internals/std/_internal/__init__.py +0 -0
  56. guppylang_internals/std/_internal/checker.py +573 -0
  57. guppylang_internals/std/_internal/compiler/__init__.py +0 -0
  58. guppylang_internals/std/_internal/compiler/arithmetic.py +136 -0
  59. guppylang_internals/std/_internal/compiler/array.py +569 -0
  60. guppylang_internals/std/_internal/compiler/either.py +131 -0
  61. guppylang_internals/std/_internal/compiler/frozenarray.py +68 -0
  62. guppylang_internals/std/_internal/compiler/futures.py +30 -0
  63. guppylang_internals/std/_internal/compiler/list.py +348 -0
  64. guppylang_internals/std/_internal/compiler/mem.py +13 -0
  65. guppylang_internals/std/_internal/compiler/option.py +78 -0
  66. guppylang_internals/std/_internal/compiler/prelude.py +271 -0
  67. guppylang_internals/std/_internal/compiler/qsystem.py +48 -0
  68. guppylang_internals/std/_internal/compiler/quantum.py +118 -0
  69. guppylang_internals/std/_internal/compiler/tket_bool.py +55 -0
  70. guppylang_internals/std/_internal/compiler/tket_exts.py +59 -0
  71. guppylang_internals/std/_internal/compiler/wasm.py +135 -0
  72. guppylang_internals/std/_internal/compiler.py +0 -0
  73. guppylang_internals/std/_internal/debug.py +95 -0
  74. guppylang_internals/std/_internal/util.py +271 -0
  75. guppylang_internals/tracing/__init__.py +0 -0
  76. guppylang_internals/tracing/builtins_mock.py +62 -0
  77. guppylang_internals/tracing/frozenlist.py +57 -0
  78. guppylang_internals/tracing/function.py +186 -0
  79. guppylang_internals/tracing/object.py +551 -0
  80. guppylang_internals/tracing/state.py +69 -0
  81. guppylang_internals/tracing/unpacking.py +194 -0
  82. guppylang_internals/tracing/util.py +86 -0
  83. guppylang_internals/tys/__init__.py +0 -0
  84. guppylang_internals/tys/arg.py +115 -0
  85. guppylang_internals/tys/builtin.py +382 -0
  86. guppylang_internals/tys/common.py +110 -0
  87. guppylang_internals/tys/const.py +114 -0
  88. guppylang_internals/tys/errors.py +178 -0
  89. guppylang_internals/tys/param.py +251 -0
  90. guppylang_internals/tys/parsing.py +425 -0
  91. guppylang_internals/tys/printing.py +174 -0
  92. guppylang_internals/tys/subst.py +112 -0
  93. guppylang_internals/tys/ty.py +876 -0
  94. guppylang_internals/tys/var.py +49 -0
  95. guppylang_internals-0.21.0.dist-info/METADATA +253 -0
  96. guppylang_internals-0.21.0.dist-info/RECORD +98 -0
  97. guppylang_internals-0.21.0.dist-info/WHEEL +4 -0
  98. 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