jaclang 0.8.0__py3-none-any.whl → 0.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/__init__.py +6 -0
- jaclang/cli/cli.py +23 -50
- jaclang/compiler/codeinfo.py +0 -1
- jaclang/compiler/jac.lark +14 -22
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +378 -531
- jaclang/compiler/passes/main/__init__.py +0 -14
- jaclang/compiler/passes/main/annex_pass.py +2 -8
- jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
- jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
- jaclang/compiler/passes/main/def_use_pass.py +4 -7
- jaclang/compiler/passes/main/import_pass.py +6 -14
- jaclang/compiler/passes/main/inheritance_pass.py +2 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
- jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
- jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
- jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
- jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
- jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
- jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
- jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
- jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
- jaclang/compiler/program.py +22 -66
- jaclang/compiler/tests/fixtures/fam.jac +2 -2
- jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
- jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
- jaclang/compiler/tests/test_importer.py +30 -13
- jaclang/compiler/tests/test_parser.py +1 -0
- jaclang/compiler/unitree.py +488 -320
- jaclang/langserve/__init__.jac +1 -0
- jaclang/langserve/engine.jac +503 -0
- jaclang/langserve/sem_manager.jac +309 -0
- jaclang/langserve/server.jac +201 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
- jaclang/langserve/tests/server_test/utils.py +35 -6
- jaclang/langserve/tests/session.jac +294 -0
- jaclang/langserve/tests/test_sem_tokens.py +2 -2
- jaclang/langserve/tests/test_server.py +8 -7
- jaclang/langserve/utils.jac +51 -30
- jaclang/runtimelib/archetype.py +128 -6
- jaclang/runtimelib/builtin.py +17 -14
- jaclang/runtimelib/importer.py +51 -76
- jaclang/runtimelib/machine.py +469 -305
- jaclang/runtimelib/meta_importer.py +86 -0
- jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
- jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
- jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
- jaclang/runtimelib/tests/test_jaseci.py +3 -1
- jaclang/runtimelib/utils.py +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
- jaclang/tests/fixtures/async_ability.jac +43 -10
- jaclang/tests/fixtures/async_function.jac +18 -0
- jaclang/tests/fixtures/async_walker.jac +17 -12
- jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
- jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
- jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
- jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
- jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
- jaclang/tests/fixtures/concurrency.jac +1 -1
- jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
- jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
- jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
- jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +2 -2
- jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
- jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
- jaclang/tests/fixtures/edge_ability.jac +49 -0
- jaclang/tests/fixtures/foo.jac +14 -22
- jaclang/tests/fixtures/guess_game.jac +1 -1
- jaclang/tests/fixtures/here_usage_error.jac +21 -0
- jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
- jaclang/tests/fixtures/jac_from_py.py +1 -1
- jaclang/tests/fixtures/jp_importer.jac +6 -6
- jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
- jaclang/tests/fixtures/node_del.jac +30 -36
- jaclang/tests/fixtures/unicode_strings.jac +24 -0
- jaclang/tests/fixtures/visit_traversal.jac +47 -0
- jaclang/tests/fixtures/walker_update.jac +5 -7
- jaclang/tests/test_cli.py +12 -7
- jaclang/tests/test_language.py +218 -145
- jaclang/tests/test_reference.py +9 -4
- jaclang/tests/test_typecheck.py +13 -26
- jaclang/utils/helpers.py +14 -6
- jaclang/utils/lang_tools.py +9 -8
- jaclang/utils/module_resolver.py +23 -0
- jaclang/utils/tests/test_lang_tools.py +2 -1
- jaclang/utils/treeprinter.py +3 -4
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
- jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
- jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
- jaclang/langserve/__init__.py +0 -1
- jaclang/langserve/engine.py +0 -553
- jaclang/langserve/sem_manager.py +0 -383
- jaclang/langserve/server.py +0 -167
- jaclang/langserve/tests/session.py +0 -255
- jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
- jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
- jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
jaclang/runtimelib/importer.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
102
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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=
|
|
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
|
-
|
|
291
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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 =
|
|
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:
|