jaclang 0.8.0__py3-none-any.whl → 0.8.2__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 +6 -0
- jaclang/cli/cli.py +23 -50
- jaclang/compiler/codeinfo.py +0 -1
- jaclang/compiler/jac.lark +14 -22
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +378 -531
- jaclang/compiler/passes/main/__init__.py +0 -14
- jaclang/compiler/passes/main/annex_pass.py +2 -8
- jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
- jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
- jaclang/compiler/passes/main/def_use_pass.py +4 -7
- jaclang/compiler/passes/main/import_pass.py +6 -14
- jaclang/compiler/passes/main/inheritance_pass.py +2 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
- jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
- jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
- jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
- jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
- jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
- jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
- jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
- jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
- jaclang/compiler/program.py +22 -66
- jaclang/compiler/tests/fixtures/fam.jac +2 -2
- jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
- jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
- jaclang/compiler/tests/test_importer.py +30 -13
- jaclang/compiler/tests/test_parser.py +1 -0
- jaclang/compiler/unitree.py +488 -320
- jaclang/langserve/__init__.jac +1 -0
- jaclang/langserve/engine.jac +503 -0
- jaclang/langserve/sem_manager.jac +309 -0
- jaclang/langserve/server.jac +201 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
- jaclang/langserve/tests/server_test/utils.py +35 -6
- jaclang/langserve/tests/session.jac +294 -0
- jaclang/langserve/tests/test_sem_tokens.py +2 -2
- jaclang/langserve/tests/test_server.py +8 -7
- jaclang/langserve/utils.jac +51 -30
- jaclang/runtimelib/archetype.py +128 -6
- jaclang/runtimelib/builtin.py +17 -14
- jaclang/runtimelib/importer.py +51 -76
- jaclang/runtimelib/machine.py +469 -305
- jaclang/runtimelib/meta_importer.py +86 -0
- jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
- jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
- jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
- jaclang/runtimelib/tests/test_jaseci.py +3 -1
- jaclang/runtimelib/utils.py +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
- jaclang/tests/fixtures/async_ability.jac +43 -10
- jaclang/tests/fixtures/async_function.jac +18 -0
- jaclang/tests/fixtures/async_walker.jac +17 -12
- jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
- jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
- jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
- jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
- jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
- jaclang/tests/fixtures/concurrency.jac +1 -1
- jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
- jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
- jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
- jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +2 -2
- jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
- jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
- jaclang/tests/fixtures/edge_ability.jac +49 -0
- jaclang/tests/fixtures/foo.jac +14 -22
- jaclang/tests/fixtures/guess_game.jac +1 -1
- jaclang/tests/fixtures/here_usage_error.jac +21 -0
- jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
- jaclang/tests/fixtures/jac_from_py.py +1 -1
- jaclang/tests/fixtures/jp_importer.jac +6 -6
- jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
- jaclang/tests/fixtures/node_del.jac +30 -36
- jaclang/tests/fixtures/unicode_strings.jac +24 -0
- jaclang/tests/fixtures/visit_traversal.jac +47 -0
- jaclang/tests/fixtures/walker_update.jac +5 -7
- jaclang/tests/test_cli.py +12 -7
- jaclang/tests/test_language.py +218 -145
- jaclang/tests/test_reference.py +9 -4
- jaclang/tests/test_typecheck.py +13 -26
- jaclang/utils/helpers.py +14 -6
- jaclang/utils/lang_tools.py +9 -8
- jaclang/utils/module_resolver.py +23 -0
- jaclang/utils/tests/test_lang_tools.py +2 -1
- jaclang/utils/treeprinter.py +3 -4
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
- jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
- jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
- jaclang/langserve/__init__.py +0 -1
- jaclang/langserve/engine.py +0 -553
- jaclang/langserve/sem_manager.py +0 -383
- jaclang/langserve/server.py +0 -167
- jaclang/langserve/tests/session.py +0 -255
- jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
- jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
- jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
jaclang/runtimelib/machine.py
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import ast as ast3
|
|
6
|
-
import asyncio
|
|
7
6
|
import fnmatch
|
|
8
7
|
import html
|
|
9
8
|
import inspect
|
|
@@ -14,12 +13,13 @@ import types
|
|
|
14
13
|
from collections import OrderedDict
|
|
15
14
|
from concurrent.futures import Future, ThreadPoolExecutor
|
|
16
15
|
from dataclasses import MISSING, dataclass, field
|
|
17
|
-
from functools import
|
|
16
|
+
from functools import wraps
|
|
18
17
|
from inspect import getfile
|
|
19
18
|
from logging import getLogger
|
|
20
19
|
from typing import (
|
|
21
20
|
Any,
|
|
22
21
|
Callable,
|
|
22
|
+
Coroutine,
|
|
23
23
|
Mapping,
|
|
24
24
|
Optional,
|
|
25
25
|
ParamSpec,
|
|
@@ -39,7 +39,9 @@ from jaclang.compiler.constant import Constants as Con, EdgeDir, colors
|
|
|
39
39
|
from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass
|
|
40
40
|
from jaclang.compiler.program import JacProgram
|
|
41
41
|
from jaclang.runtimelib.archetype import (
|
|
42
|
+
DataSpatialDestination,
|
|
42
43
|
DataSpatialFunction,
|
|
44
|
+
DataSpatialPath,
|
|
43
45
|
GenericEdge as _GenericEdge,
|
|
44
46
|
Root as _Root,
|
|
45
47
|
)
|
|
@@ -77,6 +79,64 @@ T = TypeVar("T")
|
|
|
77
79
|
P = ParamSpec("P")
|
|
78
80
|
|
|
79
81
|
|
|
82
|
+
class ExecutionContext:
|
|
83
|
+
"""Execution Context."""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
session: Optional[str] = None,
|
|
88
|
+
root: Optional[str] = None,
|
|
89
|
+
) -> None:
|
|
90
|
+
"""Initialize JacMachine."""
|
|
91
|
+
self.mem: Memory = ShelfStorage(session)
|
|
92
|
+
self.reports: list[Any] = []
|
|
93
|
+
sr_arch = Root()
|
|
94
|
+
sr_anch = sr_arch.__jac__
|
|
95
|
+
sr_anch.id = UUID(Con.SUPER_ROOT_UUID)
|
|
96
|
+
sr_anch.persistent = False
|
|
97
|
+
self.system_root = sr_anch
|
|
98
|
+
self.custom: Any = MISSING
|
|
99
|
+
if not isinstance(
|
|
100
|
+
system_root := self.mem.find_by_id(UUID(Con.SUPER_ROOT_UUID)), NodeAnchor
|
|
101
|
+
):
|
|
102
|
+
system_root = cast(NodeAnchor, Root().__jac__) # type: ignore[attr-defined]
|
|
103
|
+
system_root.id = UUID(Con.SUPER_ROOT_UUID)
|
|
104
|
+
self.mem.set(system_root.id, system_root)
|
|
105
|
+
|
|
106
|
+
self.system_root = system_root
|
|
107
|
+
|
|
108
|
+
self.entry_node = self.root_state = self.init_anchor(root, self.system_root)
|
|
109
|
+
|
|
110
|
+
def init_anchor(
|
|
111
|
+
self,
|
|
112
|
+
anchor_id: str | None,
|
|
113
|
+
default: NodeAnchor,
|
|
114
|
+
) -> NodeAnchor:
|
|
115
|
+
"""Load initial anchors."""
|
|
116
|
+
if anchor_id:
|
|
117
|
+
if isinstance(anchor := self.mem.find_by_id(UUID(anchor_id)), NodeAnchor):
|
|
118
|
+
return anchor
|
|
119
|
+
raise ValueError(f"Invalid anchor id {anchor_id} !")
|
|
120
|
+
return default
|
|
121
|
+
|
|
122
|
+
def set_entry_node(self, entry_node: str | None) -> None:
|
|
123
|
+
"""Override entry."""
|
|
124
|
+
self.entry_node = self.init_anchor(entry_node, self.root_state)
|
|
125
|
+
|
|
126
|
+
def close(self) -> None:
|
|
127
|
+
"""Close current ExecutionContext."""
|
|
128
|
+
self.mem.close()
|
|
129
|
+
JacMachine.reset_machine()
|
|
130
|
+
|
|
131
|
+
def get_root(self) -> Root:
|
|
132
|
+
"""Get current root."""
|
|
133
|
+
return cast(Root, self.root_state.archetype)
|
|
134
|
+
|
|
135
|
+
def global_system_root(self) -> NodeAnchor:
|
|
136
|
+
"""Get global system root."""
|
|
137
|
+
return self.system_root
|
|
138
|
+
|
|
139
|
+
|
|
80
140
|
class JacAccessValidation:
|
|
81
141
|
"""Jac Access Validation Specs."""
|
|
82
142
|
|
|
@@ -233,69 +293,105 @@ class JacNode:
|
|
|
233
293
|
|
|
234
294
|
@staticmethod
|
|
235
295
|
def get_edges(
|
|
236
|
-
|
|
237
|
-
dir: EdgeDir,
|
|
238
|
-
filter: Callable[[EdgeArchetype], bool] | None,
|
|
239
|
-
target_obj: list[NodeArchetype] | None,
|
|
296
|
+
origin: list[NodeArchetype], destination: DataSpatialDestination
|
|
240
297
|
) -> list[EdgeArchetype]:
|
|
241
298
|
"""Get edges connected to this node."""
|
|
242
|
-
|
|
243
|
-
for
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
and (target := anchor.target)
|
|
247
|
-
and (not filter or filter(anchor.archetype))
|
|
248
|
-
and source.archetype
|
|
249
|
-
and target.archetype
|
|
250
|
-
):
|
|
299
|
+
edges: OrderedDict[EdgeAnchor, EdgeArchetype] = OrderedDict()
|
|
300
|
+
for node in origin:
|
|
301
|
+
nanch = node.__jac__
|
|
302
|
+
for anchor in nanch.edges:
|
|
251
303
|
if (
|
|
252
|
-
|
|
253
|
-
and
|
|
254
|
-
and (
|
|
255
|
-
and
|
|
304
|
+
(source := anchor.source)
|
|
305
|
+
and (target := anchor.target)
|
|
306
|
+
and destination.edge_filter(anchor.archetype)
|
|
307
|
+
and source.archetype
|
|
308
|
+
and target.archetype
|
|
256
309
|
):
|
|
257
|
-
|
|
310
|
+
if (
|
|
311
|
+
destination.direction in [EdgeDir.OUT, EdgeDir.ANY]
|
|
312
|
+
and nanch == source
|
|
313
|
+
and destination.node_filter(target.archetype)
|
|
314
|
+
and JacMachineInterface.check_read_access(target)
|
|
315
|
+
):
|
|
316
|
+
edges[anchor] = anchor.archetype
|
|
317
|
+
if (
|
|
318
|
+
destination.direction in [EdgeDir.IN, EdgeDir.ANY]
|
|
319
|
+
and nanch == target
|
|
320
|
+
and destination.node_filter(source.archetype)
|
|
321
|
+
and JacMachineInterface.check_read_access(source)
|
|
322
|
+
):
|
|
323
|
+
edges[anchor] = anchor.archetype
|
|
324
|
+
return list(edges.values())
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def get_edges_with_node(
|
|
328
|
+
origin: list[NodeArchetype],
|
|
329
|
+
destination: DataSpatialDestination,
|
|
330
|
+
from_visit: bool = False,
|
|
331
|
+
) -> list[EdgeArchetype | NodeArchetype]:
|
|
332
|
+
"""Get edges connected to this node and the node."""
|
|
333
|
+
loc: OrderedDict[
|
|
334
|
+
Union[NodeAnchor, EdgeAnchor], Union[NodeArchetype, EdgeArchetype]
|
|
335
|
+
] = OrderedDict()
|
|
336
|
+
for node in origin:
|
|
337
|
+
nanch = node.__jac__
|
|
338
|
+
for anchor in nanch.edges:
|
|
258
339
|
if (
|
|
259
|
-
|
|
260
|
-
and
|
|
261
|
-
and (
|
|
262
|
-
and
|
|
340
|
+
(source := anchor.source)
|
|
341
|
+
and (target := anchor.target)
|
|
342
|
+
and destination.edge_filter(anchor.archetype)
|
|
343
|
+
and source.archetype
|
|
344
|
+
and target.archetype
|
|
263
345
|
):
|
|
264
|
-
|
|
265
|
-
|
|
346
|
+
if (
|
|
347
|
+
destination.direction in [EdgeDir.OUT, EdgeDir.ANY]
|
|
348
|
+
and nanch == source
|
|
349
|
+
and destination.node_filter(target.archetype)
|
|
350
|
+
and JacMachineInterface.check_read_access(target)
|
|
351
|
+
):
|
|
352
|
+
loc[anchor] = anchor.archetype
|
|
353
|
+
loc[target] = target.archetype
|
|
354
|
+
if (
|
|
355
|
+
destination.direction in [EdgeDir.IN, EdgeDir.ANY]
|
|
356
|
+
and nanch == target
|
|
357
|
+
and destination.node_filter(source.archetype)
|
|
358
|
+
and JacMachineInterface.check_read_access(source)
|
|
359
|
+
):
|
|
360
|
+
loc[anchor] = anchor.archetype
|
|
361
|
+
loc[source] = source.archetype
|
|
362
|
+
return list(loc.values())
|
|
266
363
|
|
|
267
364
|
@staticmethod
|
|
268
365
|
def edges_to_nodes(
|
|
269
|
-
|
|
270
|
-
dir: EdgeDir,
|
|
271
|
-
filter: Callable[[EdgeArchetype], bool] | None,
|
|
272
|
-
target_obj: list[NodeArchetype] | None,
|
|
366
|
+
origin: list[NodeArchetype], destination: DataSpatialDestination
|
|
273
367
|
) -> list[NodeArchetype]:
|
|
274
368
|
"""Get set of nodes connected to this node."""
|
|
275
|
-
|
|
276
|
-
for
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
and (target := anchor.target)
|
|
280
|
-
and (not filter or filter(anchor.archetype))
|
|
281
|
-
and source.archetype
|
|
282
|
-
and target.archetype
|
|
283
|
-
):
|
|
369
|
+
nodes: OrderedDict[NodeAnchor, NodeArchetype] = OrderedDict()
|
|
370
|
+
for node in origin:
|
|
371
|
+
nanch = node.__jac__
|
|
372
|
+
for anchor in nanch.edges:
|
|
284
373
|
if (
|
|
285
|
-
|
|
286
|
-
and
|
|
287
|
-
and (
|
|
288
|
-
and
|
|
289
|
-
|
|
290
|
-
ret_edges.append(target.archetype)
|
|
291
|
-
if (
|
|
292
|
-
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
293
|
-
and node == target
|
|
294
|
-
and (not target_obj or source.archetype in target_obj)
|
|
295
|
-
and JacMachineInterface.check_read_access(source)
|
|
374
|
+
(source := anchor.source)
|
|
375
|
+
and (target := anchor.target)
|
|
376
|
+
and destination.edge_filter(anchor.archetype)
|
|
377
|
+
and source.archetype
|
|
378
|
+
and target.archetype
|
|
296
379
|
):
|
|
297
|
-
|
|
298
|
-
|
|
380
|
+
if (
|
|
381
|
+
destination.direction in [EdgeDir.OUT, EdgeDir.ANY]
|
|
382
|
+
and nanch == source
|
|
383
|
+
and destination.node_filter(target.archetype)
|
|
384
|
+
and JacMachineInterface.check_read_access(target)
|
|
385
|
+
):
|
|
386
|
+
nodes[target] = target.archetype
|
|
387
|
+
if (
|
|
388
|
+
destination.direction in [EdgeDir.IN, EdgeDir.ANY]
|
|
389
|
+
and nanch == target
|
|
390
|
+
and destination.node_filter(source.archetype)
|
|
391
|
+
and JacMachineInterface.check_read_access(source)
|
|
392
|
+
):
|
|
393
|
+
nodes[source] = source.archetype
|
|
394
|
+
return list(nodes.values())
|
|
299
395
|
|
|
300
396
|
@staticmethod
|
|
301
397
|
def remove_edge(node: NodeAnchor, edge: EdgeAnchor) -> None:
|
|
@@ -329,23 +425,27 @@ class JacWalker:
|
|
|
329
425
|
| NodeArchetype
|
|
330
426
|
| EdgeArchetype
|
|
331
427
|
),
|
|
428
|
+
insert_loc: int = -1,
|
|
332
429
|
) -> bool: # noqa: ANN401
|
|
333
430
|
"""Jac's visit stmt feature."""
|
|
334
431
|
if isinstance(walker, WalkerArchetype):
|
|
335
432
|
"""Walker visits node."""
|
|
336
433
|
wanch = walker.__jac__
|
|
337
434
|
before_len = len(wanch.next)
|
|
435
|
+
next = []
|
|
338
436
|
for anchor in (
|
|
339
437
|
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
340
438
|
):
|
|
341
439
|
if anchor not in wanch.ignores:
|
|
342
|
-
if isinstance(anchor, NodeAnchor):
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
440
|
+
if isinstance(anchor, (NodeAnchor, EdgeAnchor)):
|
|
441
|
+
next.append(anchor)
|
|
442
|
+
else:
|
|
443
|
+
raise ValueError("Anchor should be NodeAnchor or EdgeAnchor.")
|
|
444
|
+
if insert_loc < -len(wanch.next): # for out of index selection
|
|
445
|
+
insert_loc = 0
|
|
446
|
+
elif insert_loc < 0:
|
|
447
|
+
insert_loc += len(wanch.next) + 1
|
|
448
|
+
wanch.next = wanch.next[:insert_loc] + next + wanch.next[insert_loc:]
|
|
349
449
|
return len(wanch.next) > before_len
|
|
350
450
|
else:
|
|
351
451
|
raise TypeError("Invalid walker object")
|
|
@@ -381,83 +481,199 @@ class JacWalker:
|
|
|
381
481
|
raise TypeError("Invalid walker object")
|
|
382
482
|
|
|
383
483
|
@staticmethod
|
|
384
|
-
def spawn_call(
|
|
484
|
+
def spawn_call(
|
|
485
|
+
walker: WalkerAnchor,
|
|
486
|
+
node: NodeAnchor | EdgeAnchor,
|
|
487
|
+
) -> WalkerArchetype:
|
|
488
|
+
"""Jac's spawn operator feature."""
|
|
489
|
+
warch = walker.archetype
|
|
490
|
+
walker.path = []
|
|
491
|
+
current_loc = node.archetype
|
|
492
|
+
|
|
493
|
+
# walker ability on any entry
|
|
494
|
+
for i in warch._jac_entry_funcs_:
|
|
495
|
+
if not i.trigger:
|
|
496
|
+
i.func(warch, current_loc)
|
|
497
|
+
if walker.disengaged:
|
|
498
|
+
return warch
|
|
499
|
+
|
|
500
|
+
while len(walker.next):
|
|
501
|
+
if current_loc := walker.next.pop(0).archetype:
|
|
502
|
+
# walker ability with loc entry
|
|
503
|
+
for i in warch._jac_entry_funcs_:
|
|
504
|
+
if (
|
|
505
|
+
i.trigger
|
|
506
|
+
and (
|
|
507
|
+
all_issubclass(i.trigger, NodeArchetype)
|
|
508
|
+
or all_issubclass(i.trigger, EdgeArchetype)
|
|
509
|
+
)
|
|
510
|
+
and isinstance(current_loc, i.trigger)
|
|
511
|
+
):
|
|
512
|
+
i.func(warch, current_loc)
|
|
513
|
+
if walker.disengaged:
|
|
514
|
+
return warch
|
|
515
|
+
|
|
516
|
+
# loc ability with any entry
|
|
517
|
+
for i in current_loc._jac_entry_funcs_:
|
|
518
|
+
if not i.trigger:
|
|
519
|
+
i.func(current_loc, warch)
|
|
520
|
+
if walker.disengaged:
|
|
521
|
+
return warch
|
|
522
|
+
|
|
523
|
+
# loc ability with walker entry
|
|
524
|
+
for i in current_loc._jac_entry_funcs_:
|
|
525
|
+
if (
|
|
526
|
+
i.trigger
|
|
527
|
+
and all_issubclass(i.trigger, WalkerArchetype)
|
|
528
|
+
and isinstance(warch, i.trigger)
|
|
529
|
+
):
|
|
530
|
+
i.func(current_loc, warch)
|
|
531
|
+
if walker.disengaged:
|
|
532
|
+
return warch
|
|
533
|
+
|
|
534
|
+
# loc ability with walker exit
|
|
535
|
+
for i in current_loc._jac_exit_funcs_:
|
|
536
|
+
if (
|
|
537
|
+
i.trigger
|
|
538
|
+
and all_issubclass(i.trigger, WalkerArchetype)
|
|
539
|
+
and isinstance(warch, i.trigger)
|
|
540
|
+
):
|
|
541
|
+
i.func(current_loc, warch)
|
|
542
|
+
if walker.disengaged:
|
|
543
|
+
return warch
|
|
544
|
+
|
|
545
|
+
# loc ability with any exit
|
|
546
|
+
for i in current_loc._jac_exit_funcs_:
|
|
547
|
+
if not i.trigger:
|
|
548
|
+
i.func(current_loc, warch)
|
|
549
|
+
if walker.disengaged:
|
|
550
|
+
return warch
|
|
551
|
+
|
|
552
|
+
# walker ability with loc exit
|
|
553
|
+
for i in warch._jac_exit_funcs_:
|
|
554
|
+
if (
|
|
555
|
+
i.trigger
|
|
556
|
+
and (
|
|
557
|
+
all_issubclass(i.trigger, NodeArchetype)
|
|
558
|
+
or all_issubclass(i.trigger, EdgeArchetype)
|
|
559
|
+
)
|
|
560
|
+
and isinstance(current_loc, i.trigger)
|
|
561
|
+
):
|
|
562
|
+
i.func(warch, current_loc)
|
|
563
|
+
if walker.disengaged:
|
|
564
|
+
return warch
|
|
565
|
+
# walker ability with any exit
|
|
566
|
+
for i in warch._jac_exit_funcs_:
|
|
567
|
+
if not i.trigger:
|
|
568
|
+
i.func(warch, current_loc)
|
|
569
|
+
if walker.disengaged:
|
|
570
|
+
return warch
|
|
571
|
+
|
|
572
|
+
walker.ignores = []
|
|
573
|
+
return warch
|
|
574
|
+
|
|
575
|
+
@staticmethod
|
|
576
|
+
async def async_spawn_call(
|
|
577
|
+
walker: WalkerAnchor,
|
|
578
|
+
node: NodeAnchor | EdgeAnchor,
|
|
579
|
+
) -> WalkerArchetype:
|
|
385
580
|
"""Jac's spawn operator feature."""
|
|
386
581
|
warch = walker.archetype
|
|
387
582
|
walker.path = []
|
|
388
|
-
|
|
389
|
-
current_node = node.archetype
|
|
583
|
+
current_loc = node.archetype
|
|
390
584
|
|
|
391
|
-
# walker entry
|
|
585
|
+
# walker ability on any entry
|
|
392
586
|
for i in warch._jac_entry_funcs_:
|
|
393
587
|
if not i.trigger:
|
|
394
|
-
i.func(warch,
|
|
588
|
+
result = i.func(warch, current_loc)
|
|
589
|
+
if isinstance(result, Coroutine):
|
|
590
|
+
await result
|
|
395
591
|
if walker.disengaged:
|
|
396
592
|
return warch
|
|
397
593
|
|
|
398
594
|
while len(walker.next):
|
|
399
|
-
if
|
|
400
|
-
# walker
|
|
595
|
+
if current_loc := walker.next.pop(0).archetype:
|
|
596
|
+
# walker ability with loc entry
|
|
401
597
|
for i in warch._jac_entry_funcs_:
|
|
402
598
|
if (
|
|
403
599
|
i.trigger
|
|
404
|
-
and
|
|
405
|
-
|
|
600
|
+
and (
|
|
601
|
+
all_issubclass(i.trigger, NodeArchetype)
|
|
602
|
+
or all_issubclass(i.trigger, EdgeArchetype)
|
|
603
|
+
)
|
|
604
|
+
and isinstance(current_loc, i.trigger)
|
|
406
605
|
):
|
|
407
|
-
i.func(warch,
|
|
606
|
+
result = i.func(warch, current_loc)
|
|
607
|
+
if isinstance(result, Coroutine):
|
|
608
|
+
await result
|
|
408
609
|
if walker.disengaged:
|
|
409
610
|
return warch
|
|
410
611
|
|
|
411
|
-
#
|
|
412
|
-
for i in
|
|
612
|
+
# loc ability with any entry
|
|
613
|
+
for i in current_loc._jac_entry_funcs_:
|
|
413
614
|
if not i.trigger:
|
|
414
|
-
i.func(
|
|
615
|
+
result = i.func(current_loc, warch)
|
|
616
|
+
if isinstance(result, Coroutine):
|
|
617
|
+
await result
|
|
415
618
|
if walker.disengaged:
|
|
416
619
|
return warch
|
|
417
620
|
|
|
418
|
-
#
|
|
419
|
-
for i in
|
|
621
|
+
# loc ability with walker entry
|
|
622
|
+
for i in current_loc._jac_entry_funcs_:
|
|
420
623
|
if (
|
|
421
624
|
i.trigger
|
|
422
625
|
and all_issubclass(i.trigger, WalkerArchetype)
|
|
423
626
|
and isinstance(warch, i.trigger)
|
|
424
627
|
):
|
|
425
|
-
i.func(
|
|
628
|
+
result = i.func(current_loc, warch)
|
|
629
|
+
if isinstance(result, Coroutine):
|
|
630
|
+
await result
|
|
426
631
|
if walker.disengaged:
|
|
427
632
|
return warch
|
|
428
633
|
|
|
429
|
-
#
|
|
430
|
-
for i in
|
|
634
|
+
# loc ability with walker exit
|
|
635
|
+
for i in current_loc._jac_exit_funcs_:
|
|
431
636
|
if (
|
|
432
637
|
i.trigger
|
|
433
638
|
and all_issubclass(i.trigger, WalkerArchetype)
|
|
434
639
|
and isinstance(warch, i.trigger)
|
|
435
640
|
):
|
|
436
|
-
i.func(
|
|
641
|
+
result = i.func(current_loc, warch)
|
|
642
|
+
if isinstance(result, Coroutine):
|
|
643
|
+
await result
|
|
437
644
|
if walker.disengaged:
|
|
438
645
|
return warch
|
|
439
646
|
|
|
440
|
-
#
|
|
441
|
-
for i in
|
|
647
|
+
# loc ability with any exit
|
|
648
|
+
for i in current_loc._jac_exit_funcs_:
|
|
442
649
|
if not i.trigger:
|
|
443
|
-
i.func(
|
|
650
|
+
result = i.func(current_loc, warch)
|
|
651
|
+
if isinstance(result, Coroutine):
|
|
652
|
+
await result
|
|
444
653
|
if walker.disengaged:
|
|
445
654
|
return warch
|
|
446
655
|
|
|
447
|
-
# walker
|
|
656
|
+
# walker ability with loc exit
|
|
448
657
|
for i in warch._jac_exit_funcs_:
|
|
449
658
|
if (
|
|
450
659
|
i.trigger
|
|
451
|
-
and
|
|
452
|
-
|
|
660
|
+
and (
|
|
661
|
+
all_issubclass(i.trigger, NodeArchetype)
|
|
662
|
+
or all_issubclass(i.trigger, EdgeArchetype)
|
|
663
|
+
)
|
|
664
|
+
and isinstance(current_loc, i.trigger)
|
|
453
665
|
):
|
|
454
|
-
i.func(warch,
|
|
666
|
+
result = i.func(warch, current_loc)
|
|
667
|
+
if isinstance(result, Coroutine):
|
|
668
|
+
await result
|
|
455
669
|
if walker.disengaged:
|
|
456
670
|
return warch
|
|
457
|
-
# walker exit
|
|
671
|
+
# walker ability with any exit
|
|
458
672
|
for i in warch._jac_exit_funcs_:
|
|
459
673
|
if not i.trigger:
|
|
460
|
-
i.func(warch,
|
|
674
|
+
result = i.func(warch, current_loc)
|
|
675
|
+
if isinstance(result, Coroutine):
|
|
676
|
+
await result
|
|
461
677
|
if walker.disengaged:
|
|
462
678
|
return warch
|
|
463
679
|
|
|
@@ -465,14 +681,16 @@ class JacWalker:
|
|
|
465
681
|
return warch
|
|
466
682
|
|
|
467
683
|
@staticmethod
|
|
468
|
-
def spawn(op1: Archetype, op2: Archetype) -> WalkerArchetype |
|
|
684
|
+
def spawn(op1: Archetype, op2: Archetype) -> WalkerArchetype | Coroutine:
|
|
469
685
|
"""Jac's spawn operator feature."""
|
|
686
|
+
edge: EdgeAnchor | None = None
|
|
470
687
|
if isinstance(op1, WalkerArchetype):
|
|
471
688
|
warch = op1
|
|
472
689
|
walker = op1.__jac__
|
|
473
690
|
if isinstance(op2, NodeArchetype):
|
|
474
691
|
node = op2.__jac__
|
|
475
692
|
elif isinstance(op2, EdgeArchetype):
|
|
693
|
+
edge = op2.__jac__
|
|
476
694
|
node = op2.__jac__.target
|
|
477
695
|
else:
|
|
478
696
|
raise TypeError("Invalid target object")
|
|
@@ -482,21 +700,24 @@ class JacWalker:
|
|
|
482
700
|
if isinstance(op1, NodeArchetype):
|
|
483
701
|
node = op1.__jac__
|
|
484
702
|
elif isinstance(op1, EdgeArchetype):
|
|
703
|
+
edge = op1.__jac__
|
|
485
704
|
node = op1.__jac__.target
|
|
486
705
|
else:
|
|
487
706
|
raise TypeError("Invalid target object")
|
|
488
707
|
else:
|
|
489
708
|
raise TypeError("Invalid walker object")
|
|
490
709
|
|
|
710
|
+
if edge is not None:
|
|
711
|
+
loc: EdgeAnchor | NodeAnchor = edge
|
|
712
|
+
walker.next = [edge, node]
|
|
713
|
+
else:
|
|
714
|
+
loc = node
|
|
715
|
+
walker.next = [node]
|
|
716
|
+
|
|
491
717
|
if warch.__jac_async__:
|
|
492
|
-
|
|
493
|
-
_event_loop = machine._event_loop
|
|
494
|
-
func = partial(JacMachineInterface.spawn_call, *(walker, node))
|
|
495
|
-
return asyncio.ensure_future(
|
|
496
|
-
_event_loop.run_in_executor(None, func), loop=_event_loop
|
|
497
|
-
)
|
|
718
|
+
return JacMachineInterface.async_spawn_call(walker=walker, node=loc)
|
|
498
719
|
else:
|
|
499
|
-
return JacMachineInterface.spawn_call(walker=walker, node=
|
|
720
|
+
return JacMachineInterface.spawn_call(walker=walker, node=loc)
|
|
500
721
|
|
|
501
722
|
@staticmethod
|
|
502
723
|
def disengage(walker: WalkerArchetype) -> bool:
|
|
@@ -520,12 +741,14 @@ class JacClassReferences:
|
|
|
520
741
|
Root: TypeAlias = _Root
|
|
521
742
|
GenericEdge: TypeAlias = _GenericEdge
|
|
522
743
|
|
|
744
|
+
Path: TypeAlias = DataSpatialPath
|
|
745
|
+
|
|
523
746
|
|
|
524
747
|
class JacBuiltin:
|
|
525
748
|
"""Jac Builtins."""
|
|
526
749
|
|
|
527
750
|
@staticmethod
|
|
528
|
-
def
|
|
751
|
+
def printgraph(
|
|
529
752
|
node: NodeArchetype,
|
|
530
753
|
depth: int,
|
|
531
754
|
traverse: bool,
|
|
@@ -533,9 +756,10 @@ class JacBuiltin:
|
|
|
533
756
|
bfs: bool,
|
|
534
757
|
edge_limit: int,
|
|
535
758
|
node_limit: int,
|
|
536
|
-
|
|
759
|
+
file: Optional[str],
|
|
760
|
+
format: str,
|
|
537
761
|
) -> str:
|
|
538
|
-
"""Generate
|
|
762
|
+
"""Generate graph for visualizing nodes and edges."""
|
|
539
763
|
edge_type = edge_type if edge_type else []
|
|
540
764
|
visited_nodes: list[NodeArchetype] = []
|
|
541
765
|
node_depths: dict[NodeArchetype, int] = {node: 0}
|
|
@@ -589,24 +813,32 @@ class JacBuiltin:
|
|
|
589
813
|
'digraph {\nnode [style="filled", shape="ellipse", '
|
|
590
814
|
'fillcolor="invis", fontcolor="black"];\n'
|
|
591
815
|
)
|
|
816
|
+
mermaid_content = "flowchart LR\n"
|
|
592
817
|
for source, target, edge in connections:
|
|
593
818
|
edge_label = html.escape(str(edge.__jac__.archetype))
|
|
594
819
|
dot_content += (
|
|
595
820
|
f"{visited_nodes.index(source)} -> {visited_nodes.index(target)} "
|
|
596
821
|
f' [label="{edge_label if "GenericEdge" not in edge_label else ""}"];\n'
|
|
597
822
|
)
|
|
823
|
+
mermaid_content += (
|
|
824
|
+
f"{visited_nodes.index(source)} -->"
|
|
825
|
+
f"|{edge_label if 'GenericEdge' not in edge_label else ''}| {visited_nodes.index(target)}\n"
|
|
826
|
+
)
|
|
598
827
|
for node_ in visited_nodes:
|
|
599
828
|
color = (
|
|
600
829
|
colors[node_depths[node_]] if node_depths[node_] < 25 else colors[24]
|
|
601
830
|
)
|
|
831
|
+
label = html.escape(str(node_.__jac__.archetype))
|
|
602
832
|
dot_content += (
|
|
603
|
-
f'{visited_nodes.index(node_)} [label="{
|
|
833
|
+
f'{visited_nodes.index(node_)} [label="{label}"'
|
|
604
834
|
f'fillcolor="{color}"];\n'
|
|
605
835
|
)
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
836
|
+
mermaid_content += f'{visited_nodes.index(node_)}["{label}"]\n'
|
|
837
|
+
output = dot_content + "}" if format == "dot" else mermaid_content
|
|
838
|
+
if file:
|
|
839
|
+
with open(file, "w") as f:
|
|
840
|
+
f.write(output)
|
|
841
|
+
return output
|
|
610
842
|
|
|
611
843
|
|
|
612
844
|
class JacCmd:
|
|
@@ -625,9 +857,9 @@ class JacBasics:
|
|
|
625
857
|
"""Set Class References."""
|
|
626
858
|
|
|
627
859
|
@staticmethod
|
|
628
|
-
def get_context() ->
|
|
860
|
+
def get_context() -> ExecutionContext:
|
|
629
861
|
"""Get current execution context."""
|
|
630
|
-
return
|
|
862
|
+
return JacMachine.exec_ctx
|
|
631
863
|
|
|
632
864
|
@staticmethod
|
|
633
865
|
def reset_graph(root: Optional[Root] = None) -> int:
|
|
@@ -728,54 +960,8 @@ class JacBasics:
|
|
|
728
960
|
|
|
729
961
|
return decorator
|
|
730
962
|
|
|
731
|
-
@staticmethod
|
|
732
|
-
def py_get_jac_machine() -> JacMachine:
|
|
733
|
-
"""Get jac machine from python context."""
|
|
734
|
-
machine = JacBasics.py_find_jac_machine()
|
|
735
|
-
if not machine:
|
|
736
|
-
raise RuntimeError("Jac machine not found in python context. ")
|
|
737
|
-
return machine
|
|
738
|
-
|
|
739
|
-
@staticmethod
|
|
740
|
-
def py_find_jac_machine() -> Optional[JacMachine]:
|
|
741
|
-
"""Get jac machine from python context."""
|
|
742
|
-
machine = None
|
|
743
|
-
for i in inspect.stack():
|
|
744
|
-
machine = i.frame.f_globals.get("__jac_mach__") or i.frame.f_locals.get(
|
|
745
|
-
"__jac_mach__"
|
|
746
|
-
)
|
|
747
|
-
if machine:
|
|
748
|
-
break
|
|
749
|
-
return machine
|
|
750
|
-
|
|
751
|
-
@staticmethod
|
|
752
|
-
def py_jac_import(
|
|
753
|
-
target: str,
|
|
754
|
-
base_path: str,
|
|
755
|
-
absorb: bool = False,
|
|
756
|
-
mdl_alias: Optional[str] = None,
|
|
757
|
-
override_name: Optional[str] = None,
|
|
758
|
-
items: Optional[dict[str, Union[str, Optional[str]]]] = None,
|
|
759
|
-
reload_module: Optional[bool] = False,
|
|
760
|
-
) -> tuple[types.ModuleType, ...]:
|
|
761
|
-
"""Core Import Process."""
|
|
762
|
-
machine = JacBasics.py_find_jac_machine()
|
|
763
|
-
if not machine:
|
|
764
|
-
machine = JacMachine(base_path=base_path)
|
|
765
|
-
return JacMachineInterface.jac_import(
|
|
766
|
-
mach=machine,
|
|
767
|
-
target=target,
|
|
768
|
-
base_path=base_path,
|
|
769
|
-
absorb=absorb,
|
|
770
|
-
mdl_alias=mdl_alias,
|
|
771
|
-
override_name=override_name,
|
|
772
|
-
items=items,
|
|
773
|
-
reload_module=reload_module,
|
|
774
|
-
)
|
|
775
|
-
|
|
776
963
|
@staticmethod
|
|
777
964
|
def jac_import(
|
|
778
|
-
mach: JacMachine,
|
|
779
965
|
target: str,
|
|
780
966
|
base_path: str,
|
|
781
967
|
absorb: bool = False,
|
|
@@ -803,13 +989,13 @@ class JacBasics:
|
|
|
803
989
|
items,
|
|
804
990
|
)
|
|
805
991
|
|
|
806
|
-
if not
|
|
807
|
-
JacMachineInterface.attach_program(
|
|
992
|
+
if not JacMachine.program:
|
|
993
|
+
JacMachineInterface.attach_program(JacProgram())
|
|
808
994
|
|
|
809
995
|
if lng == "py":
|
|
810
|
-
import_result = PythonImporter(
|
|
996
|
+
import_result = PythonImporter().run_import(spec)
|
|
811
997
|
else:
|
|
812
|
-
import_result = JacImporter(
|
|
998
|
+
import_result = JacImporter().run_import(spec, reload_module)
|
|
813
999
|
|
|
814
1000
|
return (
|
|
815
1001
|
(import_result.ret_mod,)
|
|
@@ -833,7 +1019,6 @@ class JacBasics:
|
|
|
833
1019
|
|
|
834
1020
|
@staticmethod
|
|
835
1021
|
def run_test(
|
|
836
|
-
mach: JacMachine,
|
|
837
1022
|
filepath: str,
|
|
838
1023
|
func_name: Optional[str] = None,
|
|
839
1024
|
filter: Optional[str] = None,
|
|
@@ -853,9 +1038,7 @@ class JacBasics:
|
|
|
853
1038
|
if mod_name.endswith(".test"):
|
|
854
1039
|
mod_name = mod_name[:-5]
|
|
855
1040
|
JacTestCheck.reset()
|
|
856
|
-
JacMachineInterface.jac_import(
|
|
857
|
-
mach=mach, target=mod_name, base_path=base
|
|
858
|
-
)
|
|
1041
|
+
JacMachineInterface.jac_import(target=mod_name, base_path=base)
|
|
859
1042
|
JacTestCheck.run_test(
|
|
860
1043
|
xit, maxfail, verbose, os.path.abspath(filepath), func_name
|
|
861
1044
|
)
|
|
@@ -884,7 +1067,7 @@ class JacBasics:
|
|
|
884
1067
|
print(f"\n\n\t\t* Inside {root_dir}" + "/" + f"{file} *")
|
|
885
1068
|
JacTestCheck.reset()
|
|
886
1069
|
JacMachineInterface.jac_import(
|
|
887
|
-
|
|
1070
|
+
target=file[:-4], base_path=root_dir
|
|
888
1071
|
)
|
|
889
1072
|
JacTestCheck.run_test(
|
|
890
1073
|
xit, maxfail, verbose, os.path.abspath(file), func_name
|
|
@@ -919,40 +1102,31 @@ class JacBasics:
|
|
|
919
1102
|
|
|
920
1103
|
@staticmethod
|
|
921
1104
|
def refs(
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
edges_only: bool = False,
|
|
927
|
-
) -> list[NodeArchetype] | list[EdgeArchetype]:
|
|
1105
|
+
path: DataSpatialPath | NodeArchetype | list[NodeArchetype],
|
|
1106
|
+
) -> (
|
|
1107
|
+
list[NodeArchetype] | list[EdgeArchetype] | list[NodeArchetype | EdgeArchetype]
|
|
1108
|
+
):
|
|
928
1109
|
"""Jac's apply_dir stmt feature."""
|
|
929
|
-
if isinstance(
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
if edges_only:
|
|
937
|
-
connected_edges: list[EdgeArchetype] = []
|
|
938
|
-
for node in sources:
|
|
939
|
-
edges = JacMachineInterface.get_edges(
|
|
940
|
-
node.__jac__, dir, filter, target_obj=targ_obj_set
|
|
941
|
-
)
|
|
942
|
-
connected_edges.extend(
|
|
943
|
-
edge for edge in edges if edge not in connected_edges
|
|
944
|
-
)
|
|
945
|
-
return connected_edges
|
|
1110
|
+
if not isinstance(path, DataSpatialPath):
|
|
1111
|
+
path = DataSpatialPath(path, [DataSpatialDestination(EdgeDir.OUT)])
|
|
1112
|
+
|
|
1113
|
+
origin = path.origin
|
|
1114
|
+
|
|
1115
|
+
if path.edge_only:
|
|
1116
|
+
destinations = path.destinations[:-1]
|
|
946
1117
|
else:
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1118
|
+
destinations = path.destinations
|
|
1119
|
+
while destinations:
|
|
1120
|
+
dest = path.destinations.pop(0)
|
|
1121
|
+
origin = JacMachineInterface.edges_to_nodes(origin, dest)
|
|
1122
|
+
|
|
1123
|
+
if path.edge_only:
|
|
1124
|
+
if path.from_visit:
|
|
1125
|
+
return JacMachineInterface.get_edges_with_node(
|
|
1126
|
+
origin, path.destinations[-1]
|
|
954
1127
|
)
|
|
955
|
-
return
|
|
1128
|
+
return JacMachineInterface.get_edges(origin, path.destinations[-1])
|
|
1129
|
+
return origin
|
|
956
1130
|
|
|
957
1131
|
@staticmethod
|
|
958
1132
|
def filter(
|
|
@@ -1052,7 +1226,7 @@ class JacBasics:
|
|
|
1052
1226
|
@staticmethod
|
|
1053
1227
|
def root() -> Root:
|
|
1054
1228
|
"""Jac's root getter."""
|
|
1055
|
-
return
|
|
1229
|
+
return JacMachine.get_context().get_root()
|
|
1056
1230
|
|
|
1057
1231
|
@staticmethod
|
|
1058
1232
|
def build_edge(
|
|
@@ -1166,6 +1340,40 @@ class JacBasics:
|
|
|
1166
1340
|
"mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`."
|
|
1167
1341
|
)
|
|
1168
1342
|
|
|
1343
|
+
@staticmethod
|
|
1344
|
+
def gen_llm_call_override(
|
|
1345
|
+
_pass: PyastGenPass, node: ast.FuncCall
|
|
1346
|
+
) -> list[ast3.AST]:
|
|
1347
|
+
"""Generate python ast nodes for llm function body override syntax.
|
|
1348
|
+
|
|
1349
|
+
example:
|
|
1350
|
+
foo() by llm();
|
|
1351
|
+
"""
|
|
1352
|
+
_pass.log_warning(
|
|
1353
|
+
"MT-LLM is not installed. Please install it with `pip install mtllm`."
|
|
1354
|
+
)
|
|
1355
|
+
return [
|
|
1356
|
+
_pass.sync(
|
|
1357
|
+
ast3.Raise(
|
|
1358
|
+
_pass.sync(
|
|
1359
|
+
ast3.Call(
|
|
1360
|
+
func=_pass.sync(
|
|
1361
|
+
ast3.Name(id="ImportError", ctx=ast3.Load())
|
|
1362
|
+
),
|
|
1363
|
+
args=[
|
|
1364
|
+
_pass.sync(
|
|
1365
|
+
ast3.Constant(
|
|
1366
|
+
value="mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`." # noqa: E501
|
|
1367
|
+
)
|
|
1368
|
+
)
|
|
1369
|
+
],
|
|
1370
|
+
keywords=[],
|
|
1371
|
+
)
|
|
1372
|
+
)
|
|
1373
|
+
)
|
|
1374
|
+
)
|
|
1375
|
+
]
|
|
1376
|
+
|
|
1169
1377
|
@staticmethod
|
|
1170
1378
|
def gen_llm_body(_pass: PyastGenPass, node: ast.Ability) -> list[ast3.AST]:
|
|
1171
1379
|
"""Generate the by LLM body."""
|
|
@@ -1303,32 +1511,49 @@ class JacBasics:
|
|
|
1303
1511
|
"exclude_info": [],
|
|
1304
1512
|
}
|
|
1305
1513
|
|
|
1514
|
+
@staticmethod
|
|
1515
|
+
def get_semstr_type(
|
|
1516
|
+
file_loc: str, scope: str, attr: str, return_semstr: bool
|
|
1517
|
+
) -> Optional[str]:
|
|
1518
|
+
"""Jac's get_semstr_type feature."""
|
|
1519
|
+
|
|
1520
|
+
@staticmethod
|
|
1521
|
+
def obj_scope(file_loc: str, attr: str) -> str:
|
|
1522
|
+
"""Jac's gather_scope feature."""
|
|
1523
|
+
return ""
|
|
1524
|
+
|
|
1525
|
+
@staticmethod
|
|
1526
|
+
def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
|
|
1527
|
+
"""Jac's get_semstr_type implementation."""
|
|
1528
|
+
return None, None
|
|
1529
|
+
|
|
1306
1530
|
|
|
1307
1531
|
class JacUtils:
|
|
1308
1532
|
"""Jac Machine Utilities."""
|
|
1309
1533
|
|
|
1310
1534
|
@staticmethod
|
|
1311
|
-
def attach_program(
|
|
1535
|
+
def attach_program(jac_program: JacProgram) -> None:
|
|
1312
1536
|
"""Attach a JacProgram to the machine."""
|
|
1313
|
-
|
|
1537
|
+
JacMachine.program = jac_program
|
|
1314
1538
|
|
|
1315
1539
|
@staticmethod
|
|
1316
1540
|
def load_module(
|
|
1317
|
-
|
|
1541
|
+
module_name: str, module: types.ModuleType, force: bool = False
|
|
1318
1542
|
) -> None:
|
|
1319
1543
|
"""Load a module into the machine."""
|
|
1320
|
-
|
|
1321
|
-
|
|
1544
|
+
if module_name not in JacMachine.loaded_modules or force:
|
|
1545
|
+
JacMachine.loaded_modules[module_name] = module
|
|
1546
|
+
sys.modules[module_name] = module # TODO: May want to nuke this one day
|
|
1322
1547
|
|
|
1323
1548
|
@staticmethod
|
|
1324
|
-
def list_modules(
|
|
1549
|
+
def list_modules() -> list[str]:
|
|
1325
1550
|
"""List all loaded modules."""
|
|
1326
|
-
return list(
|
|
1551
|
+
return list(JacMachine.loaded_modules.keys())
|
|
1327
1552
|
|
|
1328
1553
|
@staticmethod
|
|
1329
|
-
def list_walkers(
|
|
1554
|
+
def list_walkers(module_name: str) -> list[str]:
|
|
1330
1555
|
"""List all walkers in a specific module."""
|
|
1331
|
-
module =
|
|
1556
|
+
module = JacMachine.loaded_modules.get(module_name)
|
|
1332
1557
|
if module:
|
|
1333
1558
|
walkers = []
|
|
1334
1559
|
for name, obj in inspect.getmembers(module):
|
|
@@ -1338,9 +1563,9 @@ class JacUtils:
|
|
|
1338
1563
|
return []
|
|
1339
1564
|
|
|
1340
1565
|
@staticmethod
|
|
1341
|
-
def list_nodes(
|
|
1566
|
+
def list_nodes(module_name: str) -> list[str]:
|
|
1342
1567
|
"""List all nodes in a specific module."""
|
|
1343
|
-
module =
|
|
1568
|
+
module = JacMachine.loaded_modules.get(module_name)
|
|
1344
1569
|
if module:
|
|
1345
1570
|
nodes = []
|
|
1346
1571
|
for name, obj in inspect.getmembers(module):
|
|
@@ -1350,9 +1575,9 @@ class JacUtils:
|
|
|
1350
1575
|
return []
|
|
1351
1576
|
|
|
1352
1577
|
@staticmethod
|
|
1353
|
-
def list_edges(
|
|
1578
|
+
def list_edges(module_name: str) -> list[str]:
|
|
1354
1579
|
"""List all edges in a specific module."""
|
|
1355
|
-
module =
|
|
1580
|
+
module = JacMachine.loaded_modules.get(module_name)
|
|
1356
1581
|
if module:
|
|
1357
1582
|
nodes = []
|
|
1358
1583
|
for name, obj in inspect.getmembers(module):
|
|
@@ -1363,7 +1588,6 @@ class JacUtils:
|
|
|
1363
1588
|
|
|
1364
1589
|
@staticmethod
|
|
1365
1590
|
def create_archetype_from_source(
|
|
1366
|
-
mach: JacMachine,
|
|
1367
1591
|
source_code: str,
|
|
1368
1592
|
module_name: Optional[str] = None,
|
|
1369
1593
|
base_path: Optional[str] = None,
|
|
@@ -1374,12 +1598,12 @@ class JacUtils:
|
|
|
1374
1598
|
from jaclang.runtimelib.importer import JacImporter, ImportPathSpec
|
|
1375
1599
|
|
|
1376
1600
|
if not base_path:
|
|
1377
|
-
base_path =
|
|
1601
|
+
base_path = JacMachine.base_path_dir or os.getcwd()
|
|
1378
1602
|
|
|
1379
1603
|
if base_path and not os.path.exists(base_path):
|
|
1380
1604
|
os.makedirs(base_path)
|
|
1381
1605
|
if not module_name:
|
|
1382
|
-
module_name = f"_dynamic_module_{len(
|
|
1606
|
+
module_name = f"_dynamic_module_{len(JacMachine.loaded_modules)}"
|
|
1383
1607
|
with tempfile.NamedTemporaryFile(
|
|
1384
1608
|
mode="w",
|
|
1385
1609
|
suffix=".jac",
|
|
@@ -1391,7 +1615,7 @@ class JacUtils:
|
|
|
1391
1615
|
tmp_file.write(source_code)
|
|
1392
1616
|
|
|
1393
1617
|
try:
|
|
1394
|
-
importer = JacImporter(
|
|
1618
|
+
importer = JacImporter()
|
|
1395
1619
|
tmp_file_basename = os.path.basename(tmp_file_path)
|
|
1396
1620
|
tmp_module_name, _ = os.path.splitext(tmp_file_basename)
|
|
1397
1621
|
|
|
@@ -1408,7 +1632,7 @@ class JacUtils:
|
|
|
1408
1632
|
import_result = importer.run_import(spec, reload=False)
|
|
1409
1633
|
module = import_result.ret_mod
|
|
1410
1634
|
|
|
1411
|
-
|
|
1635
|
+
JacMachine.loaded_modules[module_name] = module
|
|
1412
1636
|
return module
|
|
1413
1637
|
except Exception as e:
|
|
1414
1638
|
logger.error(f"Error importing dynamic module '{module_name}': {e}")
|
|
@@ -1419,20 +1643,19 @@ class JacUtils:
|
|
|
1419
1643
|
|
|
1420
1644
|
@staticmethod
|
|
1421
1645
|
def update_walker(
|
|
1422
|
-
mach: JacMachine,
|
|
1423
1646
|
module_name: str,
|
|
1424
1647
|
items: Optional[dict[str, Union[str, Optional[str]]]],
|
|
1425
1648
|
) -> tuple[types.ModuleType, ...]:
|
|
1426
1649
|
"""Reimport the module."""
|
|
1427
1650
|
from .importer import JacImporter, ImportPathSpec
|
|
1428
1651
|
|
|
1429
|
-
if module_name in
|
|
1652
|
+
if module_name in JacMachine.loaded_modules:
|
|
1430
1653
|
try:
|
|
1431
|
-
old_module =
|
|
1432
|
-
importer = JacImporter(
|
|
1654
|
+
old_module = JacMachine.loaded_modules[module_name]
|
|
1655
|
+
importer = JacImporter()
|
|
1433
1656
|
spec = ImportPathSpec(
|
|
1434
1657
|
target=module_name,
|
|
1435
|
-
base_path=
|
|
1658
|
+
base_path=JacMachine.base_path_dir,
|
|
1436
1659
|
absorb=False,
|
|
1437
1660
|
mdl_alias=None,
|
|
1438
1661
|
override_name=None,
|
|
@@ -1461,13 +1684,12 @@ class JacUtils:
|
|
|
1461
1684
|
|
|
1462
1685
|
@staticmethod
|
|
1463
1686
|
def spawn_node(
|
|
1464
|
-
mach: JacMachine,
|
|
1465
1687
|
node_name: str,
|
|
1466
1688
|
attributes: Optional[dict] = None,
|
|
1467
1689
|
module_name: str = "__main__",
|
|
1468
1690
|
) -> NodeArchetype:
|
|
1469
1691
|
"""Spawn a node instance of the given node_name with attributes."""
|
|
1470
|
-
node_class = JacMachineInterface.get_archetype(
|
|
1692
|
+
node_class = JacMachineInterface.get_archetype(module_name, node_name)
|
|
1471
1693
|
if isinstance(node_class, type) and issubclass(node_class, NodeArchetype):
|
|
1472
1694
|
if attributes is None:
|
|
1473
1695
|
attributes = {}
|
|
@@ -1478,13 +1700,12 @@ class JacUtils:
|
|
|
1478
1700
|
|
|
1479
1701
|
@staticmethod
|
|
1480
1702
|
def spawn_walker(
|
|
1481
|
-
mach: JacMachine,
|
|
1482
1703
|
walker_name: str,
|
|
1483
1704
|
attributes: Optional[dict] = None,
|
|
1484
1705
|
module_name: str = "__main__",
|
|
1485
1706
|
) -> WalkerArchetype:
|
|
1486
1707
|
"""Spawn a walker instance of the given walker_name."""
|
|
1487
|
-
walker_class = JacMachineInterface.get_archetype(
|
|
1708
|
+
walker_class = JacMachineInterface.get_archetype(module_name, walker_name)
|
|
1488
1709
|
if isinstance(walker_class, type) and issubclass(walker_class, WalkerArchetype):
|
|
1489
1710
|
if attributes is None:
|
|
1490
1711
|
attributes = {}
|
|
@@ -1494,27 +1715,17 @@ class JacUtils:
|
|
|
1494
1715
|
raise ValueError(f"Walker {walker_name} not found.")
|
|
1495
1716
|
|
|
1496
1717
|
@staticmethod
|
|
1497
|
-
def get_archetype(
|
|
1498
|
-
mach: JacMachine, module_name: str, archetype_name: str
|
|
1499
|
-
) -> Optional[Archetype]:
|
|
1718
|
+
def get_archetype(module_name: str, archetype_name: str) -> Optional[Archetype]:
|
|
1500
1719
|
"""Retrieve an archetype class from a module."""
|
|
1501
|
-
module =
|
|
1720
|
+
module = JacMachine.loaded_modules.get(module_name)
|
|
1502
1721
|
if module:
|
|
1503
1722
|
return getattr(module, archetype_name, None)
|
|
1504
1723
|
return None
|
|
1505
1724
|
|
|
1506
|
-
@staticmethod
|
|
1507
|
-
def await_obj(obj: Any) -> Any: # noqa: ANN401
|
|
1508
|
-
"""Await an object if it is a coroutine or async or future function."""
|
|
1509
|
-
machine = JacMachineInterface.py_get_jac_machine()
|
|
1510
|
-
_event_loop = machine._event_loop
|
|
1511
|
-
return _event_loop.run_until_complete(obj)
|
|
1512
|
-
|
|
1513
1725
|
@staticmethod
|
|
1514
1726
|
def thread_run(func: Callable, *args: object) -> Future: # noqa: ANN401
|
|
1515
1727
|
"""Run a function in a thread."""
|
|
1516
|
-
|
|
1517
|
-
_executor = machine.pool
|
|
1728
|
+
_executor = JacMachine.pool
|
|
1518
1729
|
return _executor.submit(func, *args)
|
|
1519
1730
|
|
|
1520
1731
|
@staticmethod
|
|
@@ -1540,82 +1751,35 @@ class JacMachineInterface(
|
|
|
1540
1751
|
class JacMachine(JacMachineInterface):
|
|
1541
1752
|
"""Jac Machine State."""
|
|
1542
1753
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
interp_mode: bool = False,
|
|
1549
|
-
) -> None:
|
|
1550
|
-
"""Initialize JacMachine."""
|
|
1551
|
-
self.loaded_modules: dict[str, types.ModuleType] = {}
|
|
1552
|
-
if not base_path:
|
|
1553
|
-
base_path = os.getcwd()
|
|
1554
|
-
# Ensure the base_path is a list rather than a string
|
|
1555
|
-
self.base_path = base_path
|
|
1556
|
-
self.base_path_dir = (
|
|
1557
|
-
os.path.dirname(base_path)
|
|
1558
|
-
if not os.path.isdir(base_path)
|
|
1559
|
-
else os.path.abspath(base_path)
|
|
1560
|
-
)
|
|
1561
|
-
self.jac_program: JacProgram = JacProgram()
|
|
1562
|
-
self.interp_mode = interp_mode
|
|
1563
|
-
self.pool = ThreadPoolExecutor()
|
|
1564
|
-
self._event_loop = asyncio.new_event_loop()
|
|
1565
|
-
self.mem: Memory = ShelfStorage(session)
|
|
1566
|
-
self.reports: list[Any] = []
|
|
1567
|
-
sr_arch = Root()
|
|
1568
|
-
sr_anch = sr_arch.__jac__
|
|
1569
|
-
sr_anch.id = UUID(Con.SUPER_ROOT_UUID)
|
|
1570
|
-
sr_anch.persistent = False
|
|
1571
|
-
self.system_root = sr_anch
|
|
1572
|
-
self.custom: Any = MISSING
|
|
1573
|
-
if not isinstance(
|
|
1574
|
-
system_root := self.mem.find_by_id(UUID(Con.SUPER_ROOT_UUID)), NodeAnchor
|
|
1575
|
-
):
|
|
1576
|
-
system_root = cast(NodeAnchor, Root().__jac__) # type: ignore[attr-defined]
|
|
1577
|
-
system_root.id = UUID(Con.SUPER_ROOT_UUID)
|
|
1578
|
-
self.mem.set(system_root.id, system_root)
|
|
1579
|
-
|
|
1580
|
-
self.system_root = system_root
|
|
1581
|
-
|
|
1582
|
-
self.entry_node = self.root_state = self.init_anchor(root, self.system_root)
|
|
1583
|
-
|
|
1584
|
-
def init_anchor(
|
|
1585
|
-
self,
|
|
1586
|
-
anchor_id: str | None,
|
|
1587
|
-
default: NodeAnchor,
|
|
1588
|
-
) -> NodeAnchor:
|
|
1589
|
-
"""Load initial anchors."""
|
|
1590
|
-
if anchor_id:
|
|
1591
|
-
if isinstance(anchor := self.mem.find_by_id(UUID(anchor_id)), NodeAnchor):
|
|
1592
|
-
return anchor
|
|
1593
|
-
raise ValueError(f"Invalid anchor id {anchor_id} !")
|
|
1594
|
-
return default
|
|
1754
|
+
loaded_modules: dict[str, types.ModuleType] = {}
|
|
1755
|
+
base_path_dir: str = os.getcwd()
|
|
1756
|
+
program: JacProgram = JacProgram()
|
|
1757
|
+
pool: ThreadPoolExecutor = ThreadPoolExecutor()
|
|
1758
|
+
exec_ctx: ExecutionContext = ExecutionContext()
|
|
1595
1759
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
def get_root(self) -> Root:
|
|
1605
|
-
"""Get current root."""
|
|
1606
|
-
return cast(Root, self.root_state.archetype)
|
|
1607
|
-
|
|
1608
|
-
def global_system_root(self) -> NodeAnchor:
|
|
1609
|
-
"""Get global system root."""
|
|
1610
|
-
return self.system_root
|
|
1760
|
+
@staticmethod
|
|
1761
|
+
def set_base_path(base_path: str) -> None:
|
|
1762
|
+
"""Set the base path for the machine."""
|
|
1763
|
+
JacMachine.reset_machine()
|
|
1764
|
+
JacMachine.base_path_dir = (
|
|
1765
|
+
base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
|
|
1766
|
+
)
|
|
1611
1767
|
|
|
1768
|
+
@staticmethod
|
|
1769
|
+
def set_context(context: ExecutionContext) -> None:
|
|
1770
|
+
"""Set the context for the machine."""
|
|
1771
|
+
JacMachine.exec_ctx = context
|
|
1612
1772
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1773
|
+
@staticmethod
|
|
1774
|
+
def reset_machine() -> None:
|
|
1775
|
+
"""Reset the machine."""
|
|
1776
|
+
# for i in JacMachine.loaded_modules.values():
|
|
1777
|
+
# sys.modules.pop(i.__name__, None)
|
|
1778
|
+
JacMachine.loaded_modules.clear()
|
|
1779
|
+
JacMachine.base_path_dir = os.getcwd()
|
|
1780
|
+
JacMachine.program = JacProgram()
|
|
1781
|
+
JacMachine.pool = ThreadPoolExecutor()
|
|
1782
|
+
JacMachine.exec_ctx = ExecutionContext()
|
|
1619
1783
|
|
|
1620
1784
|
|
|
1621
1785
|
def generate_plugin_helpers(
|