jaclang 0.8.8__py3-none-any.whl → 0.8.10__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/cli/cli.py +194 -10
- jaclang/cli/cmdreg.py +144 -8
- jaclang/compiler/__init__.py +6 -1
- jaclang/compiler/codeinfo.py +16 -1
- jaclang/compiler/constant.py +33 -8
- jaclang/compiler/jac.lark +154 -62
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +656 -149
- jaclang/compiler/passes/__init__.py +2 -1
- jaclang/compiler/passes/ast_gen/__init__.py +5 -0
- jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
- jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
- jaclang/compiler/passes/ecmascript/__init__.py +25 -0
- jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
- jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
- jaclang/compiler/passes/ecmascript/estree.py +972 -0
- jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
- jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
- jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
- jaclang/compiler/passes/main/__init__.py +0 -3
- jaclang/compiler/passes/main/annex_pass.py +23 -1
- jaclang/compiler/passes/main/def_use_pass.py +1 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +413 -255
- jaclang/compiler/passes/main/pyast_load_pass.py +48 -11
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
- jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
- jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -3
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +13 -14
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
- jaclang/compiler/passes/main/type_checker_pass.py +7 -0
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +219 -20
- jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +135 -29
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
- jaclang/compiler/passes/transform.py +9 -1
- jaclang/compiler/passes/uni_pass.py +5 -7
- jaclang/compiler/program.py +27 -26
- jaclang/compiler/tests/test_client_codegen.py +113 -0
- jaclang/compiler/tests/test_importer.py +12 -10
- jaclang/compiler/tests/test_parser.py +249 -3
- jaclang/compiler/type_system/type_evaluator.jac +1078 -0
- jaclang/compiler/type_system/type_utils.py +1 -1
- jaclang/compiler/type_system/types.py +6 -0
- jaclang/compiler/unitree.py +438 -82
- jaclang/langserve/engine.jac +224 -288
- jaclang/langserve/sem_manager.jac +12 -8
- jaclang/langserve/server.jac +48 -48
- jaclang/langserve/tests/fixtures/greet.py +17 -0
- jaclang/langserve/tests/fixtures/md_path.jac +22 -0
- jaclang/langserve/tests/fixtures/user.jac +15 -0
- jaclang/langserve/tests/test_server.py +66 -371
- jaclang/lib.py +17 -0
- jaclang/runtimelib/archetype.py +25 -25
- jaclang/runtimelib/client_bundle.py +169 -0
- jaclang/runtimelib/client_runtime.jac +586 -0
- jaclang/runtimelib/constructs.py +4 -2
- jaclang/runtimelib/machine.py +308 -139
- jaclang/runtimelib/meta_importer.py +111 -22
- jaclang/runtimelib/mtp.py +15 -0
- jaclang/runtimelib/server.py +1089 -0
- jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
- jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
- jaclang/runtimelib/tests/test_client_bundle.py +55 -0
- jaclang/runtimelib/tests/test_client_render.py +63 -0
- jaclang/runtimelib/tests/test_serve.py +1069 -0
- jaclang/settings.py +0 -3
- jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
- jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
- jaclang/tests/fixtures/funccall_genexpr.py +5 -0
- jaclang/tests/fixtures/iife_functions.jac +142 -0
- jaclang/tests/fixtures/iife_functions_client.jac +143 -0
- jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
- jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
- jaclang/tests/fixtures/needs_import_dup.jac +6 -4
- jaclang/tests/fixtures/py2jac_empty.py +0 -0
- jaclang/tests/fixtures/py_run.py +7 -5
- jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
- jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
- jaclang/tests/test_cli.py +134 -18
- jaclang/tests/test_language.py +120 -32
- jaclang/tests/test_reference.py +20 -3
- jaclang/utils/NonGPT.py +375 -0
- jaclang/utils/helpers.py +64 -20
- jaclang/utils/lang_tools.py +31 -4
- jaclang/utils/tests/test_lang_tools.py +5 -16
- jaclang/utils/treeprinter.py +8 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/RECORD +106 -71
- jaclang/compiler/passes/main/binder_pass.py +0 -594
- jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
- jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
- jaclang/compiler/type_system/type_evaluator.py +0 -844
- jaclang/langserve/tests/session.jac +0 -294
- jaclang/langserve/tests/test_dev_server.py +0 -80
- jaclang/runtimelib/importer.py +0 -351
- jaclang/tests/test_typecheck.py +0 -542
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
jaclang/runtimelib/machine.py
CHANGED
|
@@ -10,6 +10,7 @@ import sys
|
|
|
10
10
|
import tempfile
|
|
11
11
|
import types
|
|
12
12
|
from collections import OrderedDict
|
|
13
|
+
from collections.abc import Mapping, Sequence
|
|
13
14
|
from concurrent.futures import Future, ThreadPoolExecutor
|
|
14
15
|
from dataclasses import MISSING, dataclass, field
|
|
15
16
|
from functools import wraps
|
|
@@ -27,6 +28,7 @@ from typing import (
|
|
|
27
28
|
TypeVar,
|
|
28
29
|
Union,
|
|
29
30
|
cast,
|
|
31
|
+
get_type_hints,
|
|
30
32
|
)
|
|
31
33
|
from uuid import UUID
|
|
32
34
|
|
|
@@ -34,10 +36,10 @@ from uuid import UUID
|
|
|
34
36
|
from jaclang.compiler.constant import Constants as Con, EdgeDir, colors
|
|
35
37
|
from jaclang.compiler.program import JacProgram
|
|
36
38
|
from jaclang.runtimelib.archetype import (
|
|
37
|
-
DataSpatialDestination,
|
|
38
|
-
DataSpatialFunction,
|
|
39
|
-
DataSpatialPath,
|
|
40
39
|
GenericEdge as _GenericEdge,
|
|
40
|
+
ObjectSpatialDestination,
|
|
41
|
+
ObjectSpatialFunction,
|
|
42
|
+
ObjectSpatialPath,
|
|
41
43
|
Root as _Root,
|
|
42
44
|
)
|
|
43
45
|
from jaclang.runtimelib.constructs import (
|
|
@@ -55,6 +57,7 @@ from jaclang.runtimelib.constructs import (
|
|
|
55
57
|
WalkerArchetype,
|
|
56
58
|
)
|
|
57
59
|
from jaclang.runtimelib.memory import Memory, Shelf, ShelfStorage
|
|
60
|
+
from jaclang.runtimelib.mtp import MTIR
|
|
58
61
|
from jaclang.runtimelib.utils import (
|
|
59
62
|
all_issubclass,
|
|
60
63
|
traverse_graph,
|
|
@@ -85,37 +88,31 @@ class ExecutionContext:
|
|
|
85
88
|
self.mem: Memory = ShelfStorage(session)
|
|
86
89
|
self.reports: list[Any] = []
|
|
87
90
|
self.custom: Any = MISSING
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
system_root =
|
|
92
|
-
system_root.id
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
self.entry_node = self.root_state = self.init_anchor(root, self.system_root)
|
|
91
|
+
self.system_root = self.mem.find_by_id(UUID(Con.SUPER_ROOT_UUID))
|
|
92
|
+
if not isinstance(self.system_root, NodeAnchor):
|
|
93
|
+
self.system_root = cast(NodeAnchor, Root().__jac__)
|
|
94
|
+
self.system_root.id = UUID(Con.SUPER_ROOT_UUID)
|
|
95
|
+
self.mem.set(self.system_root.id, self.system_root)
|
|
96
|
+
self.entry_node = self.root_state = (
|
|
97
|
+
self._get_anchor(root) if root else self.system_root
|
|
98
|
+
)
|
|
98
99
|
|
|
99
|
-
def
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
) -> NodeAnchor:
|
|
104
|
-
"""Load initial anchors."""
|
|
105
|
-
if anchor_id:
|
|
106
|
-
if isinstance(anchor := self.mem.find_by_id(UUID(anchor_id)), NodeAnchor):
|
|
107
|
-
return anchor
|
|
100
|
+
def _get_anchor(self, anchor_id: str) -> NodeAnchor:
|
|
101
|
+
"""Get anchor by ID or raise error."""
|
|
102
|
+
anchor = self.mem.find_by_id(UUID(anchor_id))
|
|
103
|
+
if not isinstance(anchor, NodeAnchor):
|
|
108
104
|
raise ValueError(f"Invalid anchor id {anchor_id} !")
|
|
109
|
-
return
|
|
105
|
+
return anchor
|
|
110
106
|
|
|
111
107
|
def set_entry_node(self, entry_node: str | None) -> None:
|
|
112
|
-
"""Override entry."""
|
|
113
|
-
self.entry_node =
|
|
108
|
+
"""Override entry node."""
|
|
109
|
+
self.entry_node = (
|
|
110
|
+
self._get_anchor(entry_node) if entry_node else self.root_state
|
|
111
|
+
)
|
|
114
112
|
|
|
115
113
|
def close(self) -> None:
|
|
116
114
|
"""Close current ExecutionContext."""
|
|
117
115
|
self.mem.close()
|
|
118
|
-
JacMachine.reset_machine()
|
|
119
116
|
|
|
120
117
|
def get_root(self) -> Root:
|
|
121
118
|
"""Get current root."""
|
|
@@ -267,7 +264,7 @@ class JacNode:
|
|
|
267
264
|
|
|
268
265
|
@staticmethod
|
|
269
266
|
def get_edges(
|
|
270
|
-
origin: list[NodeArchetype], destination:
|
|
267
|
+
origin: list[NodeArchetype], destination: ObjectSpatialDestination
|
|
271
268
|
) -> list[EdgeArchetype]:
|
|
272
269
|
"""Get edges connected to this node."""
|
|
273
270
|
edges: OrderedDict[EdgeAnchor, EdgeArchetype] = OrderedDict()
|
|
@@ -300,7 +297,7 @@ class JacNode:
|
|
|
300
297
|
@staticmethod
|
|
301
298
|
def get_edges_with_node(
|
|
302
299
|
origin: list[NodeArchetype],
|
|
303
|
-
destination:
|
|
300
|
+
destination: ObjectSpatialDestination,
|
|
304
301
|
from_visit: bool = False,
|
|
305
302
|
) -> list[EdgeArchetype | NodeArchetype]:
|
|
306
303
|
"""Get edges connected to this node and the node."""
|
|
@@ -337,7 +334,7 @@ class JacNode:
|
|
|
337
334
|
|
|
338
335
|
@staticmethod
|
|
339
336
|
def edges_to_nodes(
|
|
340
|
-
origin: list[NodeArchetype], destination:
|
|
337
|
+
origin: list[NodeArchetype], destination: ObjectSpatialDestination
|
|
341
338
|
) -> list[NodeArchetype]:
|
|
342
339
|
"""Get set of nodes connected to this node."""
|
|
343
340
|
nodes: OrderedDict[NodeAnchor, NodeArchetype] = OrderedDict()
|
|
@@ -424,36 +421,6 @@ class JacWalker:
|
|
|
424
421
|
else:
|
|
425
422
|
raise TypeError("Invalid walker object")
|
|
426
423
|
|
|
427
|
-
@staticmethod
|
|
428
|
-
def ignore(
|
|
429
|
-
walker: WalkerArchetype,
|
|
430
|
-
expr: (
|
|
431
|
-
list[NodeArchetype | EdgeArchetype]
|
|
432
|
-
| list[NodeArchetype]
|
|
433
|
-
| list[EdgeArchetype]
|
|
434
|
-
| NodeArchetype
|
|
435
|
-
| EdgeArchetype
|
|
436
|
-
),
|
|
437
|
-
) -> bool: # noqa: ANN401
|
|
438
|
-
"""Jac's ignore stmt feature."""
|
|
439
|
-
if isinstance(walker, WalkerArchetype):
|
|
440
|
-
wanch = walker.__jac__
|
|
441
|
-
before_len = len(wanch.ignores)
|
|
442
|
-
for anchor in (
|
|
443
|
-
(i.__jac__ for i in expr) if isinstance(expr, list) else [expr.__jac__]
|
|
444
|
-
):
|
|
445
|
-
if anchor not in wanch.ignores:
|
|
446
|
-
if isinstance(anchor, NodeAnchor):
|
|
447
|
-
wanch.ignores.append(anchor)
|
|
448
|
-
elif isinstance(anchor, EdgeAnchor):
|
|
449
|
-
if target := anchor.target:
|
|
450
|
-
wanch.ignores.append(target)
|
|
451
|
-
else:
|
|
452
|
-
raise ValueError("Edge has no target.")
|
|
453
|
-
return len(wanch.ignores) > before_len
|
|
454
|
-
else:
|
|
455
|
-
raise TypeError("Invalid walker object")
|
|
456
|
-
|
|
457
424
|
@staticmethod
|
|
458
425
|
def spawn_call(
|
|
459
426
|
walker: WalkerAnchor,
|
|
@@ -718,7 +685,7 @@ class JacClassReferences:
|
|
|
718
685
|
|
|
719
686
|
TYPE_CHECKING: bool = TYPE_CHECKING
|
|
720
687
|
EdgeDir: TypeAlias = EdgeDir
|
|
721
|
-
DSFunc: TypeAlias =
|
|
688
|
+
DSFunc: TypeAlias = ObjectSpatialFunction
|
|
722
689
|
|
|
723
690
|
Obj: TypeAlias = Archetype
|
|
724
691
|
Node: TypeAlias = NodeArchetype
|
|
@@ -728,7 +695,7 @@ class JacClassReferences:
|
|
|
728
695
|
Root: TypeAlias = _Root
|
|
729
696
|
GenericEdge: TypeAlias = _GenericEdge
|
|
730
697
|
|
|
731
|
-
|
|
698
|
+
OPath: TypeAlias = ObjectSpatialPath
|
|
732
699
|
|
|
733
700
|
|
|
734
701
|
class JacBuiltin:
|
|
@@ -967,45 +934,163 @@ class JacBasics:
|
|
|
967
934
|
target: str,
|
|
968
935
|
base_path: str,
|
|
969
936
|
absorb: bool = False,
|
|
970
|
-
mdl_alias: Optional[str] = None,
|
|
971
937
|
override_name: Optional[str] = None,
|
|
972
938
|
items: Optional[dict[str, Union[str, Optional[str]]]] = None,
|
|
973
939
|
reload_module: Optional[bool] = False,
|
|
974
940
|
lng: Optional[str] = None,
|
|
975
941
|
) -> tuple[types.ModuleType, ...]:
|
|
976
|
-
"""
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
942
|
+
"""Import a Jac or Python module using Python's standard import machinery.
|
|
943
|
+
|
|
944
|
+
This function bridges Jac's import semantics with Python's import system,
|
|
945
|
+
leveraging importlib.import_module() which automatically invokes our
|
|
946
|
+
JacMetaImporter (registered in sys.meta_path).
|
|
947
|
+
|
|
948
|
+
Args:
|
|
949
|
+
target: Module name to import (e.g., "foo.bar" or ".relative")
|
|
950
|
+
base_path: Base directory for resolving the module
|
|
951
|
+
absorb: If True with items, return module instead of items
|
|
952
|
+
override_name: Special handling for "__main__" execution context
|
|
953
|
+
items: Specific items to import from module (like "from X import Y")
|
|
954
|
+
reload_module: Force reload even if already in sys.modules
|
|
955
|
+
lng: Language hint ("jac", "py", etc.) - auto-detected if None
|
|
956
|
+
|
|
957
|
+
Returns:
|
|
958
|
+
Tuple of imported module(s) or item(s)
|
|
959
|
+
|
|
960
|
+
Examples:
|
|
961
|
+
# Import entire module
|
|
962
|
+
(mod,) = jac_import("mymod", "/path/to/base")
|
|
963
|
+
|
|
964
|
+
# Import specific items
|
|
965
|
+
(func, cls) = jac_import("mymod", "/path", items={"myfunc": None, "MyClass": None})
|
|
966
|
+
|
|
967
|
+
# Run as __main__
|
|
968
|
+
jac_import("mymod", "/path", override_name="__main__")
|
|
969
|
+
"""
|
|
970
|
+
import importlib
|
|
971
|
+
import importlib.util
|
|
982
972
|
|
|
983
973
|
if lng is None:
|
|
984
974
|
lng = infer_language(target, base_path)
|
|
985
975
|
|
|
986
|
-
spec = ImportPathSpec(
|
|
987
|
-
target,
|
|
988
|
-
base_path,
|
|
989
|
-
absorb,
|
|
990
|
-
mdl_alias,
|
|
991
|
-
override_name,
|
|
992
|
-
lng,
|
|
993
|
-
items,
|
|
994
|
-
)
|
|
995
|
-
|
|
996
976
|
if not JacMachine.program:
|
|
997
977
|
JacMachineInterface.attach_program(JacProgram())
|
|
998
978
|
|
|
999
|
-
|
|
1000
|
-
|
|
979
|
+
# Compute the module name
|
|
980
|
+
# Convert relative imports (e.g., ".foo") to absolute
|
|
981
|
+
if target.startswith("."):
|
|
982
|
+
# Relative import - need to resolve against base_path
|
|
983
|
+
caller_dir = (
|
|
984
|
+
base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
|
|
985
|
+
)
|
|
986
|
+
chomp_target = target
|
|
987
|
+
while chomp_target.startswith("."):
|
|
988
|
+
if len(chomp_target) > 1 and chomp_target[1] == ".":
|
|
989
|
+
caller_dir = os.path.dirname(caller_dir)
|
|
990
|
+
chomp_target = chomp_target[1:]
|
|
991
|
+
else:
|
|
992
|
+
chomp_target = chomp_target[1:]
|
|
993
|
+
break
|
|
994
|
+
module_name = chomp_target
|
|
1001
995
|
else:
|
|
1002
|
-
|
|
996
|
+
module_name = target
|
|
1003
997
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
else
|
|
998
|
+
# Add base_path to sys.path for import resolution
|
|
999
|
+
# The meta importer uses this for finding modules
|
|
1000
|
+
caller_dir = (
|
|
1001
|
+
base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
|
|
1008
1002
|
)
|
|
1003
|
+
original_path = None
|
|
1004
|
+
|
|
1005
|
+
# Only modify sys.path if the directory isn't already there
|
|
1006
|
+
if caller_dir and caller_dir not in sys.path:
|
|
1007
|
+
original_path = sys.path.copy()
|
|
1008
|
+
sys.path.insert(0, caller_dir)
|
|
1009
|
+
|
|
1010
|
+
try:
|
|
1011
|
+
# Handle special case: override_name="__main__" means run as script
|
|
1012
|
+
if override_name == "__main__":
|
|
1013
|
+
# For __main__ execution, we use spec_from_file_location
|
|
1014
|
+
from jaclang.runtimelib.meta_importer import JacMetaImporter
|
|
1015
|
+
|
|
1016
|
+
finder = JacMetaImporter()
|
|
1017
|
+
# Pass None as path for top-level imports (e.g., "micro.simple_walk")
|
|
1018
|
+
# This ensures the meta importer searches sys.path correctly
|
|
1019
|
+
spec = finder.find_spec(module_name, None)
|
|
1020
|
+
if (
|
|
1021
|
+
spec
|
|
1022
|
+
and spec.origin
|
|
1023
|
+
and spec.origin.endswith(".jac")
|
|
1024
|
+
and lng == "py"
|
|
1025
|
+
):
|
|
1026
|
+
spec = None
|
|
1027
|
+
|
|
1028
|
+
if (not spec or not spec.origin) and lng == "py":
|
|
1029
|
+
file_path = os.path.join(caller_dir, f"{module_name}.py")
|
|
1030
|
+
if os.path.isfile(file_path):
|
|
1031
|
+
spec_name = (
|
|
1032
|
+
"__main__" if override_name == "__main__" else module_name
|
|
1033
|
+
)
|
|
1034
|
+
spec = importlib.util.spec_from_file_location(
|
|
1035
|
+
spec_name, file_path
|
|
1036
|
+
)
|
|
1037
|
+
|
|
1038
|
+
if not spec or not spec.origin:
|
|
1039
|
+
raise ImportError(f"Cannot find module {module_name}")
|
|
1040
|
+
|
|
1041
|
+
# Create or get __main__ module
|
|
1042
|
+
if "__main__" in sys.modules and not reload_module:
|
|
1043
|
+
module = sys.modules["__main__"]
|
|
1044
|
+
# Clear the module's dict except for special attributes
|
|
1045
|
+
to_keep = {
|
|
1046
|
+
k: v for k, v in module.__dict__.items() if k.startswith("__")
|
|
1047
|
+
}
|
|
1048
|
+
# module.__dict__.clear()
|
|
1049
|
+
module.__dict__.update(to_keep)
|
|
1050
|
+
else:
|
|
1051
|
+
module = types.ModuleType("__main__")
|
|
1052
|
+
sys.modules["__main__"] = module
|
|
1053
|
+
|
|
1054
|
+
# Set module attributes
|
|
1055
|
+
module.__file__ = spec.origin
|
|
1056
|
+
module.__name__ = "__main__"
|
|
1057
|
+
module.__spec__ = spec
|
|
1058
|
+
if spec.submodule_search_locations:
|
|
1059
|
+
module.__path__ = spec.submodule_search_locations
|
|
1060
|
+
|
|
1061
|
+
# Register in JacMachine
|
|
1062
|
+
JacMachineInterface.load_module("__main__", module)
|
|
1063
|
+
|
|
1064
|
+
# Execute the module
|
|
1065
|
+
if spec.loader:
|
|
1066
|
+
spec.loader.exec_module(module)
|
|
1067
|
+
elif reload_module and module_name in sys.modules:
|
|
1068
|
+
# Handle reload case
|
|
1069
|
+
module = importlib.reload(sys.modules[module_name])
|
|
1070
|
+
else:
|
|
1071
|
+
# Use Python's standard import machinery
|
|
1072
|
+
# This will invoke JacMetaImporter.find_spec() and exec_module()
|
|
1073
|
+
module = importlib.import_module(module_name)
|
|
1074
|
+
|
|
1075
|
+
# Handle selective item imports
|
|
1076
|
+
if items:
|
|
1077
|
+
imported_items = []
|
|
1078
|
+
for item_name, _ in items.items():
|
|
1079
|
+
if hasattr(module, item_name):
|
|
1080
|
+
item = getattr(module, item_name)
|
|
1081
|
+
imported_items.append(item)
|
|
1082
|
+
else:
|
|
1083
|
+
raise ImportError(
|
|
1084
|
+
f"Cannot import name '{item_name}' from '{module_name}'"
|
|
1085
|
+
)
|
|
1086
|
+
return tuple(imported_items) if not absorb else (module,)
|
|
1087
|
+
|
|
1088
|
+
return (module,)
|
|
1089
|
+
|
|
1090
|
+
finally:
|
|
1091
|
+
# Restore original sys.path if we modified it
|
|
1092
|
+
if original_path is not None:
|
|
1093
|
+
sys.path[:] = original_path
|
|
1009
1094
|
|
|
1010
1095
|
@staticmethod
|
|
1011
1096
|
def jac_test(test_fun: Callable) -> Callable:
|
|
@@ -1021,6 +1106,30 @@ class JacBasics:
|
|
|
1021
1106
|
|
|
1022
1107
|
return test_deco
|
|
1023
1108
|
|
|
1109
|
+
@staticmethod
|
|
1110
|
+
def jsx(
|
|
1111
|
+
tag: object,
|
|
1112
|
+
attributes: Mapping[str, object] | None = None,
|
|
1113
|
+
children: Sequence[object] | None = None,
|
|
1114
|
+
) -> dict[str, object]:
|
|
1115
|
+
"""JSX interface for creating elements.
|
|
1116
|
+
|
|
1117
|
+
Args:
|
|
1118
|
+
tag: Element tag (string for HTML elements, callable for components)
|
|
1119
|
+
attributes: Element attributes/props
|
|
1120
|
+
children: Child elements
|
|
1121
|
+
|
|
1122
|
+
Returns:
|
|
1123
|
+
JSX element representation (implementation-defined)
|
|
1124
|
+
"""
|
|
1125
|
+
props: dict[str, object] = dict(attributes) if attributes else {}
|
|
1126
|
+
child_list = list(children) if children else []
|
|
1127
|
+
return {
|
|
1128
|
+
"tag": tag,
|
|
1129
|
+
"props": props,
|
|
1130
|
+
"children": child_list,
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1024
1133
|
@staticmethod
|
|
1025
1134
|
def run_test(
|
|
1026
1135
|
filepath: str,
|
|
@@ -1096,23 +1205,24 @@ class JacBasics:
|
|
|
1096
1205
|
return field(init=init)
|
|
1097
1206
|
|
|
1098
1207
|
@staticmethod
|
|
1099
|
-
def
|
|
1208
|
+
def log_report(expr: Any, custom: bool = False) -> None: # noqa: ANN401
|
|
1100
1209
|
"""Jac's report stmt feature."""
|
|
1101
1210
|
ctx = JacMachineInterface.get_context()
|
|
1102
1211
|
if custom:
|
|
1103
1212
|
ctx.custom = expr
|
|
1104
1213
|
else:
|
|
1214
|
+
print(expr)
|
|
1105
1215
|
ctx.reports.append(expr)
|
|
1106
1216
|
|
|
1107
1217
|
@staticmethod
|
|
1108
1218
|
def refs(
|
|
1109
|
-
path:
|
|
1219
|
+
path: ObjectSpatialPath | NodeArchetype | list[NodeArchetype],
|
|
1110
1220
|
) -> (
|
|
1111
1221
|
list[NodeArchetype] | list[EdgeArchetype] | list[NodeArchetype | EdgeArchetype]
|
|
1112
1222
|
):
|
|
1113
1223
|
"""Jac's apply_dir stmt feature."""
|
|
1114
|
-
if not isinstance(path,
|
|
1115
|
-
path =
|
|
1224
|
+
if not isinstance(path, ObjectSpatialPath):
|
|
1225
|
+
path = ObjectSpatialPath(path, [ObjectSpatialDestination(EdgeDir.OUT)])
|
|
1116
1226
|
|
|
1117
1227
|
origin = path.origin
|
|
1118
1228
|
|
|
@@ -1134,13 +1244,13 @@ class JacBasics:
|
|
|
1134
1244
|
|
|
1135
1245
|
@staticmethod
|
|
1136
1246
|
async def arefs(
|
|
1137
|
-
path:
|
|
1247
|
+
path: ObjectSpatialPath | NodeArchetype | list[NodeArchetype],
|
|
1138
1248
|
) -> None:
|
|
1139
1249
|
"""Jac's apply_dir stmt feature."""
|
|
1140
1250
|
pass
|
|
1141
1251
|
|
|
1142
1252
|
@staticmethod
|
|
1143
|
-
def
|
|
1253
|
+
def filter_on(
|
|
1144
1254
|
items: list[Archetype],
|
|
1145
1255
|
func: Callable[[Archetype], bool],
|
|
1146
1256
|
) -> list[Archetype]:
|
|
@@ -1226,7 +1336,7 @@ class JacBasics:
|
|
|
1226
1336
|
return disconnect_occurred
|
|
1227
1337
|
|
|
1228
1338
|
@staticmethod
|
|
1229
|
-
def
|
|
1339
|
+
def assign_all(target: list[T], attr_val: tuple[tuple[str], tuple[Any]]) -> list[T]:
|
|
1230
1340
|
"""Jac's assign comprehension feature."""
|
|
1231
1341
|
for obj in target:
|
|
1232
1342
|
attrs, values = attr_val
|
|
@@ -1328,17 +1438,28 @@ class JacBasics:
|
|
|
1328
1438
|
JacMachineInterface.get_context().mem.remove(anchor.id)
|
|
1329
1439
|
|
|
1330
1440
|
@staticmethod
|
|
1331
|
-
def
|
|
1441
|
+
def on_entry(func: Callable) -> Callable:
|
|
1332
1442
|
"""Mark a method as jac entry with this decorator."""
|
|
1333
1443
|
setattr(func, "__jac_entry", None) # noqa:B010
|
|
1334
1444
|
return func
|
|
1335
1445
|
|
|
1336
1446
|
@staticmethod
|
|
1337
|
-
def
|
|
1447
|
+
def on_exit(func: Callable) -> Callable:
|
|
1338
1448
|
"""Mark a method as jac exit with this decorator."""
|
|
1339
1449
|
setattr(func, "__jac_exit", None) # noqa:B010
|
|
1340
1450
|
return func
|
|
1341
1451
|
|
|
1452
|
+
|
|
1453
|
+
class JacByLLM:
|
|
1454
|
+
"""Jac byLLM integration."""
|
|
1455
|
+
|
|
1456
|
+
@staticmethod
|
|
1457
|
+
def get_mtir(
|
|
1458
|
+
caller: Callable, args: dict[int | str, object], call_params: dict[str, object]
|
|
1459
|
+
) -> MTIR:
|
|
1460
|
+
"""Get byLLM library."""
|
|
1461
|
+
return MTIR(caller=caller, args=args, call_params=call_params)
|
|
1462
|
+
|
|
1342
1463
|
@staticmethod
|
|
1343
1464
|
def sem(semstr: str, inner_semstr: dict[str, str]) -> Callable:
|
|
1344
1465
|
"""Attach the semstring to the given object."""
|
|
@@ -1351,11 +1472,47 @@ class JacBasics:
|
|
|
1351
1472
|
return decorator
|
|
1352
1473
|
|
|
1353
1474
|
@staticmethod
|
|
1354
|
-
def call_llm(model: object, mtir:
|
|
1475
|
+
def call_llm(model: object, mtir: MTIR) -> Any: # noqa: ANN401
|
|
1355
1476
|
"""Call the LLM model."""
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1477
|
+
from jaclang.utils.NonGPT import random_value_for_type
|
|
1478
|
+
|
|
1479
|
+
try:
|
|
1480
|
+
type_hints = get_type_hints(
|
|
1481
|
+
mtir.caller,
|
|
1482
|
+
globalns=getattr(mtir.caller, "__globals__", {}),
|
|
1483
|
+
localns=None,
|
|
1484
|
+
include_extras=True,
|
|
1485
|
+
)
|
|
1486
|
+
except Exception:
|
|
1487
|
+
type_hints = getattr(mtir.caller, "__annotations__", {})
|
|
1488
|
+
return_type = type_hints.get("return", Any)
|
|
1489
|
+
|
|
1490
|
+
# Generate and return a random value matching the return type
|
|
1491
|
+
return random_value_for_type(return_type)
|
|
1492
|
+
|
|
1493
|
+
@staticmethod
|
|
1494
|
+
def by(model: object) -> Callable:
|
|
1495
|
+
"""Python library mode decorator for Jac's by llm() syntax."""
|
|
1496
|
+
|
|
1497
|
+
def _decorator(caller: Callable) -> Callable:
|
|
1498
|
+
def _wrapped_caller(*args: object, **kwargs: object) -> object:
|
|
1499
|
+
invoke_args: dict[int | str, object] = {}
|
|
1500
|
+
for i, arg in enumerate(args):
|
|
1501
|
+
invoke_args[i] = arg
|
|
1502
|
+
for key, value in kwargs.items():
|
|
1503
|
+
invoke_args[key] = value
|
|
1504
|
+
mtir = JacMachine.get_mtir(
|
|
1505
|
+
caller=caller,
|
|
1506
|
+
args=invoke_args,
|
|
1507
|
+
call_params=(
|
|
1508
|
+
model.call_params if hasattr(model, "call_params") else {}
|
|
1509
|
+
),
|
|
1510
|
+
)
|
|
1511
|
+
return JacMachine.call_llm(model, mtir)
|
|
1512
|
+
|
|
1513
|
+
return _wrapped_caller
|
|
1514
|
+
|
|
1515
|
+
return _decorator
|
|
1359
1516
|
|
|
1360
1517
|
|
|
1361
1518
|
class JacUtils:
|
|
@@ -1387,7 +1544,11 @@ class JacUtils:
|
|
|
1387
1544
|
if module:
|
|
1388
1545
|
walkers = []
|
|
1389
1546
|
for name, obj in inspect.getmembers(module):
|
|
1390
|
-
if
|
|
1547
|
+
if (
|
|
1548
|
+
isinstance(obj, type)
|
|
1549
|
+
and issubclass(obj, WalkerArchetype)
|
|
1550
|
+
and obj.__module__ == module_name
|
|
1551
|
+
):
|
|
1391
1552
|
walkers.append(name)
|
|
1392
1553
|
return walkers
|
|
1393
1554
|
return []
|
|
@@ -1399,7 +1560,11 @@ class JacUtils:
|
|
|
1399
1560
|
if module:
|
|
1400
1561
|
nodes = []
|
|
1401
1562
|
for name, obj in inspect.getmembers(module):
|
|
1402
|
-
if
|
|
1563
|
+
if (
|
|
1564
|
+
isinstance(obj, type)
|
|
1565
|
+
and issubclass(obj, NodeArchetype)
|
|
1566
|
+
and obj.__module__ == module_name
|
|
1567
|
+
):
|
|
1403
1568
|
nodes.append(name)
|
|
1404
1569
|
return nodes
|
|
1405
1570
|
return []
|
|
@@ -1409,11 +1574,15 @@ class JacUtils:
|
|
|
1409
1574
|
"""List all edges in a specific module."""
|
|
1410
1575
|
module = JacMachine.loaded_modules.get(module_name)
|
|
1411
1576
|
if module:
|
|
1412
|
-
|
|
1577
|
+
edges = []
|
|
1413
1578
|
for name, obj in inspect.getmembers(module):
|
|
1414
|
-
if
|
|
1415
|
-
|
|
1416
|
-
|
|
1579
|
+
if (
|
|
1580
|
+
isinstance(obj, type)
|
|
1581
|
+
and issubclass(obj, EdgeArchetype)
|
|
1582
|
+
and obj.__module__ == module_name
|
|
1583
|
+
):
|
|
1584
|
+
edges.append(name)
|
|
1585
|
+
return edges
|
|
1417
1586
|
return []
|
|
1418
1587
|
|
|
1419
1588
|
@staticmethod
|
|
@@ -1424,9 +1593,11 @@ class JacUtils:
|
|
|
1424
1593
|
cachable: bool = False,
|
|
1425
1594
|
keep_temporary_files: bool = False,
|
|
1426
1595
|
) -> Optional[types.ModuleType]:
|
|
1427
|
-
"""Dynamically creates archetypes (nodes, walkers, etc.) from Jac source code.
|
|
1428
|
-
from jaclang.runtimelib.importer import JacImporter, ImportPathSpec
|
|
1596
|
+
"""Dynamically creates archetypes (nodes, walkers, etc.) from Jac source code.
|
|
1429
1597
|
|
|
1598
|
+
This leverages Python's standard import machinery via jac_import(),
|
|
1599
|
+
which will automatically invoke JacMetaImporter.
|
|
1600
|
+
"""
|
|
1430
1601
|
if not base_path:
|
|
1431
1602
|
base_path = JacMachine.base_path_dir or os.getcwd()
|
|
1432
1603
|
|
|
@@ -1434,6 +1605,7 @@ class JacUtils:
|
|
|
1434
1605
|
os.makedirs(base_path)
|
|
1435
1606
|
if not module_name:
|
|
1436
1607
|
module_name = f"_dynamic_module_{len(JacMachine.loaded_modules)}"
|
|
1608
|
+
|
|
1437
1609
|
with tempfile.NamedTemporaryFile(
|
|
1438
1610
|
mode="w",
|
|
1439
1611
|
suffix=".jac",
|
|
@@ -1445,24 +1617,20 @@ class JacUtils:
|
|
|
1445
1617
|
tmp_file.write(source_code)
|
|
1446
1618
|
|
|
1447
1619
|
try:
|
|
1448
|
-
importer = JacImporter()
|
|
1449
1620
|
tmp_file_basename = os.path.basename(tmp_file_path)
|
|
1450
1621
|
tmp_module_name, _ = os.path.splitext(tmp_file_basename)
|
|
1451
1622
|
|
|
1452
|
-
|
|
1623
|
+
# Use simplified jac_import which delegates to importlib
|
|
1624
|
+
result = JacMachineInterface.jac_import(
|
|
1453
1625
|
target=tmp_module_name,
|
|
1454
1626
|
base_path=base_path,
|
|
1455
|
-
absorb=False,
|
|
1456
|
-
mdl_alias=None,
|
|
1457
1627
|
override_name=module_name,
|
|
1458
1628
|
lng="jac",
|
|
1459
|
-
items=None,
|
|
1460
1629
|
)
|
|
1630
|
+
module = result[0] if result else None
|
|
1461
1631
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
JacMachine.loaded_modules[module_name] = module
|
|
1632
|
+
if module:
|
|
1633
|
+
JacMachine.loaded_modules[module_name] = module
|
|
1466
1634
|
return module
|
|
1467
1635
|
except Exception as e:
|
|
1468
1636
|
logger.error(f"Error importing dynamic module '{module_name}': {e}")
|
|
@@ -1476,36 +1644,31 @@ class JacUtils:
|
|
|
1476
1644
|
module_name: str,
|
|
1477
1645
|
items: Optional[dict[str, Union[str, Optional[str]]]],
|
|
1478
1646
|
) -> tuple[types.ModuleType, ...]:
|
|
1479
|
-
"""Reimport the module."""
|
|
1480
|
-
from .importer import JacImporter, ImportPathSpec
|
|
1481
|
-
|
|
1647
|
+
"""Reimport the module using Python's reload mechanism."""
|
|
1482
1648
|
if module_name in JacMachine.loaded_modules:
|
|
1483
1649
|
try:
|
|
1484
1650
|
old_module = JacMachine.loaded_modules[module_name]
|
|
1485
|
-
|
|
1486
|
-
|
|
1651
|
+
|
|
1652
|
+
# Use jac_import with reload flag
|
|
1653
|
+
result = JacMachineInterface.jac_import(
|
|
1487
1654
|
target=module_name,
|
|
1488
1655
|
base_path=JacMachine.base_path_dir,
|
|
1489
|
-
absorb=False,
|
|
1490
|
-
mdl_alias=None,
|
|
1491
|
-
override_name=None,
|
|
1492
|
-
lng="jac",
|
|
1493
1656
|
items=items,
|
|
1657
|
+
reload_module=True,
|
|
1658
|
+
lng="jac",
|
|
1494
1659
|
)
|
|
1495
|
-
|
|
1496
|
-
|
|
1660
|
+
|
|
1661
|
+
# Update the old module's attributes if specific items were requested
|
|
1497
1662
|
if items:
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
)
|
|
1508
|
-
return (old_module,) if not items else tuple(ret_items)
|
|
1663
|
+
ret_items = []
|
|
1664
|
+
for idx, item_name in enumerate(items.keys()):
|
|
1665
|
+
if hasattr(old_module, item_name) and idx < len(result):
|
|
1666
|
+
new_attr = result[idx]
|
|
1667
|
+
ret_items.append(new_attr)
|
|
1668
|
+
setattr(old_module, item_name, new_attr)
|
|
1669
|
+
return tuple(ret_items)
|
|
1670
|
+
|
|
1671
|
+
return (old_module,)
|
|
1509
1672
|
except Exception as e:
|
|
1510
1673
|
logger.error(f"Failed to update module {module_name}: {e}")
|
|
1511
1674
|
else:
|
|
@@ -1573,6 +1736,7 @@ class JacMachineInterface(
|
|
|
1573
1736
|
JacBuiltin,
|
|
1574
1737
|
JacCmd,
|
|
1575
1738
|
JacBasics,
|
|
1739
|
+
JacByLLM,
|
|
1576
1740
|
JacUtils,
|
|
1577
1741
|
):
|
|
1578
1742
|
"""Jac Feature."""
|
|
@@ -1710,10 +1874,15 @@ class JacMachine(JacMachineInterface):
|
|
|
1710
1874
|
@staticmethod
|
|
1711
1875
|
def reset_machine() -> None:
|
|
1712
1876
|
"""Reset the machine."""
|
|
1713
|
-
#
|
|
1714
|
-
#
|
|
1877
|
+
# Remove Jac modules from sys.modules, but skip special module names
|
|
1878
|
+
# that Python relies on (like __main__, __mp_main__, etc.)
|
|
1879
|
+
special_modules = {"__main__", "__mp_main__", "builtins"}
|
|
1880
|
+
for i in JacMachine.loaded_modules.values():
|
|
1881
|
+
if i.__name__ not in special_modules:
|
|
1882
|
+
sys.modules.pop(i.__name__, None)
|
|
1715
1883
|
JacMachine.loaded_modules.clear()
|
|
1716
1884
|
JacMachine.base_path_dir = os.getcwd()
|
|
1717
1885
|
JacMachine.program = JacProgram()
|
|
1718
1886
|
JacMachine.pool = ThreadPoolExecutor()
|
|
1887
|
+
JacMachine.exec_ctx.mem.close()
|
|
1719
1888
|
JacMachine.exec_ctx = ExecutionContext()
|