jaclang 0.7.29__py3-none-any.whl → 0.7.31__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 +419 -3
- jaclang/compiler/__init__.py +1 -1
- jaclang/compiler/absyntree.py +15 -5
- jaclang/compiler/compile.py +1 -1
- jaclang/compiler/constant.py +4 -5
- jaclang/compiler/jac.lark +227 -180
- jaclang/compiler/parser.py +1335 -1826
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +2 -2
- jaclang/compiler/passes/main/import_pass.py +3 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +570 -747
- jaclang/compiler/passes/main/tests/test_import_pass.py +4 -1
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +6 -3
- jaclang/compiler/passes/tool/jac_formatter_pass.py +0 -1
- jaclang/compiler/tests/test_importer.py +45 -1
- jaclang/compiler/tests/test_parser.py +13 -5
- jaclang/plugin/builtin.py +11 -0
- jaclang/plugin/default.py +55 -20
- jaclang/plugin/feature.py +14 -5
- jaclang/plugin/spec.py +16 -6
- jaclang/plugin/tests/fixtures/graph_purger.jac +2 -0
- jaclang/plugin/tests/fixtures/other_root_access.jac +1 -0
- jaclang/plugin/tests/fixtures/savable_object.jac +2 -0
- jaclang/plugin/tests/test_jaseci.py +1 -1
- jaclang/runtimelib/architype.py +11 -21
- jaclang/runtimelib/context.py +25 -9
- jaclang/runtimelib/importer.py +26 -3
- jaclang/runtimelib/machine.py +2 -2
- jaclang/settings.py +2 -0
- jaclang/tests/fixtures/create_dynamic_architype.jac +1 -1
- jaclang/tests/fixtures/nested_impls.jac +55 -0
- jaclang/tests/test_cli.py +1 -1
- jaclang/tests/test_language.py +27 -13
- jaclang/tests/test_reference.py +2 -2
- jaclang/utils/helpers.py +4 -3
- jaclang/utils/test.py +2 -2
- jaclang/utils/tests/test_lang_tools.py +4 -2
- {jaclang-0.7.29.dist-info → jaclang-0.7.31.dist-info}/METADATA +2 -2
- {jaclang-0.7.29.dist-info → jaclang-0.7.31.dist-info}/RECORD +40 -39
- {jaclang-0.7.29.dist-info → jaclang-0.7.31.dist-info}/WHEEL +1 -1
- {jaclang-0.7.29.dist-info → jaclang-0.7.31.dist-info}/entry_points.txt +0 -0
|
@@ -83,7 +83,10 @@ class ImportPassPassTests(TestCase):
|
|
|
83
83
|
for i in p:
|
|
84
84
|
self.assertIn(i, build.ir.py_info.py_raise_map)
|
|
85
85
|
self.assertRegex(
|
|
86
|
-
re.sub(r".*fixtures/", "", build.ir.py_info.py_raise_map[i])
|
|
86
|
+
re.sub(r".*fixtures/", "", build.ir.py_info.py_raise_map[i]).replace(
|
|
87
|
+
"\\", "/"
|
|
88
|
+
),
|
|
89
|
+
p[i],
|
|
87
90
|
)
|
|
88
91
|
|
|
89
92
|
def test_py_raised_mods(self) -> None:
|
|
@@ -70,19 +70,22 @@ class MypyTypeCheckPassTests(TestCase):
|
|
|
70
70
|
)
|
|
71
71
|
self.assertRegex(
|
|
72
72
|
out,
|
|
73
|
-
r"129:24 - 129:28.*SpecialVarRef -
|
|
73
|
+
r"129:24 - 129:28.*SpecialVarRef - Jac.get_root\(\) \- Type\: jaclang.Root",
|
|
74
74
|
)
|
|
75
|
+
|
|
75
76
|
self.assertRegex(out, r"129:11 - 129:29.*FuncCall \- Type\: builtins\.str")
|
|
76
77
|
self.assertRegex(
|
|
77
78
|
out,
|
|
78
79
|
r"129:15 - 129:23.*Name \- node_dot \- Type\: builtins.str, SymbolTable\: str",
|
|
79
80
|
)
|
|
81
|
+
|
|
80
82
|
self.assertRegex(
|
|
81
83
|
out,
|
|
82
|
-
r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.
|
|
84
|
+
r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.Walker",
|
|
83
85
|
)
|
|
84
86
|
self.assertRegex(
|
|
85
87
|
out,
|
|
86
|
-
r"48:11 - 48:28.*EdgeRefTrailer \- Type\:
|
|
88
|
+
r"48:11 - 48:28.*EdgeRefTrailer \- Type\: jaclang.JacList\[data_spatial_types.A\]",
|
|
87
89
|
)
|
|
90
|
+
|
|
88
91
|
self.assertRegex(out, r"24:5 - 24:25.*BinaryExpr \- Type\: builtins.bool", out)
|
|
@@ -33,7 +33,7 @@ class TestLoader(TestCase):
|
|
|
33
33
|
)
|
|
34
34
|
self.assertIn(
|
|
35
35
|
"/tests/fixtures/hello_world.jac",
|
|
36
|
-
str(JacMachine.get().loaded_modules),
|
|
36
|
+
str(JacMachine.get().loaded_modules).replace("\\\\", "/"),
|
|
37
37
|
)
|
|
38
38
|
JacMachine.detach()
|
|
39
39
|
|
|
@@ -62,3 +62,47 @@ class TestLoader(TestCase):
|
|
|
62
62
|
"{SomeObj(a=10): 'check'} [MyObj(apple=5, banana=7), MyObj(apple=5, banana=7)]",
|
|
63
63
|
stdout_value,
|
|
64
64
|
)
|
|
65
|
+
|
|
66
|
+
def test_import_with_jacpath(self) -> None:
|
|
67
|
+
"""Test module import using JACPATH."""
|
|
68
|
+
# Set up a temporary JACPATH environment variable
|
|
69
|
+
import os
|
|
70
|
+
import tempfile
|
|
71
|
+
|
|
72
|
+
jacpath_dir = tempfile.TemporaryDirectory()
|
|
73
|
+
os.environ["JACPATH"] = jacpath_dir.name
|
|
74
|
+
|
|
75
|
+
# Create a mock Jac file in the JACPATH directory
|
|
76
|
+
module_name = "test_module"
|
|
77
|
+
jac_file_path = os.path.join(jacpath_dir.name, f"{module_name}.jac")
|
|
78
|
+
with open(jac_file_path, "w") as f:
|
|
79
|
+
f.write(
|
|
80
|
+
"""
|
|
81
|
+
with entry {
|
|
82
|
+
"Hello from JACPATH!" :> print;
|
|
83
|
+
}
|
|
84
|
+
"""
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Capture the output
|
|
88
|
+
captured_output = io.StringIO()
|
|
89
|
+
sys.stdout = captured_output
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
93
|
+
JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
|
|
94
|
+
)
|
|
95
|
+
jac_import(module_name, base_path=__file__)
|
|
96
|
+
cli.run(jac_file_path)
|
|
97
|
+
|
|
98
|
+
# Reset stdout and get the output
|
|
99
|
+
sys.stdout = sys.__stdout__
|
|
100
|
+
stdout_value = captured_output.getvalue()
|
|
101
|
+
|
|
102
|
+
self.assertIn("Hello from JACPATH!", stdout_value)
|
|
103
|
+
|
|
104
|
+
finally:
|
|
105
|
+
captured_output.close()
|
|
106
|
+
JacMachine.detach()
|
|
107
|
+
os.environ.pop("JACPATH", None)
|
|
108
|
+
jacpath_dir.cleanup()
|
|
@@ -89,12 +89,20 @@ class TestLarkParser(TestCaseMicroSuite):
|
|
|
89
89
|
JacParser.TreeToAST.__base__, value.__name__, False
|
|
90
90
|
):
|
|
91
91
|
parse_funcs.append(name)
|
|
92
|
-
for
|
|
93
|
-
self.assertIn(
|
|
94
|
-
for
|
|
95
|
-
if
|
|
92
|
+
for rule in rules:
|
|
93
|
+
self.assertIn(rule, parse_funcs)
|
|
94
|
+
for fn in parse_funcs:
|
|
95
|
+
if fn.startswith("_") or fn in [
|
|
96
|
+
"ice",
|
|
97
|
+
"match",
|
|
98
|
+
"consume",
|
|
99
|
+
"match_token",
|
|
100
|
+
"consume_token",
|
|
101
|
+
"match_many",
|
|
102
|
+
"consume_many",
|
|
103
|
+
]:
|
|
96
104
|
continue
|
|
97
|
-
self.assertIn(
|
|
105
|
+
self.assertIn(fn, rules)
|
|
98
106
|
|
|
99
107
|
def test_all_ast_has_normalize(self) -> None:
|
|
100
108
|
"""Test for enter/exit name diffs with parser."""
|
jaclang/plugin/builtin.py
CHANGED
|
@@ -7,6 +7,12 @@ from typing import Optional
|
|
|
7
7
|
from jaclang.plugin.feature import JacFeature as Jac
|
|
8
8
|
from jaclang.runtimelib.constructs import Architype, NodeArchitype
|
|
9
9
|
|
|
10
|
+
__all__ = [
|
|
11
|
+
"dotgen",
|
|
12
|
+
"jid",
|
|
13
|
+
"jobj",
|
|
14
|
+
]
|
|
15
|
+
|
|
10
16
|
|
|
11
17
|
def dotgen(
|
|
12
18
|
node: Optional[NodeArchitype] = None,
|
|
@@ -44,3 +50,8 @@ def dotgen(
|
|
|
44
50
|
def jid(obj: Architype) -> str:
|
|
45
51
|
"""Get the id of the object."""
|
|
46
52
|
return Jac.object_ref(obj)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def jobj(id: str) -> Architype | None:
|
|
56
|
+
"""Get the object from the id."""
|
|
57
|
+
return Jac.get_object(id)
|
jaclang/plugin/default.py
CHANGED
|
@@ -179,14 +179,12 @@ class JacAccessValidationImpl:
|
|
|
179
179
|
if to_root.access.all > access_level:
|
|
180
180
|
access_level = to_root.access.all
|
|
181
181
|
|
|
182
|
-
level
|
|
183
|
-
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
182
|
+
if (level := to_root.access.roots.check(str(jroot.id))) is not None:
|
|
184
183
|
access_level = level
|
|
185
184
|
|
|
186
185
|
# if target anchor have set allowed roots
|
|
187
186
|
# if current root is allowed to target anchor
|
|
188
|
-
level
|
|
189
|
-
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
187
|
+
if (level := to_access.roots.check(str(jroot.id))) is not None:
|
|
190
188
|
access_level = level
|
|
191
189
|
|
|
192
190
|
return access_level
|
|
@@ -662,11 +660,15 @@ class JacFeatureImpl(
|
|
|
662
660
|
if not hasattr(cls, "_jac_entry_funcs_") or not hasattr(
|
|
663
661
|
cls, "_jac_exit_funcs_"
|
|
664
662
|
):
|
|
665
|
-
#
|
|
666
|
-
#
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
663
|
+
# If a class only inherit from object (ie. Doesn't inherit from a class), we cannot modify
|
|
664
|
+
# the __bases__ property of it, so it's necessary to make sure the class is not a direct child of object.
|
|
665
|
+
assert cls.__bases__ != (object,)
|
|
666
|
+
bases = (
|
|
667
|
+
(cls.__bases__ + (arch_base,))
|
|
668
|
+
if arch_base not in cls.__bases__
|
|
669
|
+
else cls.__bases__
|
|
670
|
+
)
|
|
671
|
+
cls.__bases__ = bases
|
|
670
672
|
cls._jac_entry_funcs_ = on_entry # type: ignore
|
|
671
673
|
cls._jac_exit_funcs_ = on_exit # type: ignore
|
|
672
674
|
else:
|
|
@@ -726,6 +728,22 @@ class JacFeatureImpl(
|
|
|
726
728
|
|
|
727
729
|
return decorator
|
|
728
730
|
|
|
731
|
+
@staticmethod
|
|
732
|
+
@hookimpl
|
|
733
|
+
def make_root(
|
|
734
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
735
|
+
) -> Callable[[type], type]:
|
|
736
|
+
"""Create a obj architype."""
|
|
737
|
+
|
|
738
|
+
def decorator(cls: Type[Architype]) -> Type[Architype]:
|
|
739
|
+
"""Decorate class."""
|
|
740
|
+
cls = Jac.make_architype(
|
|
741
|
+
cls=cls, arch_base=Root, on_entry=on_entry, on_exit=on_exit
|
|
742
|
+
)
|
|
743
|
+
return cls
|
|
744
|
+
|
|
745
|
+
return decorator
|
|
746
|
+
|
|
729
747
|
@staticmethod
|
|
730
748
|
@hookimpl
|
|
731
749
|
def make_edge(
|
|
@@ -742,6 +760,25 @@ class JacFeatureImpl(
|
|
|
742
760
|
|
|
743
761
|
return decorator
|
|
744
762
|
|
|
763
|
+
@staticmethod
|
|
764
|
+
@hookimpl
|
|
765
|
+
def make_generic_edge(
|
|
766
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
767
|
+
) -> Callable[[type], type]:
|
|
768
|
+
"""Create a edge architype."""
|
|
769
|
+
|
|
770
|
+
def decorator(cls: Type[Architype]) -> Type[Architype]:
|
|
771
|
+
"""Decorate class."""
|
|
772
|
+
cls = Jac.make_architype(
|
|
773
|
+
cls=cls,
|
|
774
|
+
arch_base=GenericEdge,
|
|
775
|
+
on_entry=on_entry,
|
|
776
|
+
on_exit=on_exit,
|
|
777
|
+
)
|
|
778
|
+
return cls
|
|
779
|
+
|
|
780
|
+
return decorator
|
|
781
|
+
|
|
745
782
|
@staticmethod
|
|
746
783
|
@hookimpl
|
|
747
784
|
def make_walker(
|
|
@@ -920,12 +957,6 @@ class JacFeatureImpl(
|
|
|
920
957
|
|
|
921
958
|
return ret_count
|
|
922
959
|
|
|
923
|
-
@staticmethod
|
|
924
|
-
@hookimpl
|
|
925
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
926
|
-
"""Jac's elvis operator feature."""
|
|
927
|
-
return ret if (ret := op1) is not None else op2
|
|
928
|
-
|
|
929
960
|
@staticmethod
|
|
930
961
|
@hookimpl
|
|
931
962
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
|
@@ -1032,7 +1063,7 @@ class JacFeatureImpl(
|
|
|
1032
1063
|
dir in [EdgeDir.OUT, EdgeDir.ANY]
|
|
1033
1064
|
and node == source
|
|
1034
1065
|
and target.architype in right
|
|
1035
|
-
and Jac.
|
|
1066
|
+
and Jac.check_connect_access(target)
|
|
1036
1067
|
):
|
|
1037
1068
|
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
1038
1069
|
disconnect_occurred = True
|
|
@@ -1040,7 +1071,7 @@ class JacFeatureImpl(
|
|
|
1040
1071
|
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
1041
1072
|
and node == target
|
|
1042
1073
|
and source.architype in right
|
|
1043
|
-
and Jac.
|
|
1074
|
+
and Jac.check_connect_access(source)
|
|
1044
1075
|
):
|
|
1045
1076
|
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
1046
1077
|
disconnect_occurred = True
|
|
@@ -1069,7 +1100,9 @@ class JacFeatureImpl(
|
|
|
1069
1100
|
@hookimpl
|
|
1070
1101
|
def get_root_type() -> Type[Root]:
|
|
1071
1102
|
"""Jac's root getter."""
|
|
1072
|
-
|
|
1103
|
+
from jaclang import Root as JRoot
|
|
1104
|
+
|
|
1105
|
+
return cast(Type[Root], JRoot)
|
|
1073
1106
|
|
|
1074
1107
|
@staticmethod
|
|
1075
1108
|
@hookimpl
|
|
@@ -1079,10 +1112,12 @@ class JacFeatureImpl(
|
|
|
1079
1112
|
conn_assign: Optional[tuple[tuple, tuple]],
|
|
1080
1113
|
) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]:
|
|
1081
1114
|
"""Jac's root getter."""
|
|
1082
|
-
|
|
1115
|
+
from jaclang import GenericEdge
|
|
1116
|
+
|
|
1117
|
+
ct = conn_type if conn_type else GenericEdge
|
|
1083
1118
|
|
|
1084
1119
|
def builder(source: NodeAnchor, target: NodeAnchor) -> EdgeArchitype:
|
|
1085
|
-
edge =
|
|
1120
|
+
edge = ct() if isinstance(ct, type) else ct
|
|
1086
1121
|
|
|
1087
1122
|
eanch = edge.__jac__ = EdgeAnchor(
|
|
1088
1123
|
architype=edge,
|
jaclang/plugin/feature.py
CHANGED
|
@@ -305,6 +305,13 @@ class JacFeature(
|
|
|
305
305
|
"""Create a node architype."""
|
|
306
306
|
return plugin_manager.hook.make_node(on_entry=on_entry, on_exit=on_exit)
|
|
307
307
|
|
|
308
|
+
@staticmethod
|
|
309
|
+
def make_root(
|
|
310
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
311
|
+
) -> Callable[[type], type]:
|
|
312
|
+
"""Create a root node architype."""
|
|
313
|
+
return plugin_manager.hook.make_root(on_entry=on_entry, on_exit=on_exit)
|
|
314
|
+
|
|
308
315
|
@staticmethod
|
|
309
316
|
def make_edge(
|
|
310
317
|
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
@@ -312,6 +319,13 @@ class JacFeature(
|
|
|
312
319
|
"""Create a edge architype."""
|
|
313
320
|
return plugin_manager.hook.make_edge(on_entry=on_entry, on_exit=on_exit)
|
|
314
321
|
|
|
322
|
+
@staticmethod
|
|
323
|
+
def make_generic_edge(
|
|
324
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
325
|
+
) -> Callable[[type], type]:
|
|
326
|
+
"""Create a edge architype."""
|
|
327
|
+
return plugin_manager.hook.make_generic_edge(on_entry=on_entry, on_exit=on_exit)
|
|
328
|
+
|
|
315
329
|
@staticmethod
|
|
316
330
|
def make_walker(
|
|
317
331
|
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
@@ -377,11 +391,6 @@ class JacFeature(
|
|
|
377
391
|
verbose=verbose,
|
|
378
392
|
)
|
|
379
393
|
|
|
380
|
-
@staticmethod
|
|
381
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
382
|
-
"""Jac's elvis operator feature."""
|
|
383
|
-
return plugin_manager.hook.elvis(op1=op1, op2=op2)
|
|
384
|
-
|
|
385
394
|
@staticmethod
|
|
386
395
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
|
387
396
|
"""Jac's has container default feature."""
|
jaclang/plugin/spec.py
CHANGED
|
@@ -295,6 +295,14 @@ class JacFeatureSpec(
|
|
|
295
295
|
"""Create a node architype."""
|
|
296
296
|
raise NotImplementedError
|
|
297
297
|
|
|
298
|
+
@staticmethod
|
|
299
|
+
@hookspec(firstresult=True)
|
|
300
|
+
def make_root(
|
|
301
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
302
|
+
) -> Callable[[type], type]:
|
|
303
|
+
"""Create a root node architype."""
|
|
304
|
+
raise NotImplementedError
|
|
305
|
+
|
|
298
306
|
@staticmethod
|
|
299
307
|
@hookspec(firstresult=True)
|
|
300
308
|
def make_edge(
|
|
@@ -303,6 +311,14 @@ class JacFeatureSpec(
|
|
|
303
311
|
"""Create a edge architype."""
|
|
304
312
|
raise NotImplementedError
|
|
305
313
|
|
|
314
|
+
@staticmethod
|
|
315
|
+
@hookspec(firstresult=True)
|
|
316
|
+
def make_generic_edge(
|
|
317
|
+
on_entry: list[DSFunc], on_exit: list[DSFunc]
|
|
318
|
+
) -> Callable[[type], type]:
|
|
319
|
+
"""Create a generic edge architype."""
|
|
320
|
+
raise NotImplementedError
|
|
321
|
+
|
|
306
322
|
@staticmethod
|
|
307
323
|
@hookspec(firstresult=True)
|
|
308
324
|
def make_walker(
|
|
@@ -355,12 +371,6 @@ class JacFeatureSpec(
|
|
|
355
371
|
"""Run the test suite in the specified .jac file."""
|
|
356
372
|
raise NotImplementedError
|
|
357
373
|
|
|
358
|
-
@staticmethod
|
|
359
|
-
@hookspec(firstresult=True)
|
|
360
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
361
|
-
"""Jac's elvis operator feature."""
|
|
362
|
-
raise NotImplementedError
|
|
363
|
-
|
|
364
374
|
@staticmethod
|
|
365
375
|
@hookspec(firstresult=True)
|
|
366
376
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
|
@@ -748,7 +748,7 @@ class TestJaseciPlugin(TestCase):
|
|
|
748
748
|
def test_savable_object(self) -> None:
|
|
749
749
|
"""Test ObjectAnchor save."""
|
|
750
750
|
global session
|
|
751
|
-
session = self.fixture_abs_path("
|
|
751
|
+
session = self.fixture_abs_path("savable_object.session")
|
|
752
752
|
|
|
753
753
|
self._output2buffer()
|
|
754
754
|
|
jaclang/runtimelib/architype.py
CHANGED
|
@@ -12,6 +12,7 @@ from types import UnionType
|
|
|
12
12
|
from typing import Any, Callable, ClassVar, Optional, TypeVar
|
|
13
13
|
from uuid import UUID, uuid4
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
logger = getLogger(__name__)
|
|
16
17
|
|
|
17
18
|
TARCH = TypeVar("TARCH", bound="Architype")
|
|
@@ -44,9 +45,9 @@ class Access:
|
|
|
44
45
|
|
|
45
46
|
anchors: dict[str, AccessLevel] = field(default_factory=dict)
|
|
46
47
|
|
|
47
|
-
def check(self, anchor: str) -> AccessLevel:
|
|
48
|
+
def check(self, anchor: str) -> AccessLevel | None:
|
|
48
49
|
"""Validate access."""
|
|
49
|
-
return self.anchors.get(anchor
|
|
50
|
+
return self.anchors.get(anchor)
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
@dataclass
|
|
@@ -285,21 +286,13 @@ class ObjectArchitype(Architype):
|
|
|
285
286
|
self.__jac__ = ObjectAnchor(architype=self)
|
|
286
287
|
|
|
287
288
|
|
|
288
|
-
@dataclass(eq=False)
|
|
289
289
|
class GenericEdge(EdgeArchitype):
|
|
290
|
-
"""Generic
|
|
291
|
-
|
|
292
|
-
_jac_entry_funcs_: ClassVar[list[DSFunc]] = []
|
|
293
|
-
_jac_exit_funcs_: ClassVar[list[DSFunc]] = []
|
|
290
|
+
"""Generic Edge."""
|
|
294
291
|
|
|
295
292
|
|
|
296
|
-
@dataclass(eq=False)
|
|
297
293
|
class Root(NodeArchitype):
|
|
298
294
|
"""Generic Root Node."""
|
|
299
295
|
|
|
300
|
-
_jac_entry_funcs_: ClassVar[list[DSFunc]] = []
|
|
301
|
-
_jac_exit_funcs_: ClassVar[list[DSFunc]] = []
|
|
302
|
-
|
|
303
296
|
def __init__(self) -> None:
|
|
304
297
|
"""Create root node."""
|
|
305
298
|
self.__jac__ = NodeAnchor(architype=self, persistent=True, edges=[])
|
|
@@ -315,16 +308,13 @@ class DSFunc:
|
|
|
315
308
|
@cached_property
|
|
316
309
|
def trigger(self) -> type | UnionType | tuple[type | UnionType, ...] | None:
|
|
317
310
|
"""Get function parameter annotations."""
|
|
318
|
-
|
|
319
|
-
(
|
|
320
|
-
|
|
321
|
-
.
|
|
322
|
-
.annotation
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
else None
|
|
326
|
-
)
|
|
327
|
-
return None if t is inspect._empty else t
|
|
311
|
+
if self.func:
|
|
312
|
+
parameters = inspect.signature(self.func, eval_str=True).parameters
|
|
313
|
+
if len(parameters) >= 2:
|
|
314
|
+
second_param = list(parameters.values())[1]
|
|
315
|
+
ty = second_param.annotation
|
|
316
|
+
return ty if ty != inspect._empty else None
|
|
317
|
+
return None
|
|
328
318
|
|
|
329
319
|
def resolve(self, cls: type) -> None:
|
|
330
320
|
"""Resolve the function."""
|
jaclang/runtimelib/context.py
CHANGED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import unittest
|
|
6
6
|
from contextvars import ContextVar
|
|
7
7
|
from dataclasses import MISSING
|
|
8
|
-
from typing import Any, Callable, Optional, cast
|
|
8
|
+
from typing import Any, Callable, ClassVar, Optional, cast
|
|
9
9
|
from uuid import UUID
|
|
10
10
|
|
|
11
11
|
from .architype import NodeAnchor, Root
|
|
@@ -13,13 +13,7 @@ from .memory import Memory, ShelfStorage
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
EXECUTION_CONTEXT = ContextVar[Optional["ExecutionContext"]]("ExecutionContext")
|
|
16
|
-
|
|
17
16
|
SUPER_ROOT_UUID = UUID("00000000-0000-0000-0000-000000000000")
|
|
18
|
-
SUPER_ROOT_ARCHITYPE = object.__new__(Root)
|
|
19
|
-
SUPER_ROOT_ANCHOR = NodeAnchor(
|
|
20
|
-
id=SUPER_ROOT_UUID, architype=SUPER_ROOT_ARCHITYPE, persistent=False, edges=[]
|
|
21
|
-
)
|
|
22
|
-
SUPER_ROOT_ARCHITYPE.__jac__ = SUPER_ROOT_ANCHOR
|
|
23
17
|
|
|
24
18
|
|
|
25
19
|
class ExecutionContext:
|
|
@@ -32,6 +26,9 @@ class ExecutionContext:
|
|
|
32
26
|
root: NodeAnchor
|
|
33
27
|
entry_node: NodeAnchor
|
|
34
28
|
|
|
29
|
+
# A context change event subscription list, those who want to listen ctx change will register here.
|
|
30
|
+
on_ctx_change: ClassVar[list[Callable[[ExecutionContext | None], None]]] = []
|
|
31
|
+
|
|
35
32
|
def init_anchor(
|
|
36
33
|
self,
|
|
37
34
|
anchor_id: str | None,
|
|
@@ -52,6 +49,8 @@ class ExecutionContext:
|
|
|
52
49
|
"""Close current ExecutionContext."""
|
|
53
50
|
self.mem.close()
|
|
54
51
|
EXECUTION_CONTEXT.set(None)
|
|
52
|
+
for func in ExecutionContext.on_ctx_change:
|
|
53
|
+
func(EXECUTION_CONTEXT.get(None))
|
|
55
54
|
|
|
56
55
|
@staticmethod
|
|
57
56
|
def create(
|
|
@@ -60,6 +59,8 @@ class ExecutionContext:
|
|
|
60
59
|
auto_close: bool = True,
|
|
61
60
|
) -> ExecutionContext:
|
|
62
61
|
"""Create ExecutionContext."""
|
|
62
|
+
from jaclang import Root
|
|
63
|
+
|
|
63
64
|
ctx = ExecutionContext()
|
|
64
65
|
ctx.mem = ShelfStorage(session)
|
|
65
66
|
ctx.reports = []
|
|
@@ -67,7 +68,7 @@ class ExecutionContext:
|
|
|
67
68
|
if not isinstance(
|
|
68
69
|
system_root := ctx.mem.find_by_id(SUPER_ROOT_UUID), NodeAnchor
|
|
69
70
|
):
|
|
70
|
-
system_root = Root().__jac__
|
|
71
|
+
system_root = cast(NodeAnchor, Root().__jac__) # type: ignore[attr-defined]
|
|
71
72
|
system_root.id = SUPER_ROOT_UUID
|
|
72
73
|
ctx.mem.set(system_root.id, system_root)
|
|
73
74
|
|
|
@@ -79,6 +80,8 @@ class ExecutionContext:
|
|
|
79
80
|
old_ctx.close()
|
|
80
81
|
|
|
81
82
|
EXECUTION_CONTEXT.set(ctx)
|
|
83
|
+
for func in ExecutionContext.on_ctx_change:
|
|
84
|
+
func(EXECUTION_CONTEXT.get(None))
|
|
82
85
|
|
|
83
86
|
return ctx
|
|
84
87
|
|
|
@@ -95,7 +98,20 @@ class ExecutionContext:
|
|
|
95
98
|
if ctx := EXECUTION_CONTEXT.get(None):
|
|
96
99
|
return cast(Root, ctx.root.architype)
|
|
97
100
|
|
|
98
|
-
return
|
|
101
|
+
return cast(Root, ExecutionContext.global_system_root().architype)
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def global_system_root() -> NodeAnchor:
|
|
105
|
+
"""Get global system root."""
|
|
106
|
+
from jaclang import Root
|
|
107
|
+
|
|
108
|
+
if not (sr_anch := getattr(ExecutionContext, "system_root", None)):
|
|
109
|
+
sr_arch = Root()
|
|
110
|
+
sr_anch = sr_arch.__jac__ # type: ignore[attr-defined]
|
|
111
|
+
sr_anch.id = SUPER_ROOT_UUID
|
|
112
|
+
sr_anch.persistent = False
|
|
113
|
+
ExecutionContext.system_root = sr_anch
|
|
114
|
+
return sr_anch
|
|
99
115
|
|
|
100
116
|
|
|
101
117
|
class JacTestResult(unittest.TextTestResult):
|
jaclang/runtimelib/importer.py
CHANGED
|
@@ -158,9 +158,6 @@ class ImportReturn:
|
|
|
158
158
|
return getattr(new_module, name, new_module)
|
|
159
159
|
except ImportError as e:
|
|
160
160
|
logger.error(dump_traceback(e))
|
|
161
|
-
# logger.error(
|
|
162
|
-
# f"Failed to load {name} from {jac_file_path} in {module.__name__}: {str(e)}"
|
|
163
|
-
# )
|
|
164
161
|
return None
|
|
165
162
|
|
|
166
163
|
|
|
@@ -319,6 +316,32 @@ class JacImporter(Importer):
|
|
|
319
316
|
"""Run the import process for Jac modules."""
|
|
320
317
|
unique_loaded_items: list[types.ModuleType] = []
|
|
321
318
|
module = None
|
|
319
|
+
# Gather all possible search paths
|
|
320
|
+
jacpaths = os.environ.get("JACPATH", "")
|
|
321
|
+
search_paths = [spec.caller_dir]
|
|
322
|
+
if jacpaths:
|
|
323
|
+
for p in jacpaths.split(os.pathsep):
|
|
324
|
+
p = p.strip()
|
|
325
|
+
if p and p not in search_paths:
|
|
326
|
+
search_paths.append(p)
|
|
327
|
+
|
|
328
|
+
# Attempt to locate the module file or directory
|
|
329
|
+
found_path = None
|
|
330
|
+
target_path_components = spec.target.split(".")
|
|
331
|
+
for search_path in search_paths:
|
|
332
|
+
candidate = os.path.join(search_path, "/".join(target_path_components))
|
|
333
|
+
# Check if the candidate is a directory or a .jac file
|
|
334
|
+
if (os.path.isdir(candidate)) or (os.path.isfile(candidate + ".jac")):
|
|
335
|
+
found_path = candidate
|
|
336
|
+
break
|
|
337
|
+
|
|
338
|
+
# If a suitable path was found, update spec.full_target; otherwise, raise an error
|
|
339
|
+
if found_path:
|
|
340
|
+
spec.full_target = os.path.abspath(found_path)
|
|
341
|
+
else:
|
|
342
|
+
raise ImportError(
|
|
343
|
+
f"Unable to locate module '{spec.target}' in {search_paths}"
|
|
344
|
+
)
|
|
322
345
|
if os.path.isfile(spec.full_target + ".jac"):
|
|
323
346
|
module_name = self.get_sys_mod_name(spec.full_target + ".jac")
|
|
324
347
|
module_name = spec.override_name if spec.override_name else module_name
|
jaclang/runtimelib/machine.py
CHANGED
|
@@ -38,6 +38,7 @@ class JacMachine:
|
|
|
38
38
|
self.loaded_modules: dict[str, types.ModuleType] = {}
|
|
39
39
|
if not base_path:
|
|
40
40
|
base_path = os.getcwd()
|
|
41
|
+
# Ensure the base_path is a list rather than a string
|
|
41
42
|
self.base_path = base_path
|
|
42
43
|
self.base_path_dir = (
|
|
43
44
|
os.path.dirname(base_path)
|
|
@@ -306,12 +307,11 @@ class JacProgram:
|
|
|
306
307
|
return marshal.load(f)
|
|
307
308
|
|
|
308
309
|
result = compile_jac(full_target, cache_result=cachable)
|
|
309
|
-
if result.errors_had
|
|
310
|
+
if result.errors_had:
|
|
310
311
|
for alrt in result.errors_had:
|
|
311
312
|
# We're not logging here, it already gets logged as the errors were added to the errors_had list.
|
|
312
313
|
# Regardless of the logging, this needs to be sent to the end user, so we'll printing it to stderr.
|
|
313
314
|
logger.error(alrt.pretty_print())
|
|
314
|
-
return None
|
|
315
315
|
if result.ir.gen.py_bytecode is not None:
|
|
316
316
|
return marshal.loads(result.ir.gen.py_bytecode)
|
|
317
317
|
else:
|
jaclang/settings.py
CHANGED