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.

Files changed (124) hide show
  1. jaclang/__init__.py +6 -0
  2. jaclang/cli/cli.py +23 -50
  3. jaclang/compiler/codeinfo.py +0 -1
  4. jaclang/compiler/jac.lark +14 -22
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +378 -531
  7. jaclang/compiler/passes/main/__init__.py +0 -14
  8. jaclang/compiler/passes/main/annex_pass.py +2 -8
  9. jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
  11. jaclang/compiler/passes/main/def_use_pass.py +4 -7
  12. jaclang/compiler/passes/main/import_pass.py +6 -14
  13. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  14. jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
  15. jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
  16. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
  18. jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
  19. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
  20. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
  21. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
  22. jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
  23. jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
  24. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
  25. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
  26. jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
  27. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
  28. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
  29. jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
  30. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
  31. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
  32. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
  33. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
  34. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
  35. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
  36. jaclang/compiler/program.py +22 -66
  37. jaclang/compiler/tests/fixtures/fam.jac +2 -2
  38. jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
  39. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
  40. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
  41. jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
  42. jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
  43. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
  44. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
  45. jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
  46. jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
  47. jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
  48. jaclang/compiler/tests/test_importer.py +30 -13
  49. jaclang/compiler/tests/test_parser.py +1 -0
  50. jaclang/compiler/unitree.py +488 -320
  51. jaclang/langserve/__init__.jac +1 -0
  52. jaclang/langserve/engine.jac +503 -0
  53. jaclang/langserve/sem_manager.jac +309 -0
  54. jaclang/langserve/server.jac +201 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
  56. jaclang/langserve/tests/server_test/utils.py +35 -6
  57. jaclang/langserve/tests/session.jac +294 -0
  58. jaclang/langserve/tests/test_sem_tokens.py +2 -2
  59. jaclang/langserve/tests/test_server.py +8 -7
  60. jaclang/langserve/utils.jac +51 -30
  61. jaclang/runtimelib/archetype.py +128 -6
  62. jaclang/runtimelib/builtin.py +17 -14
  63. jaclang/runtimelib/importer.py +51 -76
  64. jaclang/runtimelib/machine.py +469 -305
  65. jaclang/runtimelib/meta_importer.py +86 -0
  66. jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
  67. jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
  68. jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
  69. jaclang/runtimelib/tests/test_jaseci.py +3 -1
  70. jaclang/runtimelib/utils.py +3 -3
  71. jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
  72. jaclang/tests/fixtures/async_ability.jac +43 -10
  73. jaclang/tests/fixtures/async_function.jac +18 -0
  74. jaclang/tests/fixtures/async_walker.jac +17 -12
  75. jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
  76. jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
  77. jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
  78. jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
  79. jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
  80. jaclang/tests/fixtures/concurrency.jac +1 -1
  81. jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
  82. jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
  83. jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
  84. jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
  85. jaclang/tests/fixtures/deep/one_lev.jac +2 -2
  86. jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
  87. jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
  88. jaclang/tests/fixtures/edge_ability.jac +49 -0
  89. jaclang/tests/fixtures/foo.jac +14 -22
  90. jaclang/tests/fixtures/guess_game.jac +1 -1
  91. jaclang/tests/fixtures/here_usage_error.jac +21 -0
  92. jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
  93. jaclang/tests/fixtures/jac_from_py.py +1 -1
  94. jaclang/tests/fixtures/jp_importer.jac +6 -6
  95. jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
  96. jaclang/tests/fixtures/node_del.jac +30 -36
  97. jaclang/tests/fixtures/unicode_strings.jac +24 -0
  98. jaclang/tests/fixtures/visit_traversal.jac +47 -0
  99. jaclang/tests/fixtures/walker_update.jac +5 -7
  100. jaclang/tests/test_cli.py +12 -7
  101. jaclang/tests/test_language.py +218 -145
  102. jaclang/tests/test_reference.py +9 -4
  103. jaclang/tests/test_typecheck.py +13 -26
  104. jaclang/utils/helpers.py +14 -6
  105. jaclang/utils/lang_tools.py +9 -8
  106. jaclang/utils/module_resolver.py +23 -0
  107. jaclang/utils/tests/test_lang_tools.py +2 -1
  108. jaclang/utils/treeprinter.py +3 -4
  109. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
  110. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
  111. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
  112. jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
  113. jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
  114. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
  115. jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
  116. jaclang/langserve/__init__.py +0 -1
  117. jaclang/langserve/engine.py +0 -553
  118. jaclang/langserve/sem_manager.py +0 -383
  119. jaclang/langserve/server.py +0 -167
  120. jaclang/langserve/tests/session.py +0 -255
  121. jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
  122. jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
  123. jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
  124. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
