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.
- jaclang/cli/cli.py +147 -25
- jaclang/cli/cmdreg.py +144 -8
- jaclang/compiler/__init__.py +6 -1
- jaclang/compiler/codeinfo.py +16 -1
- jaclang/compiler/constant.py +33 -13
- jaclang/compiler/jac.lark +130 -31
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +567 -176
- 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/pyast_gen_pass.py +324 -234
- jaclang/compiler/passes/main/pyast_load_pass.py +46 -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 -2
- 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_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 +115 -0
- jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
- 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 +22 -25
- 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 +169 -50
- jaclang/compiler/type_system/type_utils.py +1 -1
- jaclang/compiler/type_system/types.py +6 -0
- jaclang/compiler/unitree.py +430 -84
- 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 +1 -1
- jaclang/runtimelib/client_bundle.py +169 -0
- jaclang/runtimelib/client_runtime.jac +586 -0
- jaclang/runtimelib/constructs.py +2 -0
- jaclang/runtimelib/machine.py +259 -100
- 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 -2
- 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/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 +1 -1
- jaclang/tests/test_language.py +10 -39
- jaclang/tests/test_reference.py +17 -2
- jaclang/utils/NonGPT.py +375 -0
- jaclang/utils/helpers.py +44 -16
- jaclang/utils/lang_tools.py +31 -4
- jaclang/utils/tests/test_lang_tools.py +1 -1
- jaclang/utils/treeprinter.py +8 -3
- {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
- {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/RECORD +96 -66
- 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/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.9.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
- {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
|
@@ -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});"
|