jaclang 0.8.9__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.

Files changed (103) hide show
  1. jaclang/cli/cli.py +147 -25
  2. jaclang/cli/cmdreg.py +144 -8
  3. jaclang/compiler/__init__.py +6 -1
  4. jaclang/compiler/codeinfo.py +16 -1
  5. jaclang/compiler/constant.py +33 -13
  6. jaclang/compiler/jac.lark +130 -31
  7. jaclang/compiler/larkparse/jac_parser.py +2 -2
  8. jaclang/compiler/parser.py +567 -176
  9. jaclang/compiler/passes/__init__.py +2 -1
  10. jaclang/compiler/passes/ast_gen/__init__.py +5 -0
  11. jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
  12. jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
  13. jaclang/compiler/passes/ecmascript/__init__.py +25 -0
  14. jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
  15. jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
  16. jaclang/compiler/passes/ecmascript/estree.py +972 -0
  17. jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
  18. jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
  19. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
  20. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
  21. jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
  22. jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
  23. jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
  24. jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
  25. jaclang/compiler/passes/main/__init__.py +0 -3
  26. jaclang/compiler/passes/main/annex_pass.py +23 -1
  27. jaclang/compiler/passes/main/pyast_gen_pass.py +324 -234
  28. jaclang/compiler/passes/main/pyast_load_pass.py +46 -11
  29. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
  30. jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
  31. jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
  32. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
  33. jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
  34. jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
  35. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
  36. jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -2
  37. jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
  38. jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
  39. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
  40. jaclang/compiler/passes/main/type_checker_pass.py +7 -0
  41. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +115 -0
  42. jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
  43. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
  44. jaclang/compiler/passes/transform.py +9 -1
  45. jaclang/compiler/passes/uni_pass.py +5 -7
  46. jaclang/compiler/program.py +22 -25
  47. jaclang/compiler/tests/test_client_codegen.py +113 -0
  48. jaclang/compiler/tests/test_importer.py +12 -10
  49. jaclang/compiler/tests/test_parser.py +249 -3
  50. jaclang/compiler/type_system/type_evaluator.jac +169 -50
  51. jaclang/compiler/type_system/type_utils.py +1 -1
  52. jaclang/compiler/type_system/types.py +6 -0
  53. jaclang/compiler/unitree.py +430 -84
  54. jaclang/langserve/engine.jac +224 -288
  55. jaclang/langserve/sem_manager.jac +12 -8
  56. jaclang/langserve/server.jac +48 -48
  57. jaclang/langserve/tests/fixtures/greet.py +17 -0
  58. jaclang/langserve/tests/fixtures/md_path.jac +22 -0
  59. jaclang/langserve/tests/fixtures/user.jac +15 -0
  60. jaclang/langserve/tests/test_server.py +66 -371
  61. jaclang/lib.py +1 -1
  62. jaclang/runtimelib/client_bundle.py +169 -0
  63. jaclang/runtimelib/client_runtime.jac +586 -0
  64. jaclang/runtimelib/constructs.py +2 -0
  65. jaclang/runtimelib/machine.py +259 -100
  66. jaclang/runtimelib/meta_importer.py +111 -22
  67. jaclang/runtimelib/mtp.py +15 -0
  68. jaclang/runtimelib/server.py +1089 -0
  69. jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
  70. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  71. jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
  72. jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
  73. jaclang/runtimelib/tests/test_client_bundle.py +55 -0
  74. jaclang/runtimelib/tests/test_client_render.py +63 -0
  75. jaclang/runtimelib/tests/test_serve.py +1069 -0
  76. jaclang/settings.py +0 -2
  77. jaclang/tests/fixtures/iife_functions.jac +142 -0
  78. jaclang/tests/fixtures/iife_functions_client.jac +143 -0
  79. jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
  80. jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
  81. jaclang/tests/fixtures/needs_import_dup.jac +6 -4
  82. jaclang/tests/fixtures/py_run.py +7 -5
  83. jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
  84. jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
  85. jaclang/tests/test_cli.py +1 -1
  86. jaclang/tests/test_language.py +10 -39
  87. jaclang/tests/test_reference.py +17 -2
  88. jaclang/utils/NonGPT.py +375 -0
  89. jaclang/utils/helpers.py +44 -16
  90. jaclang/utils/lang_tools.py +31 -4
  91. jaclang/utils/tests/test_lang_tools.py +1 -1
  92. jaclang/utils/treeprinter.py +8 -3
  93. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
  94. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/RECORD +96 -66
  95. jaclang/compiler/passes/main/binder_pass.py +0 -594
  96. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
  97. jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
  98. jaclang/langserve/tests/session.jac +0 -294
  99. jaclang/langserve/tests/test_dev_server.py +0 -80
  100. jaclang/runtimelib/importer.py +0 -351
  101. jaclang/tests/test_typecheck.py +0 -542
  102. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
  103. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
