jaclang 0.8.1__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 +21 -50
- jaclang/compiler/codeinfo.py +0 -1
- jaclang/compiler/jac.lark +12 -10
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +18 -10
- 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 +38 -12
- jaclang/compiler/passes/main/import_pass.py +3 -11
- jaclang/compiler/passes/main/pyast_gen_pass.py +243 -592
- jaclang/compiler/passes/main/sym_tab_link_pass.py +2 -5
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +2 -8
- 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 +237 -105
- 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 +21 -60
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +2 -8
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +1 -5
- jaclang/compiler/tests/test_importer.py +10 -13
- jaclang/compiler/unitree.py +32 -16
- jaclang/langserve/__init__.jac +1 -1
- jaclang/langserve/engine.jac +113 -108
- jaclang/langserve/server.jac +17 -2
- jaclang/langserve/tests/server_test/test_lang_serve.py +138 -46
- jaclang/langserve/tests/server_test/utils.py +35 -9
- jaclang/langserve/tests/test_sem_tokens.py +1 -1
- jaclang/langserve/tests/test_server.py +3 -7
- jaclang/runtimelib/archetype.py +127 -5
- jaclang/runtimelib/importer.py +51 -94
- jaclang/runtimelib/machine.py +391 -268
- 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/test_jaseci.py +3 -1
- 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/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/foo.jac +14 -22
- 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/unicode_strings.jac +24 -0
- jaclang/tests/fixtures/walker_update.jac +5 -7
- jaclang/tests/test_language.py +138 -140
- jaclang/tests/test_reference.py +9 -4
- jaclang/tests/test_typecheck.py +13 -26
- jaclang/utils/lang_tools.py +7 -5
- jaclang/utils/module_resolver.py +23 -0
- {jaclang-0.8.1.dist-info → jaclang-0.8.2.dist-info}/METADATA +1 -1
- {jaclang-0.8.1.dist-info → jaclang-0.8.2.dist-info}/RECORD +72 -70
- 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/tests/fixtures/deep/deeper/__init__.jac +0 -1
- {jaclang-0.8.1.dist-info → jaclang-0.8.2.dist-info}/WHEEL +0 -0
- {jaclang-0.8.1.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,49 +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
|
-
found = False
|
|
106
|
-
if lang == "jac":
|
|
107
|
-
jac_file_path = (
|
|
108
|
-
os.path.join(module.__path__[0], f"{name}.jac")
|
|
109
|
-
if hasattr(module, "__path__")
|
|
110
|
-
else module.__file__
|
|
111
|
-
)
|
|
112
|
-
if hasattr(module, "__path__"):
|
|
113
|
-
init_jac = os.path.join(module.__path__[0], "__init__.jac")
|
|
114
|
-
if os.path.isfile(init_jac):
|
|
115
|
-
package_name = module.__name__
|
|
116
|
-
init_mod = self.importer.jac_machine.loaded_modules.get(
|
|
117
|
-
package_name,
|
|
118
|
-
self.load_jac_mod_as_item(
|
|
119
|
-
module=module,
|
|
120
|
-
name="__init__",
|
|
121
|
-
jac_file_path=init_jac,
|
|
122
|
-
),
|
|
123
|
-
)
|
|
124
|
-
# Attach all public names from __init__.jac to the package module
|
|
125
|
-
for k, v in init_mod.__dict__.items():
|
|
126
|
-
if not k.startswith("_"):
|
|
127
|
-
setattr(module, k, v)
|
|
128
|
-
if hasattr(module, name):
|
|
129
|
-
item = getattr(module, name)
|
|
130
|
-
handle_item_loading(item, alias)
|
|
131
|
-
found = True
|
|
132
|
-
if not found and jac_file_path and os.path.isfile(jac_file_path):
|
|
133
|
-
item = self.load_jac_mod_as_item(
|
|
134
|
-
module=module,
|
|
135
|
-
name=name,
|
|
136
|
-
jac_file_path=jac_file_path,
|
|
137
|
-
)
|
|
138
|
-
handle_item_loading(item, alias)
|
|
139
|
-
else:
|
|
140
|
-
if hasattr(module, "__path__"):
|
|
141
|
-
full_module_name = f"{module.__name__}.{name}"
|
|
142
|
-
item = importlib.import_module(full_module_name)
|
|
143
|
-
handle_item_loading(item, alias)
|
|
98
|
+
item = getattr(module, name)
|
|
99
|
+
handle_item_loading(item, alias)
|
|
144
100
|
|
|
145
101
|
def load_jac_mod_as_item(
|
|
146
102
|
self,
|
|
@@ -149,6 +105,8 @@ class ImportReturn:
|
|
|
149
105
|
jac_file_path: str,
|
|
150
106
|
) -> Optional[types.ModuleType]:
|
|
151
107
|
"""Load a single .jac file into the specified module component."""
|
|
108
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
109
|
+
|
|
152
110
|
try:
|
|
153
111
|
package_name = (
|
|
154
112
|
f"{module.__name__}.{name}"
|
|
@@ -156,7 +114,7 @@ class ImportReturn:
|
|
|
156
114
|
else module.__name__
|
|
157
115
|
)
|
|
158
116
|
if isinstance(self.importer, JacImporter):
|
|
159
|
-
new_module =
|
|
117
|
+
new_module = JacMachine.loaded_modules.get(
|
|
160
118
|
package_name,
|
|
161
119
|
self.importer.create_jac_py_module(
|
|
162
120
|
self.importer.get_sys_mod_name(jac_file_path),
|
|
@@ -164,9 +122,7 @@ class ImportReturn:
|
|
|
164
122
|
jac_file_path,
|
|
165
123
|
),
|
|
166
124
|
)
|
|
167
|
-
codeobj =
|
|
168
|
-
full_target=jac_file_path
|
|
169
|
-
)
|
|
125
|
+
codeobj = JacMachine.program.get_bytecode(full_target=jac_file_path)
|
|
170
126
|
if not codeobj:
|
|
171
127
|
raise ImportError(f"No bytecode found for {jac_file_path}")
|
|
172
128
|
|
|
@@ -180,28 +136,18 @@ class ImportReturn:
|
|
|
180
136
|
class Importer:
|
|
181
137
|
"""Abstract base class for all importers."""
|
|
182
138
|
|
|
183
|
-
def __init__(self
|
|
139
|
+
def __init__(self) -> None:
|
|
184
140
|
"""Initialize the Importer object."""
|
|
185
|
-
self.jac_machine = jac_machine
|
|
186
141
|
self.result: Optional[ImportReturn] = None
|
|
187
142
|
|
|
188
143
|
def run_import(self, spec: ImportPathSpec) -> ImportReturn:
|
|
189
144
|
"""Run the import process."""
|
|
190
145
|
raise NotImplementedError
|
|
191
146
|
|
|
192
|
-
def update_sys(self, module: types.ModuleType, spec: ImportPathSpec) -> None:
|
|
193
|
-
"""Update sys.modules with the newly imported module."""
|
|
194
|
-
if spec.module_name not in self.jac_machine.loaded_modules:
|
|
195
|
-
JacMachineInterface.load_module(self.jac_machine, spec.module_name, module)
|
|
196
|
-
|
|
197
147
|
|
|
198
148
|
class PythonImporter(Importer):
|
|
199
149
|
"""Importer for Python modules."""
|
|
200
150
|
|
|
201
|
-
def __init__(self, jac_machine: JacMachine) -> None:
|
|
202
|
-
"""Initialize the PythonImporter object."""
|
|
203
|
-
self.jac_machine = jac_machine
|
|
204
|
-
|
|
205
151
|
def run_import(self, spec: ImportPathSpec) -> ImportReturn:
|
|
206
152
|
"""Run the import process for Python modules."""
|
|
207
153
|
try:
|
|
@@ -273,12 +219,10 @@ class PythonImporter(Importer):
|
|
|
273
219
|
class JacImporter(Importer):
|
|
274
220
|
"""Importer for Jac modules."""
|
|
275
221
|
|
|
276
|
-
def __init__(self, jac_machine: JacMachine) -> None:
|
|
277
|
-
"""Initialize the JacImporter object."""
|
|
278
|
-
self.jac_machine = jac_machine
|
|
279
|
-
|
|
280
222
|
def get_sys_mod_name(self, full_target: str) -> str:
|
|
281
223
|
"""Generate proper module names from file paths."""
|
|
224
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
225
|
+
|
|
282
226
|
full_target = os.path.abspath(full_target)
|
|
283
227
|
|
|
284
228
|
# If the file is located within a site-packages directory, strip that prefix.
|
|
@@ -288,7 +232,7 @@ class JacImporter(Importer):
|
|
|
288
232
|
rel = full_target[sp_index + len("site-packages") :]
|
|
289
233
|
rel = rel.lstrip(os.sep)
|
|
290
234
|
else:
|
|
291
|
-
rel = path.relpath(full_target, start=
|
|
235
|
+
rel = path.relpath(full_target, start=JacMachine.base_path_dir)
|
|
292
236
|
rel = os.path.splitext(rel)[0]
|
|
293
237
|
if os.path.basename(rel) == "__init__":
|
|
294
238
|
rel = os.path.dirname(rel)
|
|
@@ -304,10 +248,36 @@ class JacImporter(Importer):
|
|
|
304
248
|
module.__name__ = module_name
|
|
305
249
|
module.__path__ = [full_mod_path]
|
|
306
250
|
module.__file__ = None
|
|
307
|
-
module.__dict__["__jac_mach__"] = self.jac_machine
|
|
308
251
|
|
|
309
|
-
|
|
310
|
-
|
|
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
|
+
|
|
311
281
|
return module
|
|
312
282
|
|
|
313
283
|
def create_jac_py_module(
|
|
@@ -317,16 +287,17 @@ class JacImporter(Importer):
|
|
|
317
287
|
full_target: str,
|
|
318
288
|
) -> types.ModuleType:
|
|
319
289
|
"""Create a module."""
|
|
290
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
291
|
+
|
|
320
292
|
module = types.ModuleType(module_name)
|
|
321
293
|
module.__file__ = full_target
|
|
322
294
|
module.__name__ = module_name
|
|
323
|
-
module.__dict__["__jac_mach__"] = self.jac_machine
|
|
324
295
|
if package_path:
|
|
325
296
|
base_path = full_target.split(package_path.replace(".", path.sep))[0]
|
|
326
297
|
parts = package_path.split(".")
|
|
327
298
|
for i in range(len(parts)):
|
|
328
299
|
package_name = ".".join(parts[: i + 1])
|
|
329
|
-
if package_name not in
|
|
300
|
+
if package_name not in JacMachine.loaded_modules:
|
|
330
301
|
full_mod_path = path.join(
|
|
331
302
|
base_path, package_name.replace(".", path.sep)
|
|
332
303
|
)
|
|
@@ -334,36 +305,24 @@ class JacImporter(Importer):
|
|
|
334
305
|
module_name=package_name,
|
|
335
306
|
full_mod_path=full_mod_path,
|
|
336
307
|
)
|
|
337
|
-
JacMachineInterface.load_module(
|
|
308
|
+
JacMachineInterface.load_module(module_name, module)
|
|
338
309
|
return module
|
|
339
310
|
|
|
340
311
|
def run_import(
|
|
341
312
|
self, spec: ImportPathSpec, reload: Optional[bool] = False
|
|
342
313
|
) -> ImportReturn:
|
|
343
314
|
"""Run the import process for Jac modules."""
|
|
315
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
316
|
+
|
|
344
317
|
unique_loaded_items: list[types.ModuleType] = []
|
|
345
318
|
module = None
|
|
346
319
|
# Gather all possible search paths
|
|
347
|
-
|
|
348
|
-
search_paths = [spec.caller_dir]
|
|
349
|
-
for site_dir in site.getsitepackages():
|
|
350
|
-
if site_dir and site_dir not in search_paths:
|
|
351
|
-
search_paths.append(site_dir)
|
|
352
|
-
user_site = getattr(site, "getusersitepackages", None)
|
|
353
|
-
if user_site:
|
|
354
|
-
user_dir = site.getusersitepackages()
|
|
355
|
-
if user_dir and user_dir not in search_paths:
|
|
356
|
-
search_paths.append(user_dir)
|
|
357
|
-
if jacpaths:
|
|
358
|
-
for p in jacpaths.split(":"):
|
|
359
|
-
p = p.strip()
|
|
360
|
-
if p and p not in search_paths:
|
|
361
|
-
search_paths.append(p)
|
|
320
|
+
search_paths = get_jac_search_paths(spec.caller_dir)
|
|
362
321
|
|
|
363
322
|
found_path = None
|
|
364
323
|
target_path_components = spec.target.split(".")
|
|
365
324
|
for search_path in search_paths:
|
|
366
|
-
candidate = os.path.join(search_path,
|
|
325
|
+
candidate = os.path.join(search_path, *target_path_components)
|
|
367
326
|
# Check if the candidate is a directory or a .jac file
|
|
368
327
|
if (os.path.isdir(candidate)) or (os.path.isfile(candidate + ".jac")):
|
|
369
328
|
found_path = candidate
|
|
@@ -386,7 +345,7 @@ class JacImporter(Importer):
|
|
|
386
345
|
else:
|
|
387
346
|
module_name = self.get_sys_mod_name(spec.full_target)
|
|
388
347
|
|
|
389
|
-
module =
|
|
348
|
+
module = JacMachine.loaded_modules.get(module_name)
|
|
390
349
|
|
|
391
350
|
if not module or module.__name__ == "__main__" or reload:
|
|
392
351
|
if os.path.isdir(spec.full_target):
|
|
@@ -398,9 +357,7 @@ class JacImporter(Importer):
|
|
|
398
357
|
spec.package_path,
|
|
399
358
|
spec.full_target,
|
|
400
359
|
)
|
|
401
|
-
codeobj =
|
|
402
|
-
full_target=spec.full_target
|
|
403
|
-
)
|
|
360
|
+
codeobj = JacMachine.program.get_bytecode(full_target=spec.full_target)
|
|
404
361
|
|
|
405
362
|
# Since this is a compile time error, we can safely raise an exception here.
|
|
406
363
|
if not codeobj:
|