jaclang 0.8.8__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.
- jaclang/cli/cli.py +194 -10
- jaclang/cli/cmdreg.py +144 -8
- jaclang/compiler/__init__.py +6 -1
- jaclang/compiler/codeinfo.py +16 -1
- jaclang/compiler/constant.py +33 -8
- jaclang/compiler/jac.lark +154 -62
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +656 -149
- jaclang/compiler/passes/__init__.py +2 -1
- jaclang/compiler/passes/ast_gen/__init__.py +5 -0
- jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
- jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
- jaclang/compiler/passes/ecmascript/__init__.py +25 -0
- jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
- jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
- jaclang/compiler/passes/ecmascript/estree.py +972 -0
- jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
- jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
- jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
- jaclang/compiler/passes/main/__init__.py +0 -3
- jaclang/compiler/passes/main/annex_pass.py +23 -1
- jaclang/compiler/passes/main/def_use_pass.py +1 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +413 -255
- jaclang/compiler/passes/main/pyast_load_pass.py +48 -11
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
- jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
- jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -3
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +13 -14
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
- jaclang/compiler/passes/main/type_checker_pass.py +7 -0
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +219 -20
- jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +135 -29
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
- jaclang/compiler/passes/transform.py +9 -1
- jaclang/compiler/passes/uni_pass.py +5 -7
- jaclang/compiler/program.py +27 -26
- jaclang/compiler/tests/test_client_codegen.py +113 -0
- jaclang/compiler/tests/test_importer.py +12 -10
- jaclang/compiler/tests/test_parser.py +249 -3
- jaclang/compiler/type_system/type_evaluator.jac +1078 -0
- jaclang/compiler/type_system/type_utils.py +1 -1
- jaclang/compiler/type_system/types.py +6 -0
- jaclang/compiler/unitree.py +438 -82
- jaclang/langserve/engine.jac +224 -288
- jaclang/langserve/sem_manager.jac +12 -8
- jaclang/langserve/server.jac +48 -48
- jaclang/langserve/tests/fixtures/greet.py +17 -0
- jaclang/langserve/tests/fixtures/md_path.jac +22 -0
- jaclang/langserve/tests/fixtures/user.jac +15 -0
- jaclang/langserve/tests/test_server.py +66 -371
- jaclang/lib.py +17 -0
- jaclang/runtimelib/archetype.py +25 -25
- jaclang/runtimelib/client_bundle.py +169 -0
- jaclang/runtimelib/client_runtime.jac +586 -0
- jaclang/runtimelib/constructs.py +4 -2
- jaclang/runtimelib/machine.py +308 -139
- jaclang/runtimelib/meta_importer.py +111 -22
- jaclang/runtimelib/mtp.py +15 -0
- jaclang/runtimelib/server.py +1089 -0
- jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
- jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
- jaclang/runtimelib/tests/test_client_bundle.py +55 -0
- jaclang/runtimelib/tests/test_client_render.py +63 -0
- jaclang/runtimelib/tests/test_serve.py +1069 -0
- jaclang/settings.py +0 -3
- jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
- jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
- jaclang/tests/fixtures/funccall_genexpr.py +5 -0
- jaclang/tests/fixtures/iife_functions.jac +142 -0
- jaclang/tests/fixtures/iife_functions_client.jac +143 -0
- jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
- jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
- jaclang/tests/fixtures/needs_import_dup.jac +6 -4
- jaclang/tests/fixtures/py2jac_empty.py +0 -0
- jaclang/tests/fixtures/py_run.py +7 -5
- jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
- jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
- jaclang/tests/test_cli.py +134 -18
- jaclang/tests/test_language.py +120 -32
- jaclang/tests/test_reference.py +20 -3
- jaclang/utils/NonGPT.py +375 -0
- jaclang/utils/helpers.py +64 -20
- jaclang/utils/lang_tools.py +31 -4
- jaclang/utils/tests/test_lang_tools.py +5 -16
- jaclang/utils/treeprinter.py +8 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/RECORD +106 -71
- jaclang/compiler/passes/main/binder_pass.py +0 -594
- jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
- jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
- jaclang/compiler/type_system/type_evaluator.py +0 -844
- jaclang/langserve/tests/session.jac +0 -294
- jaclang/langserve/tests/test_dev_server.py +0 -80
- jaclang/runtimelib/importer.py +0 -351
- jaclang/tests/test_typecheck.py +0 -542
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
jaclang/runtimelib/archetype.py
CHANGED
|
@@ -69,13 +69,13 @@ class AnchorReport:
|
|
|
69
69
|
context: dict[str, Any]
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
ObjectSpatialFilter: TypeAlias = (
|
|
73
73
|
Callable[["Archetype"], bool] | "Archetype" | list["Archetype"] | None
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
@dataclass(eq=False, repr=False)
|
|
78
|
-
class
|
|
78
|
+
class ObjectSpatialDestination:
|
|
79
79
|
"""Object-Spatial Destination."""
|
|
80
80
|
|
|
81
81
|
direction: EdgeDir
|
|
@@ -92,18 +92,18 @@ class DataSpatialDestination:
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
@dataclass(eq=False, repr=False)
|
|
95
|
-
class
|
|
95
|
+
class ObjectSpatialPath:
|
|
96
96
|
"""Object-Spatial Path."""
|
|
97
97
|
|
|
98
98
|
origin: list[NodeArchetype]
|
|
99
|
-
destinations: list[
|
|
99
|
+
destinations: list[ObjectSpatialDestination]
|
|
100
100
|
edge_only: bool
|
|
101
101
|
from_visit: bool
|
|
102
102
|
|
|
103
103
|
def __init__(
|
|
104
104
|
self,
|
|
105
105
|
origin: NodeArchetype | list[NodeArchetype],
|
|
106
|
-
destinations: list[
|
|
106
|
+
destinations: list[ObjectSpatialDestination] | None = None,
|
|
107
107
|
) -> None:
|
|
108
108
|
"""Override Init."""
|
|
109
109
|
if not isinstance(origin, list):
|
|
@@ -115,7 +115,7 @@ class DataSpatialPath:
|
|
|
115
115
|
|
|
116
116
|
def convert(
|
|
117
117
|
self,
|
|
118
|
-
filter:
|
|
118
|
+
filter: ObjectSpatialFilter,
|
|
119
119
|
) -> Callable[["Archetype"], bool] | None:
|
|
120
120
|
"""Convert filter."""
|
|
121
121
|
if not filter:
|
|
@@ -129,44 +129,44 @@ class DataSpatialPath:
|
|
|
129
129
|
def append(
|
|
130
130
|
self,
|
|
131
131
|
direction: EdgeDir,
|
|
132
|
-
edge:
|
|
133
|
-
node:
|
|
134
|
-
) ->
|
|
132
|
+
edge: ObjectSpatialFilter,
|
|
133
|
+
node: ObjectSpatialFilter,
|
|
134
|
+
) -> ObjectSpatialPath:
|
|
135
135
|
"""Append destination."""
|
|
136
136
|
self.destinations.append(
|
|
137
|
-
|
|
137
|
+
ObjectSpatialDestination(direction, self.convert(edge), self.convert(node))
|
|
138
138
|
)
|
|
139
139
|
return self
|
|
140
140
|
|
|
141
|
-
def
|
|
142
|
-
self, edge:
|
|
143
|
-
) ->
|
|
141
|
+
def edge_out(
|
|
142
|
+
self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
|
|
143
|
+
) -> ObjectSpatialPath:
|
|
144
144
|
"""Override greater than function."""
|
|
145
145
|
return self.append(EdgeDir.OUT, edge, node)
|
|
146
146
|
|
|
147
|
-
def
|
|
148
|
-
self, edge:
|
|
149
|
-
) ->
|
|
147
|
+
def edge_in(
|
|
148
|
+
self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
|
|
149
|
+
) -> ObjectSpatialPath:
|
|
150
150
|
"""Override greater than function."""
|
|
151
151
|
return self.append(EdgeDir.IN, edge, node)
|
|
152
152
|
|
|
153
|
-
def
|
|
154
|
-
self, edge:
|
|
155
|
-
) ->
|
|
153
|
+
def edge_any(
|
|
154
|
+
self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
|
|
155
|
+
) -> ObjectSpatialPath:
|
|
156
156
|
"""Override greater than function."""
|
|
157
157
|
return self.append(EdgeDir.ANY, edge, node)
|
|
158
158
|
|
|
159
|
-
def edge(self) ->
|
|
159
|
+
def edge(self) -> ObjectSpatialPath:
|
|
160
160
|
"""Set edge only."""
|
|
161
161
|
self.edge_only = True
|
|
162
162
|
return self
|
|
163
163
|
|
|
164
|
-
def visit(self) ->
|
|
164
|
+
def visit(self) -> ObjectSpatialPath:
|
|
165
165
|
"""Set from visit."""
|
|
166
166
|
self.from_visit = True
|
|
167
167
|
return self
|
|
168
168
|
|
|
169
|
-
def repr_builder(self, repr: str, dest:
|
|
169
|
+
def repr_builder(self, repr: str, dest: ObjectSpatialDestination, mark: str) -> str:
|
|
170
170
|
"""Repr builder."""
|
|
171
171
|
repr += mark
|
|
172
172
|
repr += f' (edge{" filter" if dest.edge else ""}) '
|
|
@@ -361,8 +361,8 @@ class ObjectAnchor(Anchor):
|
|
|
361
361
|
class Archetype:
|
|
362
362
|
"""Archetype Protocol."""
|
|
363
363
|
|
|
364
|
-
_jac_entry_funcs_: ClassVar[list[
|
|
365
|
-
_jac_exit_funcs_: ClassVar[list[
|
|
364
|
+
_jac_entry_funcs_: ClassVar[list[ObjectSpatialFunction]] = []
|
|
365
|
+
_jac_exit_funcs_: ClassVar[list[ObjectSpatialFunction]] = []
|
|
366
366
|
|
|
367
367
|
@cached_property
|
|
368
368
|
def __jac__(self) -> Anchor:
|
|
@@ -454,7 +454,7 @@ class Root(NodeArchetype):
|
|
|
454
454
|
|
|
455
455
|
|
|
456
456
|
@dataclass(eq=False)
|
|
457
|
-
class
|
|
457
|
+
class ObjectSpatialFunction:
|
|
458
458
|
"""Object-Spatial Function."""
|
|
459
459
|
|
|
460
460
|
name: str
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Client bundle generation utilities for Jac web front-ends."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
from typing import Any, Iterable, Sequence
|
|
11
|
+
|
|
12
|
+
from jaclang.compiler.program import JacProgram
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ClientBundleError(RuntimeError):
|
|
16
|
+
"""Raised when the client bundle cannot be generated."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(slots=True)
|
|
20
|
+
class ClientBundle:
|
|
21
|
+
"""Container for a compiled client bundle."""
|
|
22
|
+
|
|
23
|
+
module_name: str
|
|
24
|
+
code: str
|
|
25
|
+
client_functions: list[str]
|
|
26
|
+
client_globals: list[str]
|
|
27
|
+
hash: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(slots=True)
|
|
31
|
+
class _CachedBundle:
|
|
32
|
+
signature: str
|
|
33
|
+
bundle: ClientBundle
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ClientBundleBuilder:
|
|
37
|
+
"""Compile Jac modules and runtime support into a browser-ready bundle."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, runtime_path: Path | None = None) -> None:
|
|
40
|
+
"""Initialise the builder with an optional override for the runtime path."""
|
|
41
|
+
self.runtime_path = runtime_path or Path(__file__).with_name(
|
|
42
|
+
"client_runtime.jac"
|
|
43
|
+
)
|
|
44
|
+
self._cache: dict[str, _CachedBundle] = {}
|
|
45
|
+
|
|
46
|
+
def build(self, module: ModuleType, force: bool = False) -> ClientBundle:
|
|
47
|
+
"""Build (or reuse) a client bundle for the supplied module."""
|
|
48
|
+
# Derive source path from module __file__ (replace .py with .jac)
|
|
49
|
+
if not hasattr(module, "__file__") or not module.__file__:
|
|
50
|
+
raise ClientBundleError(
|
|
51
|
+
f"Module '{module.__name__}' has no __file__ attribute"
|
|
52
|
+
)
|
|
53
|
+
module_path = module.__file__.replace(".py", ".jac")
|
|
54
|
+
|
|
55
|
+
source_path = Path(module_path).resolve()
|
|
56
|
+
runtime_path = self.runtime_path.resolve()
|
|
57
|
+
signature = self._signature([source_path, runtime_path])
|
|
58
|
+
|
|
59
|
+
cached = self._cache.get(module.__name__)
|
|
60
|
+
if not force and cached and cached.signature == signature:
|
|
61
|
+
return cached.bundle
|
|
62
|
+
|
|
63
|
+
bundle = self._compile_bundle(module, source_path, runtime_path)
|
|
64
|
+
self._cache[module.__name__] = _CachedBundle(signature=signature, bundle=bundle)
|
|
65
|
+
return bundle
|
|
66
|
+
|
|
67
|
+
def _compile_bundle(
|
|
68
|
+
self,
|
|
69
|
+
module: ModuleType,
|
|
70
|
+
module_path: Path,
|
|
71
|
+
runtime_path: Path,
|
|
72
|
+
) -> ClientBundle:
|
|
73
|
+
"""Compile bundle pieces and stitch them together."""
|
|
74
|
+
runtime_js = self._compile_to_js(runtime_path)
|
|
75
|
+
|
|
76
|
+
# Get manifest from JacProgram
|
|
77
|
+
from jaclang.runtimelib.machine import JacMachine as Jac
|
|
78
|
+
|
|
79
|
+
mod = Jac.program.mod.hub.get(str(module_path))
|
|
80
|
+
manifest = mod.gen.client_manifest if mod else None
|
|
81
|
+
|
|
82
|
+
module_js = self._compile_to_js(module_path)
|
|
83
|
+
|
|
84
|
+
client_exports = sorted(dict.fromkeys(manifest.exports)) if manifest else []
|
|
85
|
+
|
|
86
|
+
client_globals_map: dict[str, Any] = {}
|
|
87
|
+
if manifest:
|
|
88
|
+
for name in manifest.globals:
|
|
89
|
+
if name in manifest.globals_values:
|
|
90
|
+
client_globals_map[name] = manifest.globals_values[name]
|
|
91
|
+
elif hasattr(module, name):
|
|
92
|
+
client_globals_map[name] = getattr(module, name)
|
|
93
|
+
else:
|
|
94
|
+
client_globals_map[name] = None
|
|
95
|
+
client_globals_map = {
|
|
96
|
+
key: client_globals_map[key] for key in sorted(client_globals_map)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
registration_js = self._generate_registration_js(
|
|
100
|
+
module.__name__, client_exports, client_globals_map
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
bundle_pieces = [
|
|
104
|
+
"// Jac client runtime",
|
|
105
|
+
runtime_js,
|
|
106
|
+
"",
|
|
107
|
+
f"// Client module: {module.__name__}",
|
|
108
|
+
module_js,
|
|
109
|
+
"",
|
|
110
|
+
registration_js,
|
|
111
|
+
]
|
|
112
|
+
bundle_code = "\n".join(piece for piece in bundle_pieces if piece is not None)
|
|
113
|
+
bundle_hash = hashlib.sha256(bundle_code.encode("utf-8")).hexdigest()
|
|
114
|
+
|
|
115
|
+
return ClientBundle(
|
|
116
|
+
module_name=module.__name__,
|
|
117
|
+
code=bundle_code,
|
|
118
|
+
client_functions=client_exports,
|
|
119
|
+
client_globals=list(client_globals_map.keys()),
|
|
120
|
+
hash=bundle_hash,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def _compile_to_js(self, source_path: Path) -> str:
|
|
124
|
+
"""Compile the provided Jac file into JavaScript."""
|
|
125
|
+
program = JacProgram()
|
|
126
|
+
mod = program.compile(str(source_path))
|
|
127
|
+
if program.errors_had:
|
|
128
|
+
formatted = "\n".join(str(err) for err in program.errors_had)
|
|
129
|
+
raise ClientBundleError(
|
|
130
|
+
f"Failed to compile '{source_path}' for client bundle:\n{formatted}"
|
|
131
|
+
)
|
|
132
|
+
return mod.gen.js or ""
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def _signature(paths: Iterable[Path]) -> str:
|
|
136
|
+
"""Compute a cache signature based on file modification times."""
|
|
137
|
+
parts: list[str] = []
|
|
138
|
+
for path in paths:
|
|
139
|
+
try:
|
|
140
|
+
stat = path.stat()
|
|
141
|
+
parts.append(f"{path}:{stat.st_mtime_ns}")
|
|
142
|
+
except FileNotFoundError:
|
|
143
|
+
parts.append(f"{path}:missing")
|
|
144
|
+
return hashlib.sha256("|".join(parts).encode("utf-8")).hexdigest()
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _generate_registration_js(
|
|
148
|
+
module_name: str,
|
|
149
|
+
client_functions: Sequence[str],
|
|
150
|
+
client_globals: dict[str, Any],
|
|
151
|
+
) -> str:
|
|
152
|
+
"""Generate registration code that exposes client symbols globally."""
|
|
153
|
+
globals_entries: list[str] = []
|
|
154
|
+
for name, value in client_globals.items():
|
|
155
|
+
identifier = json.dumps(name)
|
|
156
|
+
try:
|
|
157
|
+
value_literal = json.dumps(value)
|
|
158
|
+
except TypeError:
|
|
159
|
+
value_literal = "null"
|
|
160
|
+
globals_entries.append(f"{identifier}: {value_literal}")
|
|
161
|
+
|
|
162
|
+
globals_literal = (
|
|
163
|
+
"{ " + ", ".join(globals_entries) + " }" if globals_entries else "{}"
|
|
164
|
+
)
|
|
165
|
+
functions_literal = json.dumps(list(client_functions))
|
|
166
|
+
module_literal = json.dumps(module_name)
|
|
167
|
+
|
|
168
|
+
# Use the registration function from client_runtime.jac
|
|
169
|
+
return f"__jacRegisterClientModule({module_literal}, {functions_literal}, {globals_literal});"
|