@@ -5,19 +5,16 @@ from __future__ import annotations
5
5
  import importlib
6
6
  import importlib.util
7
7
  import os
8
- import site
9
8
  import sys
10
9
  import types
11
10
  from os import getcwd, path
12
- from typing import Optional, TYPE_CHECKING, Union
11
+ from typing import Optional, Union
13
12
 
14
13
  from jaclang.runtimelib.machine import JacMachineInterface
15
14
  from jaclang.runtimelib.utils import sys_path_context
16
15
  from jaclang.utils.helpers import dump_traceback
17
16
  from jaclang.utils.log import logging
18
-
19
- if TYPE_CHECKING:
20
- from jaclang.runtimelib.machine import JacMachine
17
+ from jaclang.utils.module_resolver import get_jac_search_paths
21
18
 
22
19
  logger = logging.getLogger(__name__)
23
20
 
@@ -98,29 +95,8 @@ class ImportReturn:
98
95
  setattr(module, alias, item)
99
96
 
100
97
  for name, alias in items.items():
101
- try:
102
- item = getattr(module, name)
103
- handle_item_loading(item, alias)
104
- except AttributeError:
105
- if lang == "jac":
106
- jac_file_path = (
107
- os.path.join(module.__path__[0], f"{name}.jac")
108
- if hasattr(module, "__path__")
109
- else module.__file__
110
- )
111
-
112
- if jac_file_path and os.path.isfile(jac_file_path):
113
- item = self.load_jac_mod_as_item(
114
- module=module,
115
- name=name,
116
- jac_file_path=jac_file_path,
117
- )
118
- handle_item_loading(item, alias)
119
- else:
120
- if hasattr(module, "__path__"):
121
- full_module_name = f"{module.__name__}.{name}"
122
- item = importlib.import_module(full_module_name)
123
- handle_item_loading(item, alias)
98
+ item = getattr(module, name)
99
+ handle_item_loading(item, alias)
124
100
 
125
101
  def load_jac_mod_as_item(
126
102
  self,
@@ -129,6 +105,8 @@ class ImportReturn:
129
105
  jac_file_path: str,
130
106
  ) -> Optional[types.ModuleType]:
131
107
  """Load a single .jac file into the specified module component."""
108
+ from jaclang.runtimelib.machine import JacMachine
109
+
132
110
  try:
133
111
  package_name = (
134
112
  f"{module.__name__}.{name}"
@@ -136,7 +114,7 @@ class ImportReturn:
136
114
  else module.__name__
137
115
  )
138
116
  if isinstance(self.importer, JacImporter):