@@ -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
 
@@ -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
- if not isinstance(
89
- system_root := self.mem.find_by_id(UUID(Con.SUPER_ROOT_UUID)), NodeAnchor
90
- ):
91
- system_root = cast(NodeAnchor, Root().__jac__) # type: ignore[attr-defined]
92
- system_root.id = UUID(Con.SUPER_ROOT_UUID)
93
- self.mem.set(system_root.id, system_root)
94
-
95
- self.system_root = system_root
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 init_anchor(
100
- self,
101
- anchor_id: str | None,
102
- default: NodeAnchor,
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 default
105
+ return anchor
110
106
 
111
107
  def set_entry_node(self, entry_node: str | None) -> None:
112
- """Override entry."""
113
- self.entry_node = self.init_anchor(entry_node, self.root_state)
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."""
@@ -698,7 +695,7 @@ class JacClassReferences:
698
695
  Root: TypeAlias = _Root
699
696
  GenericEdge: TypeAlias = _GenericEdge
700
697
 
701
- Path: TypeAlias = ObjectSpatialPath
698
+ OPath: TypeAlias = ObjectSpatialPath
702
699
 
703
700
 
704
701
  class JacBuiltin:
@@ -937,45 +934,163 @@ class JacBasics:
937
934
  target: str,
938
935
  base_path: str,
939
936
  absorb: bool = False,
940
- mdl_alias: Optional[str] = None,
941
937
  override_name: Optional[str] = None,
942
938
  items: Optional[dict[str, Union[str, Optional[str]]]] = None,
943
939
  reload_module: Optional[bool] = False,
944
940
  lng: Optional[str] = None,
945
941
  ) -> tuple[types.ModuleType, ...]:
946
- """Core Import Process."""
947
- from jaclang.runtimelib.importer import (
948
- ImportPathSpec,
949
- JacImporter,
950
- PythonImporter,
951
- )
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
952
972
 
953
973
  if lng is None:
954
974
  lng = infer_language(target, base_path)
955
975
 
956
- spec = ImportPathSpec(
957
- target,
958
- base_path,
959
- absorb,
960
- mdl_alias,
961
- override_name,
962
- lng,
963
- items,
964
- )
965
-
966
976
  if not JacMachine.program:
967
977
  JacMachineInterface.attach_program(JacProgram())
968
978
 
969
- if lng == "py":
970
- import_result = PythonImporter().run_import(spec)
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
971
995
  else:
972
- import_result = JacImporter().run_import(spec, reload_module)
996
+ module_name = target
973
997
 
974
- return (
975
- (import_result.ret_mod,)
976
- if absorb or not items
977
- else tuple(import_result.ret_items)
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)
978
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
979
1094
 
980
1095
  @staticmethod
981
1096
  def jac_test(test_fun: Callable) -> Callable:
@@ -991,6 +1106,30 @@ class JacBasics:
991
1106
 
992
1107
  return test_deco
993
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
+
994
1133
  @staticmethod
995
1134
  def run_test(
996
1135
  filepath: str,
@@ -1066,7 +1205,7 @@ class JacBasics:
1066
1205
  return field(init=init)
1067
1206
 
1068
1207
  @staticmethod
1069
- def report(expr: Any, custom: bool = False) -> None: # noqa: ANN401
1208
+ def log_report(expr: Any, custom: bool = False) -> None: # noqa: ANN401
1070
1209
  """Jac's report stmt feature."""
1071
1210
  ctx = JacMachineInterface.get_context()
1072
1211
  if custom:
@@ -1315,9 +1454,11 @@ class JacByLLM:
1315
1454
  """Jac byLLM integration."""
1316
1455
 
1317
1456
  @staticmethod
1318
- def get_mtir(caller: Callable, args: dict, call_params: dict) -> object:
1457
+ def get_mtir(
1458
+ caller: Callable, args: dict[int | str, object], call_params: dict[str, object]
1459
+ ) -> MTIR:
1319
1460
  """Get byLLM library."""
1320
- return None
1461
+ return MTIR(caller=caller, args=args, call_params=call_params)
1321
1462
 
1322
1463
  @staticmethod
1323
1464
  def sem(semstr: str, inner_semstr: dict[str, str]) -> Callable:
@@ -1331,15 +1472,23 @@ class JacByLLM:
1331
1472
  return decorator
1332
1473
 
1333
1474
  @staticmethod
1334
- def call_llm(model: object, mtir: object) -> Any: # noqa: ANN401
1335
- """Call the LLM model.
1475
+ def call_llm(model: object, mtir: MTIR) -> Any: # noqa: ANN401
1476
+ """Call the LLM model."""
1477
+ from jaclang.utils.NonGPT import random_value_for_type
1336
1478
 
1337
- Note: This is for future uses of the feature in contexts that cannot be decorated.
1338
- For most use cases, use the `by` decorator instead.
1339
- """
1340
- raise ImportError(
1341
- "byLLM is not installed. Please install it with `pip install byllm` and run `jac clean`."
1342
- )
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)
1343
1492
 
1344
1493
  @staticmethod
1345
1494
  def by(model: object) -> Callable:
@@ -1395,7 +1544,11 @@ class JacUtils:
1395
1544
  if module:
1396
1545
  walkers = []
1397
1546
  for name, obj in inspect.getmembers(module):
1398
- if isinstance(obj, type) and issubclass(obj, WalkerArchetype):
1547
+ if (
1548
+ isinstance(obj, type)
1549
+ and issubclass(obj, WalkerArchetype)
1550
+ and obj.__module__ == module_name
1551
+ ):
1399
1552
  walkers.append(name)
1400
1553
  return walkers
1401
1554
  return []
@@ -1407,7 +1560,11 @@ class JacUtils:
1407
1560
  if module:
1408
1561
  nodes = []
1409
1562
  for name, obj in inspect.getmembers(module):
1410
- if isinstance(obj, type) and issubclass(obj, NodeArchetype):
1563
+ if (
1564
+ isinstance(obj, type)
1565
+ and issubclass(obj, NodeArchetype)
1566
+ and obj.__module__ == module_name
1567
+ ):
1411
1568
  nodes.append(name)
1412
1569
  return nodes
1413
1570
  return []
@@ -1417,11 +1574,15 @@ class JacUtils:
1417
1574
  """List all edges in a specific module."""
1418
1575
  module = JacMachine.loaded_modules.get(module_name)
1419
1576
  if module:
1420
- nodes = []
1577
+ edges = []
1421
1578
  for name, obj in inspect.getmembers(module):
1422
- if isinstance(obj, type) and issubclass(obj, EdgeArchetype):
1423
- nodes.append(name)
1424
- return nodes
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
1425
1586
  return []
1426
1587
 
1427
1588
  @staticmethod
@@ -1432,9 +1593,11 @@ class JacUtils:
1432
1593
  cachable: bool = False,
1433
1594
  keep_temporary_files: bool = False,
1434
1595
  ) -> Optional[types.ModuleType]:
1435
- """Dynamically creates archetypes (nodes, walkers, etc.) from Jac source code."""
1436
- from jaclang.runtimelib.importer import JacImporter, ImportPathSpec
1596
+ """Dynamically creates archetypes (nodes, walkers, etc.) from Jac source code.
1437
1597
 
1598
+ This leverages Python's standard import machinery via jac_import(),
1599
+ which will automatically invoke JacMetaImporter.
1600
+ """
1438
1601
  if not base_path:
