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.

Files changed (103) hide show
  1. jaclang/cli/cli.py +147 -25
  2. jaclang/cli/cmdreg.py +144 -8
  3. jaclang/compiler/__init__.py +6 -1
  4. jaclang/compiler/codeinfo.py +16 -1
  5. jaclang/compiler/constant.py +33 -13
  6. jaclang/compiler/jac.lark +130 -31
  7. jaclang/compiler/larkparse/jac_parser.py +2 -2
  8. jaclang/compiler/parser.py +567 -176
  9. jaclang/compiler/passes/__init__.py +2 -1
  10. jaclang/compiler/passes/ast_gen/__init__.py +5 -0
  11. jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
  12. jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
  13. jaclang/compiler/passes/ecmascript/__init__.py +25 -0
  14. jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
  15. jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
  16. jaclang/compiler/passes/ecmascript/estree.py +972 -0
  17. jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
  18. jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
  19. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
  20. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
  21. jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
  22. jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
  23. jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
  24. jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
  25. jaclang/compiler/passes/main/__init__.py +0 -3
  26. jaclang/compiler/passes/main/annex_pass.py +23 -1
  27. jaclang/compiler/passes/main/pyast_gen_pass.py +324 -234
  28. jaclang/compiler/passes/main/pyast_load_pass.py +46 -11
  29. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
  30. jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
  31. jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
  32. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
  33. jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
  34. jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
  35. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
  36. jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -2
  37. jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
  38. jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
  39. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
  40. jaclang/compiler/passes/main/type_checker_pass.py +7 -0
  41. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +115 -0
  42. jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
  43. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
  44. jaclang/compiler/passes/transform.py +9 -1
  45. jaclang/compiler/passes/uni_pass.py +5 -7
  46. jaclang/compiler/program.py +22 -25
  47. jaclang/compiler/tests/test_client_codegen.py +113 -0
  48. jaclang/compiler/tests/test_importer.py +12 -10
  49. jaclang/compiler/tests/test_parser.py +249 -3
  50. jaclang/compiler/type_system/type_evaluator.jac +169 -50
  51. jaclang/compiler/type_system/type_utils.py +1 -1
  52. jaclang/compiler/type_system/types.py +6 -0
  53. jaclang/compiler/unitree.py +430 -84
  54. jaclang/langserve/engine.jac +224 -288
  55. jaclang/langserve/sem_manager.jac +12 -8
  56. jaclang/langserve/server.jac +48 -48
  57. jaclang/langserve/tests/fixtures/greet.py +17 -0
  58. jaclang/langserve/tests/fixtures/md_path.jac +22 -0
  59. jaclang/langserve/tests/fixtures/user.jac +15 -0
  60. jaclang/langserve/tests/test_server.py +66 -371
  61. jaclang/lib.py +1 -1
  62. jaclang/runtimelib/client_bundle.py +169 -0
  63. jaclang/runtimelib/client_runtime.jac +586 -0
  64. jaclang/runtimelib/constructs.py +2 -0
  65. jaclang/runtimelib/machine.py +259 -100
  66. jaclang/runtimelib/meta_importer.py +111 -22
  67. jaclang/runtimelib/mtp.py +15 -0
  68. jaclang/runtimelib/server.py +1089 -0
  69. jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
  70. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  71. jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
  72. jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
  73. jaclang/runtimelib/tests/test_client_bundle.py +55 -0
  74. jaclang/runtimelib/tests/test_client_render.py +63 -0
  75. jaclang/runtimelib/tests/test_serve.py +1069 -0
  76. jaclang/settings.py +0 -2
  77. jaclang/tests/fixtures/iife_functions.jac +142 -0
  78. jaclang/tests/fixtures/iife_functions_client.jac +143 -0
  79. jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
  80. jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
  81. jaclang/tests/fixtures/needs_import_dup.jac +6 -4
  82. jaclang/tests/fixtures/py_run.py +7 -5
  83. jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
  84. jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
  85. jaclang/tests/test_cli.py +1 -1
  86. jaclang/tests/test_language.py +10 -39
  87. jaclang/tests/test_reference.py +17 -2
  88. jaclang/utils/NonGPT.py +375 -0
  89. jaclang/utils/helpers.py +44 -16
  90. jaclang/utils/lang_tools.py +31 -4
  91. jaclang/utils/tests/test_lang_tools.py +1 -1
  92. jaclang/utils/treeprinter.py +8 -3
  93. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
  94. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/RECORD +96 -66
  95. jaclang/compiler/passes/main/binder_pass.py +0 -594
  96. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
  97. jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
  98. jaclang/langserve/tests/session.jac +0 -294
  99. jaclang/langserve/tests/test_dev_server.py +0 -80
  100. jaclang/runtimelib/importer.py +0 -351
  101. jaclang/tests/test_typecheck.py +0 -542
  102. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
  103. {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});"