139
- new_module = self.importer.jac_machine.loaded_modules.get(
117
+ new_module = JacMachine.loaded_modules.get(
140
118
  package_name,
141
119
  self.importer.create_jac_py_module(
142
120
  self.importer.get_sys_mod_name(jac_file_path),
@@ -144,10 +122,7 @@ class ImportReturn:
144
122
  jac_file_path,
145
123
  ),
146
124
  )
147
- codeobj = self.importer.jac_machine.jac_program.get_bytecode(
148
- full_target=jac_file_path,
149
- full_compile=not self.importer.jac_machine.interp_mode,
150
- )
125
+ codeobj = JacMachine.program.get_bytecode(full_target=jac_file_path)
151
126
  if not codeobj:
152
127
  raise ImportError(f"No bytecode found for {jac_file_path}")
153
128
 
@@ -161,28 +136,18 @@ class ImportReturn:
161
136
  class Importer:
162
137
  """Abstract base class for all importers."""
163
138
 
164
- def __init__(self, jac_machine: JacMachine) -> None:
139
+ def __init__(self) -> None:
165
140
  """Initialize the Importer object."""
166
- self.jac_machine = jac_machine
167
141
  self.result: Optional[ImportReturn] = None
168
142
 
169
143
  def run_import(self, spec: ImportPathSpec) -> ImportReturn:
170
144
  """Run the import process."""
171
145
  raise NotImplementedError
172
146
 
173
- def update_sys(self, module: types.ModuleType, spec: ImportPathSpec) -> None:
174
- """Update sys.modules with the newly imported module."""
175
- if spec.module_name not in self.jac_machine.loaded_modules:
176
- JacMachineInterface.load_module(self.jac_machine, spec.module_name, module)
177
-
178
147
 
179
148
  class PythonImporter(Importer):
180
149
  """Importer for Python modules."""
181
150
 
182
- def __init__(self, jac_machine: JacMachine) -> None:
183
- """Initialize the PythonImporter object."""
184
- self.jac_machine = jac_machine
185
-
186
151
  def run_import(self, spec: ImportPathSpec) -> ImportReturn:
187
152
  """Run the import process for Python modules."""
188
153
  try:
@@ -254,12 +219,10 @@ class PythonImporter(Importer):
254
219
  class JacImporter(Importer):
255
220
  """Importer for Jac modules."""
256
221
 
257
- def __init__(self, jac_machine: JacMachine) -> None:
258
- """Initialize the JacImporter object."""
259
- self.jac_machine = jac_machine
260
-
261
222
  def get_sys_mod_name(self, full_target: str) -> str:
262
223
  """Generate proper module names from file paths."""
224
+ from jaclang.runtimelib.machine import JacMachine
225
+
263
226
  full_target = os.path.abspath(full_target)
264
227
 
265
228
  # If the file is located within a site-packages directory, strip that prefix.
@@ -269,7 +232,7 @@ class JacImporter(Importer):
269
232
  rel = full_target[sp_index + len("site-packages") :]
270
233
  rel = rel.lstrip(os.sep)
271
234
  else:
272
- rel = path.relpath(full_target, start=self.jac_machine.base_path_dir)
235
+ rel = path.relpath(full_target, start=JacMachine.base_path_dir)
273
236
  rel = os.path.splitext(rel)[0]
274
237
  if os.path.basename(rel) == "__init__":
275
238
  rel = os.path.dirname(rel)
@@ -285,10 +248,36 @@ class JacImporter(Importer):
285
248
  module.__name__ = module_name
286
249
  module.__path__ = [full_mod_path]
287
250
  module.__file__ = None
288
- module.__dict__["__jac_mach__"] = self.jac_machine
289
251
 
290
- if module_name not in self.jac_machine.loaded_modules:
291
- JacMachineInterface.load_module(self.jac_machine, module_name, module)
252
+ JacMachineInterface.load_module(module_name, module)
253
+
254
+ # If the directory contains an __init__.jac, execute it so that the
255
+ # package namespace is populated immediately (mirrors Python's own
256
+ # package behaviour with __init__.py).
257
+ init_jac = os.path.join(full_mod_path, "__init__.jac")
258
+ if os.path.isfile(init_jac):
259
+ from jaclang.runtimelib.machine import JacMachine
260
+
261
+ # Point the package's __file__ to the init file for introspection
262
+ module.__file__ = init_jac
263
+
264
+ codeobj = JacMachine.program.get_bytecode(full_target=init_jac)
265
+ if not codeobj:
266
+ # Compilation should have provided bytecode for __init__.jac.
267
+ # Raising ImportError here surfaces compile-time issues clearly.
268
+ raise ImportError(f"No bytecode found for {init_jac}")
269
+
270
+ try:
271
+ # Ensure the directory is on sys.path while executing so that
272
+ # relative imports inside __init__.jac resolve correctly.
273
+ with sys_path_context(full_mod_path):
274
+ exec(codeobj, module.__dict__)
275
+ except Exception as e:
276
+ # Log detailed traceback for easier debugging and re-raise.
277
+ logger.error(e)
278
+ logger.error(dump_traceback(e))
279
+ raise e
280
+
292
281
  return module
293
282
 
294
283
  def create_jac_py_module(
@@ -298,16 +287,17 @@ class JacImporter(Importer):
298
287
  full_target: str,
299
288
  ) -> types.ModuleType:
300
289
  """Create a module."""
290
+ from jaclang.runtimelib.machine import JacMachine
291
+
301
292
  module = types.ModuleType(module_name)
302
293
  module.__file__ = full_target
303
294
  module.__name__ = module_name
304
- module.__dict__["__jac_mach__"] = self.jac_machine
305
295
  if package_path:
306
296
  base_path = full_target.split(package_path.replace(".", path.sep))[0]
307
297
  parts = package_path.split(".")
308
298
  for i in range(len(parts)):
309
299
  package_name = ".".join(parts[: i + 1])
310
- if package_name not in self.jac_machine.loaded_modules:
300
+ if package_name not in JacMachine.loaded_modules:
311
301
  full_mod_path = path.join(
312
302
  base_path, package_name.replace(".", path.sep)
313
303
  )
@@ -315,36 +305,24 @@ class JacImporter(Importer):
315
305
  module_name=package_name,
316
306
  full_mod_path=full_mod_path,
317
307
  )