1439
1602
  base_path = JacMachine.base_path_dir or os.getcwd()
1440
1603
 
@@ -1442,6 +1605,7 @@ class JacUtils:
1442
1605
  os.makedirs(base_path)
1443
1606
  if not module_name:
1444
1607
  module_name = f"_dynamic_module_{len(JacMachine.loaded_modules)}"
1608
+
1445
1609
  with tempfile.NamedTemporaryFile(
1446
1610
  mode="w",
1447
1611
  suffix=".jac",
@@ -1453,24 +1617,20 @@ class JacUtils:
1453
1617
  tmp_file.write(source_code)
1454
1618
 
1455
1619
  try:
1456
- importer = JacImporter()
1457
1620
  tmp_file_basename = os.path.basename(tmp_file_path)
1458
1621
  tmp_module_name, _ = os.path.splitext(tmp_file_basename)
1459
1622
 
1460
- spec = ImportPathSpec(
1623
+ # Use simplified jac_import which delegates to importlib
1624
+ result = JacMachineInterface.jac_import(
1461
1625
  target=tmp_module_name,
1462
1626
  base_path=base_path,
1463
- absorb=False,
1464
- mdl_alias=None,
1465
1627
  override_name=module_name,
1466
1628
  lng="jac",
1467
- items=None,
1468
1629
  )
1630
+ module = result[0] if result else None
1469
1631
 
1470
- import_result = importer.run_import(spec, reload=False)
1471
- module = import_result.ret_mod
1472
-
1473
- JacMachine.loaded_modules[module_name] = module
1632
+ if module:
1633
+ JacMachine.loaded_modules[module_name] = module
1474
1634
  return module
1475
1635
  except Exception as e:
1476
1636
  logger.error(f"Error importing dynamic module '{module_name}': {e}")
@@ -1484,36 +1644,31 @@ class JacUtils:
1484
1644
  module_name: str,
1485
1645
  items: Optional[dict[str, Union[str, Optional[str]]]],
1486
1646
  ) -> tuple[types.ModuleType, ...]:
1487
- """Reimport the module."""
1488
- from .importer import JacImporter, ImportPathSpec
1489
-
1647
+ """Reimport the module using Python's reload mechanism."""
1490
1648
  if module_name in JacMachine.loaded_modules:
1491
1649
  try:
1492
1650
  old_module = JacMachine.loaded_modules[module_name]
1493
- importer = JacImporter()
1494
- spec = ImportPathSpec(
1651
+
1652
+ # Use jac_import with reload flag
1653
+ result = JacMachineInterface.jac_import(
1495
1654
  target=module_name,
1496
1655
  base_path=JacMachine.base_path_dir,
1497
- absorb=False,
1498
- mdl_alias=None,
1499
- override_name=None,
1500
- lng="jac",
1501
1656
  items=items,
1657
+ reload_module=True,
1658
+ lng="jac",
1502
1659
  )
1503
- import_result = importer.run_import(spec, reload=True)
1504
- ret_items = []
1660
+
1661
+ # Update the old module's attributes if specific items were requested
1505
1662
  if items:
1506
- for item_name in items:
1507
- if hasattr(old_module, item_name):
1508
- new_attr = getattr(import_result.ret_mod, item_name, None)
1509
- if new_attr:
1510
- ret_items.append(new_attr)
1511
- setattr(
1512
- old_module,
1513
- item_name,
1514
- new_attr,
1515
- )
1516
- 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,)
1517
1672
  except Exception as e:
1518
1673
  logger.error(f"Failed to update module {module_name}: {e}")
1519
1674
  else:
@@ -1719,8 +1874,12 @@ class JacMachine(JacMachineInterface):
1719
1874
  @staticmethod
1720
1875
  def reset_machine() -> None:
1721
1876
  """Reset the machine."""
1722
- # for i in JacMachine.loaded_modules.values():
1723
- # sys.modules.pop(i.__name__, None)
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)
1724
1883
  JacMachine.loaded_modules.clear()
1725
1884
  JacMachine.base_path_dir = os.getcwd()
1726
1885
  JacMachine.program = JacProgram()