jaclang 0.7.22__py3-none-any.whl → 0.7.25__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.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/__init__.py +5 -10
- jaclang/cli/cli.py +50 -30
- jaclang/compiler/__init__.py +2 -2
- jaclang/compiler/absyntree.py +87 -48
- jaclang/compiler/codeloc.py +7 -2
- jaclang/compiler/compile.py +10 -3
- jaclang/compiler/parser.py +26 -23
- jaclang/compiler/passes/ir_pass.py +2 -2
- jaclang/compiler/passes/main/def_impl_match_pass.py +46 -0
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
- jaclang/compiler/passes/main/import_pass.py +6 -2
- jaclang/compiler/passes/main/pyast_load_pass.py +36 -35
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
- jaclang/compiler/passes/main/registry_pass.py +3 -12
- jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
- jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +59 -0
- jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
- jaclang/compiler/passes/main/type_check_pass.py +8 -6
- jaclang/compiler/passes/transform.py +27 -3
- jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
- jaclang/compiler/symtable.py +6 -0
- jaclang/compiler/tests/test_importer.py +2 -2
- jaclang/langserve/engine.py +14 -12
- jaclang/langserve/server.py +7 -2
- jaclang/langserve/tests/test_server.py +1 -1
- jaclang/langserve/utils.py +17 -3
- jaclang/plugin/builtin.py +3 -3
- jaclang/plugin/default.py +612 -236
- jaclang/plugin/feature.py +274 -99
- jaclang/plugin/plugin.md +471 -0
- jaclang/plugin/spec.py +231 -86
- jaclang/plugin/tests/fixtures/other_root_access.jac +9 -9
- jaclang/plugin/tests/test_features.py +2 -2
- jaclang/runtimelib/architype.py +1 -370
- jaclang/runtimelib/constructs.py +2 -0
- jaclang/runtimelib/context.py +2 -4
- jaclang/runtimelib/importer.py +7 -2
- jaclang/runtimelib/machine.py +78 -6
- jaclang/runtimelib/memory.py +2 -4
- jaclang/settings.py +3 -0
- jaclang/tests/fixtures/arch_create_util.jac +7 -0
- jaclang/tests/fixtures/arch_rel_import_creation.jac +30 -0
- jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
- jaclang/tests/fixtures/create_dynamic_architype.jac +35 -0
- jaclang/tests/fixtures/edge_node_walk.jac +1 -1
- jaclang/tests/fixtures/edges_walk.jac +1 -1
- jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
- jaclang/tests/fixtures/expr_type.jac +54 -0
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
- jaclang/tests/fixtures/registry.jac +20 -8
- jaclang/tests/fixtures/visit_order.jac +20 -0
- jaclang/tests/foo/__init__.jac +0 -0
- jaclang/tests/main.jac +2 -0
- jaclang/tests/test_cli.py +68 -4
- jaclang/tests/test_language.py +113 -27
- jaclang/utils/helpers.py +92 -14
- jaclang/utils/lang_tools.py +6 -2
- jaclang/utils/treeprinter.py +4 -2
- {jaclang-0.7.22.dist-info → jaclang-0.7.25.dist-info}/METADATA +2 -1
- {jaclang-0.7.22.dist-info → jaclang-0.7.25.dist-info}/RECORD +65 -55
- {jaclang-0.7.22.dist-info → jaclang-0.7.25.dist-info}/WHEEL +1 -1
- {jaclang-0.7.22.dist-info → jaclang-0.7.25.dist-info}/entry_points.txt +0 -0
jaclang/plugin/default.py
CHANGED
|
@@ -6,64 +6,553 @@ import ast as ast3
|
|
|
6
6
|
import fnmatch
|
|
7
7
|
import html
|
|
8
8
|
import os
|
|
9
|
-
import pickle
|
|
10
9
|
import types
|
|
11
10
|
from collections import OrderedDict
|
|
12
11
|
from dataclasses import field
|
|
13
12
|
from functools import wraps
|
|
13
|
+
from logging import getLogger
|
|
14
14
|
from typing import Any, Callable, Mapping, Optional, Sequence, Type, Union
|
|
15
15
|
from uuid import UUID
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
from jaclang.compiler.constant import EdgeDir, colors
|
|
19
|
-
from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass
|
|
17
|
+
from jaclang.compiler.constant import colors
|
|
20
18
|
from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
|
|
21
|
-
from jaclang.
|
|
19
|
+
from jaclang.plugin.feature import (
|
|
20
|
+
AccessLevel,
|
|
21
|
+
Anchor,
|
|
22
22
|
Architype,
|
|
23
23
|
DSFunc,
|
|
24
24
|
EdgeAnchor,
|
|
25
25
|
EdgeArchitype,
|
|
26
|
+
EdgeDir,
|
|
26
27
|
ExecutionContext,
|
|
27
|
-
|
|
28
|
-
JacTestCheck,
|
|
28
|
+
JacFeature as Jac,
|
|
29
29
|
NodeAnchor,
|
|
30
30
|
NodeArchitype,
|
|
31
|
+
P,
|
|
32
|
+
PyastGenPass,
|
|
31
33
|
Root,
|
|
32
|
-
|
|
34
|
+
T,
|
|
33
35
|
WalkerArchitype,
|
|
36
|
+
ast,
|
|
37
|
+
)
|
|
38
|
+
from jaclang.runtimelib.constructs import (
|
|
39
|
+
GenericEdge,
|
|
40
|
+
JacTestCheck,
|
|
34
41
|
)
|
|
35
42
|
from jaclang.runtimelib.importer import ImportPathSpec, JacImporter, PythonImporter
|
|
36
43
|
from jaclang.runtimelib.machine import JacMachine, JacProgram
|
|
37
|
-
from jaclang.runtimelib.utils import traverse_graph
|
|
38
|
-
from jaclang.plugin.feature import JacFeature as Jac # noqa: I100
|
|
39
|
-
from jaclang.plugin.spec import P, T
|
|
44
|
+
from jaclang.runtimelib.utils import collect_node_connections, traverse_graph
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
import pluggy
|
|
43
48
|
|
|
44
49
|
hookimpl = pluggy.HookimplMarker("jac")
|
|
50
|
+
logger = getLogger(__name__)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class JacAccessValidationImpl:
|
|
54
|
+
"""Jac Access Validation Implementations."""
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
@hookimpl
|
|
58
|
+
def allow_root(
|
|
59
|
+
architype: Architype, root_id: UUID, level: AccessLevel | int | str
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Allow all access from target root graph to current Architype."""
|
|
62
|
+
level = AccessLevel.cast(level)
|
|
63
|
+
access = architype.__jac__.access.roots
|
|
64
|
+
|
|
65
|
+
_root_id = str(root_id)
|
|
66
|
+
if level != access.anchors.get(_root_id, AccessLevel.NO_ACCESS):
|
|
67
|
+
access.anchors[_root_id] = level
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
@hookimpl
|
|
71
|
+
def disallow_root(
|
|
72
|
+
architype: Architype, root_id: UUID, level: AccessLevel | int | str
|
|
73
|
+
) -> None:
|
|
74
|
+
"""Disallow all access from target root graph to current Architype."""
|
|
75
|
+
level = AccessLevel.cast(level)
|
|
76
|
+
access = architype.__jac__.access.roots
|
|
77
|
+
|
|
78
|
+
access.anchors.pop(str(root_id), None)
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
@hookimpl
|
|
82
|
+
def unrestrict(architype: Architype, level: AccessLevel | int | str) -> None:
|
|
83
|
+
"""Allow everyone to access current Architype."""
|
|
84
|
+
anchor = architype.__jac__
|
|
85
|
+
level = AccessLevel.cast(level)
|
|
86
|
+
if level != anchor.access.all:
|
|
87
|
+
anchor.access.all = level
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
@hookimpl
|
|
91
|
+
def restrict(architype: Architype) -> None:
|
|
92
|
+
"""Disallow others to access current Architype."""
|
|
93
|
+
anchor = architype.__jac__
|
|
94
|
+
if anchor.access.all > AccessLevel.NO_ACCESS:
|
|
95
|
+
anchor.access.all = AccessLevel.NO_ACCESS
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
@hookimpl
|
|
99
|
+
def check_read_access(to: Anchor) -> bool:
|
|
100
|
+
"""Read Access Validation."""
|
|
101
|
+
if not (access_level := Jac.check_access_level(to) > AccessLevel.NO_ACCESS):
|
|
102
|
+
logger.info(
|
|
103
|
+
f"Current root doesn't have read access to {to.__class__.__name__}[{to.id}]"
|
|
104
|
+
)
|
|
105
|
+
return access_level
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
@hookimpl
|
|
109
|
+
def check_connect_access(to: Anchor) -> bool:
|
|
110
|
+
"""Write Access Validation."""
|
|
111
|
+
if not (access_level := Jac.check_access_level(to) > AccessLevel.READ):
|
|
112
|
+
logger.info(
|
|
113
|
+
f"Current root doesn't have connect access to {to.__class__.__name__}[{to.id}]"
|
|
114
|
+
)
|
|
115
|
+
return access_level
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
@hookimpl
|
|
119
|
+
def check_write_access(to: Anchor) -> bool:
|
|
120
|
+
"""Write Access Validation."""
|
|
121
|
+
if not (access_level := Jac.check_access_level(to) > AccessLevel.CONNECT):
|
|
122
|
+
logger.info(
|
|
123
|
+
f"Current root doesn't have write access to {to.__class__.__name__}[{to.id}]"
|
|
124
|
+
)
|
|
125
|
+
return access_level
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
@hookimpl
|
|
129
|
+
def check_access_level(to: Anchor) -> AccessLevel:
|
|
130
|
+
"""Access validation."""
|
|
131
|
+
if not to.persistent:
|
|
132
|
+
return AccessLevel.WRITE
|
|
133
|
+
|
|
134
|
+
jctx = Jac.get_context()
|
|
135
|
+
|
|
136
|
+
jroot = jctx.root
|
|
137
|
+
|
|
138
|
+
# if current root is system_root
|
|
139
|
+
# if current root id is equal to target anchor's root id
|
|
140
|
+
# if current root is the target anchor
|
|
141
|
+
if jroot == jctx.system_root or jroot.id == to.root or jroot == to:
|
|
142
|
+
return AccessLevel.WRITE
|
|
143
|
+
|
|
144
|
+
access_level = AccessLevel.NO_ACCESS
|
|
145
|
+
|
|
146
|
+
# if target anchor have set access.all
|
|
147
|
+
if (to_access := to.access).all > AccessLevel.NO_ACCESS:
|
|
148
|
+
access_level = to_access.all
|
|
149
|
+
|
|
150
|
+
# if target anchor's root have set allowed roots
|
|
151
|
+
# if current root is allowed to the whole graph of target anchor's root
|
|
152
|
+
if to.root and isinstance(to_root := jctx.mem.find_one(to.root), Anchor):
|
|
153
|
+
if to_root.access.all > access_level:
|
|
154
|
+
access_level = to_root.access.all
|
|
155
|
+
|
|
156
|
+
level = to_root.access.roots.check(str(jroot.id))
|
|
157
|
+
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
158
|
+
access_level = level
|
|
159
|
+
|
|
160
|
+
# if target anchor have set allowed roots
|
|
161
|
+
# if current root is allowed to target anchor
|
|
162
|
+
level = to_access.roots.check(str(jroot.id))
|
|
163
|
+
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
164
|
+
access_level = level
|
|
165
|
+
|
|
166
|
+
return access_level
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class JacNodeImpl:
|
|
170
|
+
"""Jac Node Operations."""
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
@hookimpl
|
|
174
|
+
def node_dot(node: NodeArchitype, dot_file: Optional[str]) -> str:
|
|
175
|
+
"""Generate Dot file for visualizing nodes and edges."""
|
|
176
|
+
visited_nodes: set[NodeAnchor] = set()
|
|
177
|
+
connections: set[tuple[NodeArchitype, NodeArchitype, str]] = set()
|
|
178
|
+
unique_node_id_dict = {}
|
|
179
|
+
|
|
180
|
+
collect_node_connections(node.__jac__, visited_nodes, connections)
|
|
181
|
+
dot_content = 'digraph {\nnode [style="filled", shape="ellipse", fillcolor="invis", fontcolor="black"];\n'
|
|
182
|
+
for idx, i in enumerate([nodes_.architype for nodes_ in visited_nodes]):
|
|
183
|
+
unique_node_id_dict[i] = (i.__class__.__name__, str(idx))
|
|
184
|
+
dot_content += f'{idx} [label="{i}"];\n'
|
|
185
|
+
dot_content += 'edge [color="gray", style="solid"];\n'
|
|
186
|
+
|
|
187
|
+
for pair in list(set(connections)):
|
|
188
|
+
dot_content += (
|
|
189
|
+
f"{unique_node_id_dict[pair[0]][1]} -> {unique_node_id_dict[pair[1]][1]}"
|
|
190
|
+
f' [label="{pair[2]}"];\n'
|
|
191
|
+
)
|
|
192
|
+
if dot_file:
|
|
193
|
+
with open(dot_file, "w") as f:
|
|
194
|
+
f.write(dot_content + "}")
|
|
195
|
+
return dot_content + "}"
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
@hookimpl
|
|
199
|
+
def get_edges(
|
|
200
|
+
node: NodeAnchor,
|
|
201
|
+
dir: EdgeDir,
|
|
202
|
+
filter_func: Optional[Callable[[list[EdgeArchitype]], list[EdgeArchitype]]],
|
|
203
|
+
target_obj: Optional[list[NodeArchitype]],
|
|
204
|
+
) -> list[EdgeArchitype]:
|
|
205
|
+
"""Get edges connected to this node."""
|
|
206
|
+
ret_edges: list[EdgeArchitype] = []
|
|
207
|
+
for anchor in node.edges:
|
|
208
|
+
if (
|
|
209
|
+
(source := anchor.source)
|
|
210
|
+
and (target := anchor.target)
|
|
211
|
+
and (not filter_func or filter_func([anchor.architype]))
|
|
212
|
+
and source.architype
|
|
213
|
+
and target.architype
|
|
214
|
+
):
|
|
215
|
+
if (
|
|
216
|
+
dir in [EdgeDir.OUT, EdgeDir.ANY]
|
|
217
|
+
and node == source
|
|
218
|
+
and (not target_obj or target.architype in target_obj)
|
|
219
|
+
and Jac.check_read_access(target)
|
|
220
|
+
):
|
|
221
|
+
ret_edges.append(anchor.architype)
|
|
222
|
+
if (
|
|
223
|
+
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
224
|
+
and node == target
|
|
225
|
+
and (not target_obj or source.architype in target_obj)
|
|
226
|
+
and Jac.check_read_access(source)
|
|
227
|
+
):
|
|
228
|
+
ret_edges.append(anchor.architype)
|
|
229
|
+
return ret_edges
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
@hookimpl
|
|
233
|
+
def edges_to_nodes(
|
|
234
|
+
node: NodeAnchor,
|
|
235
|
+
dir: EdgeDir,
|
|
236
|
+
filter_func: Optional[Callable[[list[EdgeArchitype]], list[EdgeArchitype]]],
|
|
237
|
+
target_obj: Optional[list[NodeArchitype]],
|
|
238
|
+
) -> list[NodeArchitype]:
|
|
239
|
+
"""Get set of nodes connected to this node."""
|
|
240
|
+
ret_edges: list[NodeArchitype] = []
|
|
241
|
+
for anchor in node.edges:
|
|
242
|
+
if (
|
|
243
|
+
(source := anchor.source)
|
|
244
|
+
and (target := anchor.target)
|
|
245
|
+
and (not filter_func or filter_func([anchor.architype]))
|
|
246
|
+
and source.architype
|
|
247
|
+
and target.architype
|
|
248
|
+
):
|
|
249
|
+
if (
|
|
250
|
+
dir in [EdgeDir.OUT, EdgeDir.ANY]
|
|
251
|
+
and node == source
|
|
252
|
+
and (not target_obj or target.architype in target_obj)
|
|
253
|
+
and Jac.check_read_access(target)
|
|
254
|
+
):
|
|
255
|
+
ret_edges.append(target.architype)
|
|
256
|
+
if (
|
|
257
|
+
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
258
|
+
and node == target
|
|
259
|
+
and (not target_obj or source.architype in target_obj)
|
|
260
|
+
and Jac.check_read_access(source)
|
|
261
|
+
):
|
|
262
|
+
ret_edges.append(source.architype)
|
|
263
|
+
return ret_edges
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
@hookimpl
|
|
267
|
+
def remove_edge(node: NodeAnchor, edge: EdgeAnchor) -> None:
|
|
268
|
+
"""Remove reference without checking sync status."""
|
|
269
|
+
for idx, ed in enumerate(node.edges):
|
|
270
|
+
if ed.id == edge.id:
|
|
271
|
+
node.edges.pop(idx)
|
|
272
|
+
break
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class JacEdgeImpl:
|
|
276
|
+
"""Jac Edge Operations."""
|
|
277
|
+
|
|
278
|
+
@staticmethod
|
|
279
|
+
@hookimpl
|
|
280
|
+
def detach(edge: EdgeAnchor) -> None:
|
|
281
|
+
"""Detach edge from nodes."""
|
|
282
|
+
Jac.remove_edge(node=edge.source, edge=edge)
|
|
283
|
+
Jac.remove_edge(node=edge.target, edge=edge)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class JacWalkerImpl:
|
|
287
|
+
"""Jac Edge Operations."""
|
|
288
|
+
|
|
289
|
+
@staticmethod
|
|
290
|
+
@hookimpl
|
|
291
|
+
def visit_node(
|
|
292
|
+
walker: WalkerArchitype,
|
|
293
|
+
expr: (
|
|
294
|
+
list[NodeArchitype | EdgeArchitype]
|
|
295
|
+
| list[NodeArchitype]
|
|
296
|
+
| list[EdgeArchitype]
|
|
297
|
+
| NodeArchitype
|
|
298
|
+
| EdgeArchitype
|
|
299
|
+
),
|
|
300
|
+
) -> bool:
|
|
301
|
+
"""Jac's visit stmt feature."""
|
|
302
|
+
if isinstance(walker, WalkerArchitype):
|
|
303
|
+
"""Walker visits node."""
|
|
304
|
+
wanch = walker.__jac__
|
|
305
|
+
before_len = len(wanch.next)
|
|
306
|
+
for anchor in (
|
|
307
|
+
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
308
|
+
):
|
|
309
|
+
if anchor not in wanch.ignores:
|
|
310
|
+
if isinstance(anchor, NodeAnchor):
|
|
311
|
+
wanch.next.append(anchor)
|
|
312
|
+
elif isinstance(anchor, EdgeAnchor):
|
|
313
|
+
if target := anchor.target:
|
|
314
|
+
wanch.next.append(target)
|
|
315
|
+
else:
|
|
316
|
+
raise ValueError("Edge has no target.")
|
|
317
|
+
return len(wanch.next) > before_len
|
|
318
|
+
else:
|
|
319
|
+
raise TypeError("Invalid walker object")
|
|
320
|
+
|
|
321
|
+
@staticmethod
|
|
322
|
+
@hookimpl
|
|
323
|
+
def ignore(
|
|
324
|
+
walker: WalkerArchitype,
|
|
325
|
+
expr: (
|
|
326
|
+
list[NodeArchitype | EdgeArchitype]
|
|
327
|
+
| list[NodeArchitype]
|
|
328
|
+
| list[EdgeArchitype]
|
|
329
|
+
| NodeArchitype
|
|
330
|
+
| EdgeArchitype
|
|
331
|
+
),
|
|
332
|
+
) -> bool:
|
|
333
|
+
"""Jac's ignore stmt feature."""
|
|
334
|
+
if isinstance(walker, WalkerArchitype):
|
|
335
|
+
wanch = walker.__jac__
|
|
336
|
+
before_len = len(wanch.ignores)
|
|
337
|
+
for anchor in (
|
|
338
|
+
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
339
|
+
):
|
|
340
|
+
if anchor not in wanch.ignores:
|
|
341
|
+
if isinstance(anchor, NodeAnchor):
|
|
342
|
+
wanch.ignores.append(anchor)
|
|
343
|
+
elif isinstance(anchor, EdgeAnchor):
|
|
344
|
+
if target := anchor.target:
|
|
345
|
+
wanch.ignores.append(target)
|
|
346
|
+
else:
|
|
347
|
+
raise ValueError("Edge has no target.")
|
|
348
|
+
return len(wanch.ignores) > before_len
|
|
349
|
+
else:
|
|
350
|
+
raise TypeError("Invalid walker object")
|
|
351
|
+
|
|
352
|
+
@staticmethod
|
|
353
|
+
@hookimpl
|
|
354
|
+
def spawn_call(op1: Architype, op2: Architype) -> WalkerArchitype:
|
|
355
|
+
"""Invoke data spatial call."""
|
|
356
|
+
if isinstance(op1, WalkerArchitype):
|
|
357
|
+
warch = op1
|
|
358
|
+
walker = op1.__jac__
|
|
359
|
+
if isinstance(op2, NodeArchitype):
|
|
360
|
+
node = op2.__jac__
|
|
361
|
+
elif isinstance(op2, EdgeArchitype):
|
|
362
|
+
node = op2.__jac__.target
|
|
363
|
+
else:
|
|
364
|
+
raise TypeError("Invalid target object")
|
|
365
|
+
elif isinstance(op2, WalkerArchitype):
|
|
366
|
+
warch = op2
|
|
367
|
+
walker = op2.__jac__
|
|
368
|
+
if isinstance(op1, NodeArchitype):
|
|
369
|
+
node = op1.__jac__
|
|
370
|
+
elif isinstance(op1, EdgeArchitype):
|
|
371
|
+
node = op1.__jac__.target
|
|
372
|
+
else:
|
|
373
|
+
raise TypeError("Invalid target object")
|
|
374
|
+
else:
|
|
375
|
+
raise TypeError("Invalid walker object")
|
|
376
|
+
|
|
377
|
+
walker.path = []
|
|
378
|
+
walker.next = [node]
|
|
379
|
+
if walker.next:
|
|
380
|
+
current_node = walker.next[-1].architype
|
|
381
|
+
for i in warch._jac_entry_funcs_:
|
|
382
|
+
if not i.trigger:
|
|
383
|
+
if i.func:
|
|
384
|
+
i.func(warch, current_node)
|
|
385
|
+
else:
|
|
386
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
387
|
+
while len(walker.next):
|
|
388
|
+
if current_node := walker.next.pop(0).architype:
|
|
389
|
+
for i in current_node._jac_entry_funcs_:
|
|
390
|
+
if not i.trigger or isinstance(warch, i.trigger):
|
|
391
|
+
if i.func:
|
|
392
|
+
i.func(current_node, warch)
|
|
393
|
+
else:
|
|
394
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
395
|
+
if walker.disengaged:
|
|
396
|
+
return warch
|
|
397
|
+
for i in warch._jac_entry_funcs_:
|
|
398
|
+
if not i.trigger or isinstance(current_node, i.trigger):
|
|
399
|
+
if i.func and i.trigger:
|
|
400
|
+
i.func(warch, current_node)
|
|
401
|
+
elif not i.trigger:
|
|
402
|
+
continue
|
|
403
|
+
else:
|
|
404
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
405
|
+
if walker.disengaged:
|
|
406
|
+
return warch
|
|
407
|
+
for i in warch._jac_exit_funcs_:
|
|
408
|
+
if not i.trigger or isinstance(current_node, i.trigger):
|
|
409
|
+
if i.func and i.trigger:
|
|
410
|
+
i.func(warch, current_node)
|
|
411
|
+
elif not i.trigger:
|
|
412
|
+
continue
|
|
413
|
+
else:
|
|
414
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
415
|
+
if walker.disengaged:
|
|
416
|
+
return warch
|
|
417
|
+
for i in current_node._jac_exit_funcs_:
|
|
418
|
+
if not i.trigger or isinstance(warch, i.trigger):
|
|
419
|
+
if i.func:
|
|
420
|
+
i.func(current_node, warch)
|
|
421
|
+
else:
|
|
422
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
423
|
+
if walker.disengaged:
|
|
424
|
+
return warch
|
|
425
|
+
for i in warch._jac_exit_funcs_:
|
|
426
|
+
if not i.trigger:
|
|
427
|
+
if i.func:
|
|
428
|
+
i.func(warch, current_node)
|
|
429
|
+
else:
|
|
430
|
+
raise ValueError(f"No function {i.name} to call.")
|
|
431
|
+
walker.ignores = []
|
|
432
|
+
return warch
|
|
433
|
+
|
|
434
|
+
@staticmethod
|
|
435
|
+
@hookimpl
|
|
436
|
+
def disengage(walker: WalkerArchitype) -> bool: # noqa: ANN401
|
|
437
|
+
"""Jac's disengage stmt feature."""
|
|
438
|
+
walker.__jac__.disengaged = True
|
|
439
|
+
return True
|
|
440
|
+
|
|
45
441
|
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
442
|
+
class JacBuiltinImpl:
|
|
443
|
+
"""Jac Builtins."""
|
|
444
|
+
|
|
445
|
+
@staticmethod
|
|
446
|
+
@hookimpl
|
|
447
|
+
def dotgen(
|
|
448
|
+
node: NodeArchitype,
|
|
449
|
+
depth: int,
|
|
450
|
+
traverse: bool,
|
|
451
|
+
edge_type: Optional[list[str]],
|
|
452
|
+
bfs: bool,
|
|
453
|
+
edge_limit: int,
|
|
454
|
+
node_limit: int,
|
|
455
|
+
dot_file: Optional[str],
|
|
456
|
+
) -> str:
|
|
457
|
+
"""Generate Dot file for visualizing nodes and edges."""
|
|
458
|
+
edge_type = edge_type if edge_type else []
|
|
459
|
+
visited_nodes: list[NodeArchitype] = []
|
|
460
|
+
node_depths: dict[NodeArchitype, int] = {node: 0}
|
|
461
|
+
queue: list = [[node, 0]]
|
|
462
|
+
connections: list[tuple[NodeArchitype, NodeArchitype, EdgeArchitype]] = []
|
|
463
|
+
|
|
464
|
+
def dfs(node: NodeArchitype, cur_depth: int) -> None:
|
|
465
|
+
"""Depth first search."""
|
|
466
|
+
if node not in visited_nodes:
|
|
467
|
+
visited_nodes.append(node)
|
|
468
|
+
traverse_graph(
|
|
469
|
+
node,
|
|
470
|
+
cur_depth,
|
|
471
|
+
depth,
|
|
472
|
+
edge_type,
|
|
473
|
+
traverse,
|
|
474
|
+
connections,
|
|
475
|
+
node_depths,
|
|
476
|
+
visited_nodes,
|
|
477
|
+
queue,
|
|
478
|
+
bfs,
|
|
479
|
+
dfs,
|
|
480
|
+
node_limit,
|
|
481
|
+
edge_limit,
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
if bfs:
|
|
485
|
+
cur_depth = 0
|
|
486
|
+
while queue:
|
|
487
|
+
current_node, cur_depth = queue.pop(0)
|
|
488
|
+
if current_node not in visited_nodes:
|
|
489
|
+
visited_nodes.append(current_node)
|
|
490
|
+
traverse_graph(
|
|
491
|
+
current_node,
|
|
492
|
+
cur_depth,
|
|
493
|
+
depth,
|
|
494
|
+
edge_type,
|
|
495
|
+
traverse,
|
|
496
|
+
connections,
|
|
497
|
+
node_depths,
|
|
498
|
+
visited_nodes,
|
|
499
|
+
queue,
|
|
500
|
+
bfs,
|
|
501
|
+
dfs,
|
|
502
|
+
node_limit,
|
|
503
|
+
edge_limit,
|
|
504
|
+
)
|
|
505
|
+
else:
|
|
506
|
+
dfs(node, cur_depth=0)
|
|
507
|
+
dot_content = (
|
|
508
|
+
'digraph {\nnode [style="filled", shape="ellipse", '
|
|
509
|
+
'fillcolor="invis", fontcolor="black"];\n'
|
|
510
|
+
)
|
|
511
|
+
for source, target, edge in connections:
|
|
512
|
+
edge_label = html.escape(str(edge.__jac__.architype))
|
|
513
|
+
dot_content += (
|
|
514
|
+
f"{visited_nodes.index(source)} -> {visited_nodes.index(target)} "
|
|
515
|
+
f' [label="{edge_label if "GenericEdge" not in edge_label else ""}"];\n'
|
|
516
|
+
)
|
|
517
|
+
for node_ in visited_nodes:
|
|
518
|
+
color = (
|
|
519
|
+
colors[node_depths[node_]] if node_depths[node_] < 25 else colors[24]
|
|
520
|
+
)
|
|
521
|
+
dot_content += (
|
|
522
|
+
f'{visited_nodes.index(node_)} [label="{html.escape(str(node_.__jac__.architype))}"'
|
|
523
|
+
f'fillcolor="{color}"];\n'
|
|
524
|
+
)
|
|
525
|
+
if dot_file:
|
|
526
|
+
with open(dot_file, "w") as f:
|
|
527
|
+
f.write(dot_content + "}")
|
|
528
|
+
return dot_content + "}"
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class JacCmdImpl:
|
|
532
|
+
"""Jac CLI command."""
|
|
533
|
+
|
|
534
|
+
@staticmethod
|
|
535
|
+
@hookimpl
|
|
536
|
+
def create_cmd() -> None:
|
|
537
|
+
"""Create Jac CLI cmds."""
|
|
538
|
+
pass
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
class JacFeatureImpl(
|
|
542
|
+
JacAccessValidationImpl,
|
|
543
|
+
JacNodeImpl,
|
|
544
|
+
JacEdgeImpl,
|
|
545
|
+
JacWalkerImpl,
|
|
546
|
+
JacBuiltinImpl,
|
|
547
|
+
JacCmdImpl,
|
|
548
|
+
):
|
|
64
549
|
"""Jac Feature."""
|
|
65
550
|
|
|
66
|
-
|
|
551
|
+
@staticmethod
|
|
552
|
+
@hookimpl
|
|
553
|
+
def setup() -> None:
|
|
554
|
+
"""Set Class References."""
|
|
555
|
+
pass
|
|
67
556
|
|
|
68
557
|
@staticmethod
|
|
69
558
|
@hookimpl
|
|
@@ -74,6 +563,7 @@ class JacFeatureDefaults:
|
|
|
74
563
|
@staticmethod
|
|
75
564
|
@hookimpl
|
|
76
565
|
def get_object(id: str) -> Architype | None:
|
|
566
|
+
"""Get object by id."""
|
|
77
567
|
if id == "root":
|
|
78
568
|
return Jac.get_context().root.architype
|
|
79
569
|
elif obj := Jac.get_context().mem.find_by_id(UUID(id)):
|
|
@@ -84,6 +574,7 @@ class JacFeatureDefaults:
|
|
|
84
574
|
@staticmethod
|
|
85
575
|
@hookimpl
|
|
86
576
|
def object_ref(obj: Architype) -> str:
|
|
577
|
+
"""Get object's id."""
|
|
87
578
|
return obj.__jac__.id.hex
|
|
88
579
|
|
|
89
580
|
@staticmethod
|
|
@@ -260,7 +751,9 @@ class JacFeatureDefaults:
|
|
|
260
751
|
|
|
261
752
|
jac_machine = JacMachine.get(base_path)
|
|
262
753
|
if not jac_machine.jac_program:
|
|
263
|
-
jac_machine.attach_program(
|
|
754
|
+
jac_machine.attach_program(
|
|
755
|
+
JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
|
|
756
|
+
)
|
|
264
757
|
|
|
265
758
|
if lng == "py":
|
|
266
759
|
import_result = PythonImporter(JacMachine.get()).run_import(spec)
|
|
@@ -309,7 +802,7 @@ class JacFeatureDefaults:
|
|
|
309
802
|
if mod_name.endswith(".test"):
|
|
310
803
|
mod_name = mod_name[:-5]
|
|
311
804
|
JacTestCheck.reset()
|
|
312
|
-
Jac.jac_import(target=mod_name, base_path=base)
|
|
805
|
+
Jac.jac_import(target=mod_name, base_path=base, cachable=False)
|
|
313
806
|
JacTestCheck.run_test(xit, maxfail, verbose)
|
|
314
807
|
ret_count = JacTestCheck.failcount
|
|
315
808
|
else:
|
|
@@ -363,66 +856,13 @@ class JacFeatureDefaults:
|
|
|
363
856
|
|
|
364
857
|
@staticmethod
|
|
365
858
|
@hookimpl
|
|
366
|
-
def
|
|
367
|
-
"""Jac's spawn operator feature."""
|
|
368
|
-
if isinstance(op1, WalkerArchitype):
|
|
369
|
-
return op1.__jac__.spawn_call(op2.__jac__)
|
|
370
|
-
elif isinstance(op2, WalkerArchitype):
|
|
371
|
-
return op2.__jac__.spawn_call(op1.__jac__)
|
|
372
|
-
else:
|
|
373
|
-
raise TypeError("Invalid walker object")
|
|
374
|
-
|
|
375
|
-
@staticmethod
|
|
376
|
-
@hookimpl
|
|
377
|
-
def report(expr: Any) -> Any: # noqa: ANN401
|
|
859
|
+
def report(expr: Any, custom: bool) -> None: # noqa: ANN401
|
|
378
860
|
"""Jac's report stmt feature."""
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
def ignore(
|
|
383
|
-
walker: WalkerArchitype,
|
|
384
|
-
expr: (
|
|
385
|
-
list[NodeArchitype | EdgeArchitype]
|
|
386
|
-
| list[NodeArchitype]
|
|
387
|
-
| list[EdgeArchitype]
|
|
388
|
-
| NodeArchitype
|
|
389
|
-
| EdgeArchitype
|
|
390
|
-
),
|
|
391
|
-
) -> bool:
|
|
392
|
-
"""Jac's ignore stmt feature."""
|
|
393
|
-
if isinstance(walker, WalkerArchitype):
|
|
394
|
-
return walker.__jac__.ignore_node(
|
|
395
|
-
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
396
|
-
)
|
|
861
|
+
ctx = Jac.get_context()
|
|
862
|
+
if custom:
|
|
863
|
+
ctx.custom = expr
|
|
397
864
|
else:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
@staticmethod
|
|
401
|
-
@hookimpl
|
|
402
|
-
def visit_node(
|
|
403
|
-
walker: WalkerArchitype,
|
|
404
|
-
expr: (
|
|
405
|
-
list[NodeArchitype | EdgeArchitype]
|
|
406
|
-
| list[NodeArchitype]
|
|
407
|
-
| list[EdgeArchitype]
|
|
408
|
-
| NodeArchitype
|
|
409
|
-
| EdgeArchitype
|
|
410
|
-
),
|
|
411
|
-
) -> bool:
|
|
412
|
-
"""Jac's visit stmt feature."""
|
|
413
|
-
if isinstance(walker, WalkerArchitype):
|
|
414
|
-
return walker.__jac__.visit_node(
|
|
415
|
-
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
416
|
-
)
|
|
417
|
-
else:
|
|
418
|
-
raise TypeError("Invalid walker object")
|
|
419
|
-
|
|
420
|
-
@staticmethod
|
|
421
|
-
@hookimpl
|
|
422
|
-
def disengage(walker: WalkerArchitype) -> bool: # noqa: ANN401
|
|
423
|
-
"""Jac's disengage stmt feature."""
|
|
424
|
-
walker.__jac__.disengage_now()
|
|
425
|
-
return True
|
|
865
|
+
ctx.reports.append(expr)
|
|
426
866
|
|
|
427
867
|
@staticmethod
|
|
428
868
|
@hookimpl
|
|
@@ -444,19 +884,23 @@ class JacFeatureDefaults:
|
|
|
444
884
|
if edges_only:
|
|
445
885
|
connected_edges: list[EdgeArchitype] = []
|
|
446
886
|
for node in node_obj:
|
|
447
|
-
|
|
448
|
-
dir, filter_func, target_obj=targ_obj_set
|
|
887
|
+
edges = Jac.get_edges(
|
|
888
|
+
node.__jac__, dir, filter_func, target_obj=targ_obj_set
|
|
449
889
|
)
|
|
450
|
-
|
|
890
|
+
connected_edges.extend(
|
|
891
|
+
edge for edge in edges if edge not in connected_edges
|
|
892
|
+
)
|
|
893
|
+
return connected_edges
|
|
451
894
|
else:
|
|
452
895
|
connected_nodes: list[NodeArchitype] = []
|
|
453
896
|
for node in node_obj:
|
|
897
|
+
nodes = Jac.edges_to_nodes(
|
|
898
|
+
node.__jac__, dir, filter_func, target_obj=targ_obj_set
|
|
899
|
+
)
|
|
454
900
|
connected_nodes.extend(
|
|
455
|
-
node
|
|
456
|
-
dir, filter_func, target_obj=targ_obj_set
|
|
457
|
-
)
|
|
901
|
+
node for node in nodes if node not in connected_nodes
|
|
458
902
|
)
|
|
459
|
-
return
|
|
903
|
+
return connected_nodes
|
|
460
904
|
|
|
461
905
|
@staticmethod
|
|
462
906
|
@hookimpl
|
|
@@ -474,14 +918,12 @@ class JacFeatureDefaults:
|
|
|
474
918
|
right = [right] if isinstance(right, NodeArchitype) else right
|
|
475
919
|
edges = []
|
|
476
920
|
|
|
477
|
-
root = Jac.get_root().__jac__
|
|
478
|
-
|
|
479
921
|
for i in left:
|
|
480
922
|
_left = i.__jac__
|
|
481
|
-
if
|
|
923
|
+
if Jac.check_connect_access(_left):
|
|
482
924
|
for j in right:
|
|
483
925
|
_right = j.__jac__
|
|
484
|
-
if
|
|
926
|
+
if Jac.check_connect_access(_right):
|
|
485
927
|
edges.append(edge_spec(_left, _right))
|
|
486
928
|
return right if not edges_only else edges
|
|
487
929
|
|
|
@@ -498,8 +940,6 @@ class JacFeatureDefaults:
|
|
|
498
940
|
left = [left] if isinstance(left, NodeArchitype) else left
|
|
499
941
|
right = [right] if isinstance(right, NodeArchitype) else right
|
|
500
942
|
|
|
501
|
-
root = Jac.get_root().__jac__
|
|
502
|
-
|
|
503
943
|
for i in left:
|
|
504
944
|
node = i.__jac__
|
|
505
945
|
for anchor in set(node.edges):
|
|
@@ -514,17 +954,17 @@ class JacFeatureDefaults:
|
|
|
514
954
|
dir in [EdgeDir.OUT, EdgeDir.ANY]
|
|
515
955
|
and node == source
|
|
516
956
|
and target.architype in right
|
|
517
|
-
and
|
|
957
|
+
and Jac.check_write_access(target)
|
|
518
958
|
):
|
|
519
|
-
|
|
959
|
+
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
520
960
|
disconnect_occurred = True
|
|
521
961
|
if (
|
|
522
962
|
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
523
963
|
and node == target
|
|
524
964
|
and source.architype in right
|
|
525
|
-
and
|
|
965
|
+
and Jac.check_write_access(source)
|
|
526
966
|
):
|
|
527
|
-
|
|
967
|
+
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
528
968
|
disconnect_occurred = True
|
|
529
969
|
|
|
530
970
|
return disconnect_occurred
|
|
@@ -565,7 +1005,16 @@ class JacFeatureDefaults:
|
|
|
565
1005
|
|
|
566
1006
|
def builder(source: NodeAnchor, target: NodeAnchor) -> EdgeArchitype:
|
|
567
1007
|
edge = conn_type() if isinstance(conn_type, type) else conn_type
|
|
568
|
-
|
|
1008
|
+
|
|
1009
|
+
eanch = edge.__jac__ = EdgeAnchor(
|
|
1010
|
+
architype=edge,
|
|
1011
|
+
source=source,
|
|
1012
|
+
target=target,
|
|
1013
|
+
is_undirected=is_undirected,
|
|
1014
|
+
)
|
|
1015
|
+
source.edges.append(eanch)
|
|
1016
|
+
target.edges.append(eanch)
|
|
1017
|
+
|
|
569
1018
|
if conn_assign:
|
|
570
1019
|
for fld, val in zip(conn_assign[0], conn_assign[1]):
|
|
571
1020
|
if hasattr(edge, fld):
|
|
@@ -573,29 +1022,58 @@ class JacFeatureDefaults:
|
|
|
573
1022
|
else:
|
|
574
1023
|
raise ValueError(f"Invalid attribute: {fld}")
|
|
575
1024
|
if source.persistent or target.persistent:
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
1025
|
+
Jac.save(eanch)
|
|
1026
|
+
Jac.save(target)
|
|
1027
|
+
Jac.save(source)
|
|
579
1028
|
return edge
|
|
580
1029
|
|
|
581
1030
|
return builder
|
|
582
1031
|
|
|
1032
|
+
@staticmethod
|
|
1033
|
+
@hookimpl
|
|
1034
|
+
def save(obj: Architype | Anchor) -> None:
|
|
1035
|
+
"""Destroy object."""
|
|
1036
|
+
anchor = obj.__jac__ if isinstance(obj, Architype) else obj
|
|
1037
|
+
|
|
1038
|
+
jctx = Jac.get_context()
|
|
1039
|
+
|
|
1040
|
+
anchor.persistent = True
|
|
1041
|
+
anchor.root = jctx.root.id
|
|
1042
|
+
|
|
1043
|
+
jctx.mem.set(anchor.id, anchor)
|
|
1044
|
+
|
|
1045
|
+
@staticmethod
|
|
1046
|
+
@hookimpl
|
|
1047
|
+
def destroy(obj: Architype | Anchor) -> None:
|
|
1048
|
+
"""Destroy object."""
|
|
1049
|
+
anchor = obj.__jac__ if isinstance(obj, Architype) else obj
|
|
1050
|
+
|
|
1051
|
+
if Jac.check_write_access(anchor):
|
|
1052
|
+
match anchor:
|
|
1053
|
+
case NodeAnchor():
|
|
1054
|
+
for edge in anchor.edges:
|
|
1055
|
+
Jac.destroy(edge)
|
|
1056
|
+
case EdgeAnchor():
|
|
1057
|
+
Jac.detach(anchor)
|
|
1058
|
+
case _:
|
|
1059
|
+
pass
|
|
1060
|
+
|
|
1061
|
+
Jac.get_context().mem.remove(anchor.id)
|
|
1062
|
+
|
|
583
1063
|
@staticmethod
|
|
584
1064
|
@hookimpl
|
|
585
1065
|
def get_semstr_type(
|
|
586
1066
|
file_loc: str, scope: str, attr: str, return_semstr: bool
|
|
587
1067
|
) -> Optional[str]:
|
|
588
1068
|
"""Jac's get_semstr_type feature."""
|
|
1069
|
+
from jaclang.compiler.semtable import SemInfo, SemScope, SemRegistry
|
|
1070
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
1071
|
+
|
|
589
1072
|
_scope = SemScope.get_scope_from_str(scope)
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
|
|
595
|
-
),
|
|
596
|
-
"rb",
|
|
597
|
-
) as f:
|
|
598
|
-
mod_registry: SemRegistry = pickle.load(f)
|
|
1073
|
+
jac_program = JacMachine.get().jac_program
|
|
1074
|
+
mod_registry: SemRegistry = (
|
|
1075
|
+
jac_program.sem_ir if jac_program is not None else SemRegistry()
|
|
1076
|
+
)
|
|
599
1077
|
_, attr_seminfo = mod_registry.lookup(_scope, attr)
|
|
600
1078
|
if attr_seminfo and isinstance(attr_seminfo, SemInfo):
|
|
601
1079
|
return attr_seminfo.semstr if return_semstr else attr_seminfo.type
|
|
@@ -605,15 +1083,12 @@ class JacFeatureDefaults:
|
|
|
605
1083
|
@hookimpl
|
|
606
1084
|
def obj_scope(file_loc: str, attr: str) -> str:
|
|
607
1085
|
"""Jac's gather_scope feature."""
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
"rb",
|
|
615
|
-
) as f:
|
|
616
|
-
mod_registry: SemRegistry = pickle.load(f)
|
|
1086
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
1087
|
+
|
|
1088
|
+
jac_program = JacMachine.get().jac_program
|
|
1089
|
+
mod_registry: SemRegistry = (
|
|
1090
|
+
jac_program.sem_ir if jac_program is not None else SemRegistry()
|
|
1091
|
+
)
|
|
617
1092
|
|
|
618
1093
|
attr_scope = None
|
|
619
1094
|
for x in attr.split("."):
|
|
@@ -645,15 +1120,14 @@ class JacFeatureDefaults:
|
|
|
645
1120
|
@staticmethod
|
|
646
1121
|
@hookimpl
|
|
647
1122
|
def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
)
|
|
656
|
-
mod_registry: SemRegistry = pickle.load(f)
|
|
1123
|
+
"""Jac's get_semstr_type implementation."""
|
|
1124
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
1125
|
+
from jaclang.compiler.semtable import SemInfo, SemScope
|
|
1126
|
+
|
|
1127
|
+
jac_program = JacMachine.get().jac_program
|
|
1128
|
+
mod_registry: SemRegistry = (
|
|
1129
|
+
jac_program.sem_ir if jac_program is not None else SemRegistry()
|
|
1130
|
+
)
|
|
657
1131
|
|
|
658
1132
|
attr_scope = None
|
|
659
1133
|
for x in attr.split("."):
|
|
@@ -843,101 +1317,3 @@ class JacFeatureDefaults:
|
|
|
843
1317
|
"include_info": [],
|
|
844
1318
|
"exclude_info": [],
|
|
845
1319
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
class JacBuiltin:
|
|
849
|
-
"""Jac Builtins."""
|
|
850
|
-
|
|
851
|
-
@staticmethod
|
|
852
|
-
@hookimpl
|
|
853
|
-
def dotgen(
|
|
854
|
-
node: NodeArchitype,
|
|
855
|
-
depth: int,
|
|
856
|
-
traverse: bool,
|
|
857
|
-
edge_type: list[str],
|
|
858
|
-
bfs: bool,
|
|
859
|
-
edge_limit: int,
|
|
860
|
-
node_limit: int,
|
|
861
|
-
dot_file: Optional[str],
|
|
862
|
-
) -> str:
|
|
863
|
-
"""Generate Dot file for visualizing nodes and edges."""
|
|
864
|
-
edge_type = edge_type if edge_type else []
|
|
865
|
-
visited_nodes: list[NodeArchitype] = []
|
|
866
|
-
node_depths: dict[NodeArchitype, int] = {node: 0}
|
|
867
|
-
queue: list = [[node, 0]]
|
|
868
|
-
connections: list[tuple[NodeArchitype, NodeArchitype, EdgeArchitype]] = []
|
|
869
|
-
|
|
870
|
-
def dfs(node: NodeArchitype, cur_depth: int) -> None:
|
|
871
|
-
"""Depth first search."""
|
|
872
|
-
if node not in visited_nodes:
|
|
873
|
-
visited_nodes.append(node)
|
|
874
|
-
traverse_graph(
|
|
875
|
-
node,
|
|
876
|
-
cur_depth,
|
|
877
|
-
depth,
|
|
878
|
-
edge_type,
|
|
879
|
-
traverse,
|
|
880
|
-
connections,
|
|
881
|
-
node_depths,
|
|
882
|
-
visited_nodes,
|
|
883
|
-
queue,
|
|
884
|
-
bfs,
|
|
885
|
-
dfs,
|
|
886
|
-
node_limit,
|
|
887
|
-
edge_limit,
|
|
888
|
-
)
|
|
889
|
-
|
|
890
|
-
if bfs:
|
|
891
|
-
cur_depth = 0
|
|
892
|
-
while queue:
|
|
893
|
-
current_node, cur_depth = queue.pop(0)
|
|
894
|
-
if current_node not in visited_nodes:
|
|
895
|
-
visited_nodes.append(current_node)
|
|
896
|
-
traverse_graph(
|
|
897
|
-
current_node,
|
|
898
|
-
cur_depth,
|
|
899
|
-
depth,
|
|
900
|
-
edge_type,
|
|
901
|
-
traverse,
|
|
902
|
-
connections,
|
|
903
|
-
node_depths,
|
|
904
|
-
visited_nodes,
|
|
905
|
-
queue,
|
|
906
|
-
bfs,
|
|
907
|
-
dfs,
|
|
908
|
-
node_limit,
|
|
909
|
-
edge_limit,
|
|
910
|
-
)
|
|
911
|
-
else:
|
|
912
|
-
dfs(node, cur_depth=0)
|
|
913
|
-
dot_content = (
|
|
914
|
-
'digraph {\nnode [style="filled", shape="ellipse", '
|
|
915
|
-
'fillcolor="invis", fontcolor="black"];\n'
|
|
916
|
-
)
|
|
917
|
-
for source, target, edge in connections:
|
|
918
|
-
dot_content += (
|
|
919
|
-
f"{visited_nodes.index(source)} -> {visited_nodes.index(target)} "
|
|
920
|
-
f' [label="{html.escape(str(edge.__jac__.architype))} "];\n'
|
|
921
|
-
)
|
|
922
|
-
for node_ in visited_nodes:
|
|
923
|
-
color = (
|
|
924
|
-
colors[node_depths[node_]] if node_depths[node_] < 25 else colors[24]
|
|
925
|
-
)
|
|
926
|
-
dot_content += (
|
|
927
|
-
f'{visited_nodes.index(node_)} [label="{html.escape(str(node_.__jac__.architype))}"'
|
|
928
|
-
f'fillcolor="{color}"];\n'
|
|
929
|
-
)
|
|
930
|
-
if dot_file:
|
|
931
|
-
with open(dot_file, "w") as f:
|
|
932
|
-
f.write(dot_content + "}")
|
|
933
|
-
return dot_content + "}"
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
class JacCmdDefaults:
|
|
937
|
-
"""Jac CLI command."""
|
|
938
|
-
|
|
939
|
-
@staticmethod
|
|
940
|
-
@hookimpl
|
|
941
|
-
def create_cmd() -> None:
|
|
942
|
-
"""Create Jac CLI cmds."""
|
|
943
|
-
pass
|