318
- JacMachineInterface.load_module(self.jac_machine, module_name, module)
308
+ JacMachineInterface.load_module(module_name, module)
319
309
  return module
320
310
 
321
311
  def run_import(
322
312
  self, spec: ImportPathSpec, reload: Optional[bool] = False
323
313
  ) -> ImportReturn:
324
314
  """Run the import process for Jac modules."""
315
+ from jaclang.runtimelib.machine import JacMachine
316
+
325
317
  unique_loaded_items: list[types.ModuleType] = []
326
318
  module = None
327
319
  # Gather all possible search paths
328
- jacpaths = os.environ.get("JACPATH", "")
329
- search_paths = [spec.caller_dir]
330
- for site_dir in site.getsitepackages():
331
- if site_dir and site_dir not in search_paths:
332
- search_paths.append(site_dir)
333
- user_site = getattr(site, "getusersitepackages", None)
334
- if user_site:
335
- user_dir = site.getusersitepackages()
336
- if user_dir and user_dir not in search_paths:
337
- search_paths.append(user_dir)
338
- if jacpaths:
339
- for p in jacpaths.split(":"):
340
- p = p.strip()
341
- if p and p not in search_paths:
342
- search_paths.append(p)
320
+ search_paths = get_jac_search_paths(spec.caller_dir)
343
321
 
344
322
  found_path = None
345
323
  target_path_components = spec.target.split(".")
346
324
  for search_path in search_paths:
347
- candidate = os.path.join(search_path, "/".join(target_path_components))
325
+ candidate = os.path.join(search_path, *target_path_components)
348
326
  # Check if the candidate is a directory or a .jac file
349
327
  if (os.path.isdir(candidate)) or (os.path.isfile(candidate + ".jac")):
350
328
  found_path = candidate
@@ -367,7 +345,7 @@ class JacImporter(Importer):
367
345
  else:
368
346
  module_name = self.get_sys_mod_name(spec.full_target)
369
347
 
370
- module = self.jac_machine.loaded_modules.get(module_name)
348
+ module = JacMachine.loaded_modules.get(module_name)
371
349
 
372
350
  if not module or module.__name__ == "__main__" or reload:
373
351
  if os.path.isdir(spec.full_target):
@@ -379,10 +357,7 @@ class JacImporter(Importer):
379
357
  spec.package_path,
380
358
  spec.full_target,
381
359
  )
382
- codeobj = self.jac_machine.jac_program.get_bytecode(
383
- full_target=spec.full_target,
384
- full_compile=not self.jac_machine.interp_mode,
385
- )
360
+ codeobj = JacMachine.program.get_bytecode(full_target=spec.full_target)
386
361
 
387
362
  # Since this is a compile time error, we can safely raise an exception here.
388
363
  if not codeobj: