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,54 @@
|
|
|
1
|
+
"""Shared helpers for AST generation passes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Generic, Optional, Sequence, TypeVar
|
|
6
|
+
|
|
7
|
+
import jaclang.compiler.unitree as uni
|
|
8
|
+
from jaclang.compiler.passes.uni_pass import UniPass
|
|
9
|
+
|
|
10
|
+
T = TypeVar("T")
|
|
11
|
+
ChildPassT = TypeVar("ChildPassT", bound="BaseAstGenPass[Any]")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseAstGenPass(UniPass, Generic[T]):
|
|
15
|
+
"""Common functionality shared across AST generation passes."""
|
|
16
|
+
|
|
17
|
+
def _get_body_inner(
|
|
18
|
+
self, node: uni.Archetype | uni.Enum | uni.Ability
|
|
19
|
+
) -> Optional[Sequence[uni.UniNode]]:
|
|
20
|
+
"""Return the list of body statements regardless of ImplDef wrapping."""
|
|
21
|
+
body = getattr(node, "body", None)
|
|
22
|
+
if isinstance(body, uni.ImplDef) and isinstance(body.body, list):
|
|
23
|
+
return body.body
|
|
24
|
+
if isinstance(body, list):
|
|
25
|
+
return body
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
def _merge_module_bodies(self, node: uni.Module) -> list[uni.UniNode]:
|
|
29
|
+
"""Concatenate impl/test bodies with the main module body."""
|
|
30
|
+
clean_body = [item for item in node.body if not isinstance(item, uni.ImplDef)]
|
|
31
|
+
merged: list[uni.UniNode] = []
|
|
32
|
+
for mod in node.impl_mod:
|
|
33
|
+
merged.extend(mod.body)
|
|
34
|
+
merged.extend(clean_body)
|
|
35
|
+
for mod in node.test_mod:
|
|
36
|
+
merged.extend(mod.body)
|
|
37
|
+
return merged
|
|
38
|
+
|
|
39
|
+
def _init_child_passes(self, pass_class: type[ChildPassT]) -> list[ChildPassT]:
|
|
40
|
+
"""Instantiate child passes for impl and test modules."""
|
|
41
|
+
return [
|
|
42
|
+
pass_class(ir_in=sub_module, prog=self.prog)
|
|
43
|
+
for sub_module in self.ir_in.impl_mod + self.ir_in.test_mod
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
def _flatten_ast_list(self, items: list[T | list[T] | None]) -> list[T]:
|
|
47
|
+
"""Flatten nested AST lists while skipping ``None`` entries."""
|
|
48
|
+
flattened: list[T] = []
|
|
49
|
+
for item in items:
|
|
50
|
+
if isinstance(item, list):
|
|
51
|
+
flattened.extend(item)
|
|
52
|
+
elif item is not None:
|
|
53
|
+
flattened.append(item)
|
|
54
|
+
return flattened
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"""Helpers for generating target-specific JSX AST nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ast as ast3
|
|
6
|
+
from typing import Optional, TYPE_CHECKING, Union, cast
|
|
7
|
+
|
|
8
|
+
import jaclang.compiler.unitree as uni
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from jaclang.compiler.passes.ecmascript.esast_gen_pass import EsastGenPass
|
|
12
|
+
from jaclang.compiler.passes.ecmascript.estree import (
|
|
13
|
+
Expression,
|
|
14
|
+
Property,
|
|
15
|
+
SpreadElement,
|
|
16
|
+
)
|
|
17
|
+
from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EsJsxProcessor:
|
|
21
|
+
"""Generate ESTree structures for JSX nodes."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, pass_ref: "EsastGenPass") -> None:
|
|
24
|
+
self.pass_ref = pass_ref
|
|
25
|
+
# Import estree at runtime to access AST node classes
|
|
26
|
+
from jaclang.compiler.passes.ecmascript import estree as es
|
|
27
|
+
|
|
28
|
+
self.es = es
|
|
29
|
+
|
|
30
|
+
def element(self, node: uni.JsxElement) -> "Expression":
|
|
31
|
+
"""Process JSX element into __jacJsx(tag, props, children) call."""
|
|
32
|
+
es = self.es
|
|
33
|
+
if node.is_fragment or not node.name:
|
|
34
|
+
tag_expr: Expression = self.pass_ref.sync_loc(
|
|
35
|
+
es.Literal(value=None), jac_node=node
|
|
36
|
+
)
|
|
37
|
+
else:
|
|
38
|
+
tag_expr = (
|
|
39
|
+
node.name.gen.es_ast
|
|
40
|
+
if node.name.gen.es_ast
|
|
41
|
+
else self.pass_ref.sync_loc(es.Literal(value=None), jac_node=node.name)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
attributes = node.attributes or []
|
|
45
|
+
has_spread = any(
|
|
46
|
+
isinstance(attr, uni.JsxSpreadAttribute) for attr in attributes
|
|
47
|
+
)
|
|
48
|
+
if not attributes:
|
|
49
|
+
props_expr: Expression = self.pass_ref.sync_loc(
|
|
50
|
+
es.ObjectExpression(properties=[]), jac_node=node
|
|
51
|
+
)
|
|
52
|
+
elif has_spread:
|
|
53
|
+
segments: list[Expression] = []
|
|
54
|
+
for attr in attributes:
|
|
55
|
+
if isinstance(attr, uni.JsxSpreadAttribute):
|
|
56
|
+
exp = getattr(attr.gen, "es_ast", None)
|
|
57
|
+
if isinstance(exp, es.Expression):
|
|
58
|
+
segments.append(exp)
|
|
59
|
+
elif isinstance(attr, uni.JsxNormalAttribute):
|
|
60
|
+
prop = getattr(attr.gen, "es_ast", None)
|
|
61
|
+
if isinstance(prop, es.Property):
|
|
62
|
+
segments.append(
|
|
63
|
+
self.pass_ref.sync_loc(
|
|
64
|
+
es.ObjectExpression(properties=[prop]), jac_node=attr
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
if segments:
|
|
68
|
+
assign_member = self.pass_ref.sync_loc(
|
|
69
|
+
es.MemberExpression(
|
|
70
|
+
object=self.pass_ref.sync_loc(
|
|
71
|
+
es.Identifier(name="Object"), jac_node=node
|
|
72
|
+
),
|
|
73
|
+
property=self.pass_ref.sync_loc(
|
|
74
|
+
es.Identifier(name="assign"), jac_node=node
|
|
75
|
+
),
|
|
76
|
+
computed=False,
|
|
77
|
+
optional=False,
|
|
78
|
+
),
|
|
79
|
+
jac_node=node,
|
|
80
|
+
)
|
|
81
|
+
props_expr = self.pass_ref.sync_loc(
|
|
82
|
+
es.CallExpression(
|
|
83
|
+
callee=assign_member,
|
|
84
|
+
arguments=[
|
|
85
|
+
self.pass_ref.sync_loc(
|
|
86
|
+
es.ObjectExpression(properties=[]), jac_node=node
|
|
87
|
+
),
|
|
88
|
+
*segments,
|
|
89
|
+
],
|
|
90
|
+
),
|
|
91
|
+
jac_node=node,
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
props_expr = self.pass_ref.sync_loc(
|
|
95
|
+
es.ObjectExpression(properties=[]), jac_node=node
|
|
96
|
+
)
|
|
97
|
+
else:
|
|
98
|
+
properties: list[Property] = []
|
|
99
|
+
for attr in attributes:
|
|
100
|
+
prop = getattr(attr.gen, "es_ast", None)
|
|
101
|
+
if isinstance(prop, es.Property):
|
|
102
|
+
properties.append(prop)
|
|
103
|
+
props_expr = self.pass_ref.sync_loc(
|
|
104
|
+
es.ObjectExpression(properties=properties), jac_node=node
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
children_elements: list[Optional[Union[Expression, SpreadElement]]] = []
|
|
108
|
+
for child in node.children or []:
|
|
109
|
+
child_expr = getattr(child.gen, "es_ast", None)
|
|
110
|
+
if child_expr is None:
|
|
111
|
+
continue
|
|
112
|
+
if isinstance(child_expr, list):
|
|
113
|
+
children_elements.extend(child_expr) # type: ignore[arg-type]
|
|
114
|
+
else:
|
|
115
|
+
children_elements.append(child_expr)
|
|
116
|
+
children_expr = self.pass_ref.sync_loc(
|
|
117
|
+
es.ArrayExpression(elements=children_elements), jac_node=node
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
call_expr = self.pass_ref.sync_loc(
|
|
121
|
+
es.CallExpression(
|
|
122
|
+
callee=self.pass_ref.sync_loc(
|
|
123
|
+
es.Identifier(name="__jacJsx"), jac_node=node
|
|
124
|
+
),
|
|
125
|
+
arguments=[tag_expr, props_expr, children_expr],
|
|
126
|
+
),
|
|
127
|
+
jac_node=node,
|
|
128
|
+
)
|
|
129
|
+
return call_expr
|
|
130
|
+
|
|
131
|
+
def element_name(self, node: uni.JsxElementName) -> "Expression":
|
|
132
|
+
"""Process JSX element name."""
|
|
133
|
+
es = self.es
|
|
134
|
+
if not node.parts:
|
|
135
|
+
expr = self.pass_ref.sync_loc(es.Literal(value=None), jac_node=node)
|
|
136
|
+
else:
|
|
137
|
+
parts = [part.value for part in node.parts]
|
|
138
|
+
first = parts[0]
|
|
139
|
+
if first and first[0].isupper():
|
|
140
|
+
expr = self.pass_ref.sync_loc(
|
|
141
|
+
es.Identifier(name=first), jac_node=node.parts[0]
|
|
142
|
+
)
|
|
143
|
+
for idx, part in enumerate(parts[1:], start=1):
|
|
144
|
+
expr = self.pass_ref.sync_loc(
|
|
145
|
+
es.MemberExpression(
|
|
146
|
+
object=expr,
|
|
147
|
+
property=self.pass_ref.sync_loc(
|
|
148
|
+
es.Identifier(name=part), jac_node=node.parts[idx]
|
|
149
|
+
),
|
|
150
|
+
computed=False,
|
|
151
|
+
optional=False,
|
|
152
|
+
),
|
|
153
|
+
jac_node=node,
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
expr = self.pass_ref.sync_loc(
|
|
157
|
+
es.Literal(value=".".join(parts)), jac_node=node
|
|
158
|
+
)
|
|
159
|
+
node.gen.es_ast = expr
|
|
160
|
+
return expr
|
|
161
|
+
|
|
162
|
+
def spread_attribute(self, node: uni.JsxSpreadAttribute) -> "Expression":
|
|
163
|
+
"""Process JSX spread attribute."""
|
|
164
|
+
es = self.es
|
|
165
|
+
expr = (
|
|
166
|
+
node.expr.gen.es_ast
|
|
167
|
+
if node.expr and node.expr.gen.es_ast
|
|
168
|
+
else self.pass_ref.sync_loc(
|
|
169
|
+
es.ObjectExpression(properties=[]), jac_node=node
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
node.gen.es_ast = expr
|
|
173
|
+
return expr
|
|
174
|
+
|
|
175
|
+
def normal_attribute(self, node: uni.JsxNormalAttribute) -> "Property":
|
|
176
|
+
"""Process JSX normal attribute."""
|
|
177
|
+
es = self.es
|
|
178
|
+
key_expr = self.pass_ref.sync_loc(
|
|
179
|
+
es.Literal(value=node.name.value), jac_node=node.name
|
|
180
|
+
)
|
|
181
|
+
if node.value is None:
|
|
182
|
+
value_expr = self.pass_ref.sync_loc(es.Literal(value=True), jac_node=node)
|
|
183
|
+
elif isinstance(node.value, uni.String):
|
|
184
|
+
value_expr = self.pass_ref.sync_loc(
|
|
185
|
+
es.Literal(value=node.value.lit_value), jac_node=node.value
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
value_expr = (
|
|
189
|
+
node.value.gen.es_ast
|
|
190
|
+
if node.value.gen.es_ast
|
|
191
|
+
else self.pass_ref.sync_loc(es.Literal(value=None), jac_node=node.value)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
prop = self.pass_ref.sync_loc(
|
|
195
|
+
es.Property(
|
|
196
|
+
key=key_expr,
|
|
197
|
+
value=value_expr,
|
|
198
|
+
kind="init",
|
|
199
|
+
method=False,
|
|
200
|
+
shorthand=False,
|
|
201
|
+
computed=False,
|
|
202
|
+
),
|
|
203
|
+
jac_node=node,
|
|
204
|
+
)
|
|
205
|
+
node.gen.es_ast = prop
|
|
206
|
+
return prop
|
|
207
|
+
|
|
208
|
+
def text(self, node: uni.JsxText) -> "Expression":
|
|
209
|
+
"""Process JSX text node."""
|
|
210
|
+
es = self.es
|
|
211
|
+
raw_value = node.value.value if hasattr(node.value, "value") else node.value
|
|
212
|
+
expr = self.pass_ref.sync_loc(es.Literal(value=str(raw_value)), jac_node=node)
|
|
213
|
+
node.gen.es_ast = expr
|
|
214
|
+
return expr
|
|
215
|
+
|
|
216
|
+
def expression(self, node: uni.JsxExpression) -> "Expression":
|
|
217
|
+
"""Process JSX expression child."""
|
|
218
|
+
es = self.es
|
|
219
|
+
expr = (
|
|
220
|
+
node.expr.gen.es_ast
|
|
221
|
+
if node.expr and node.expr.gen.es_ast
|
|
222
|
+
else self.pass_ref.sync_loc(es.Literal(value=None), jac_node=node.expr)
|
|
223
|
+
)
|
|
224
|
+
node.gen.es_ast = expr
|
|
225
|
+
return expr
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class PyJsxProcessor:
|
|
229
|
+
"""Generate Python AST structures for JSX nodes."""
|
|
230
|
+
|
|
231
|
+
def __init__(self, pass_ref: "PyastGenPass") -> None:
|
|
232
|
+
self.pass_ref = pass_ref
|
|
233
|
+
|
|
234
|
+
def element(self, node: uni.JsxElement) -> list[ast3.AST]:
|
|
235
|
+
"""Generate Python AST for JSX elements."""
|
|
236
|
+
if node.is_fragment or not node.name:
|
|
237
|
+
tag_arg: ast3.expr = self.pass_ref.sync(ast3.Constant(value=None), node)
|
|
238
|
+
else:
|
|
239
|
+
tag_arg = cast(ast3.expr, node.name.gen.py_ast[0])
|
|
240
|
+
|
|
241
|
+
if not node.attributes:
|
|
242
|
+
attrs_expr = self.pass_ref.sync(ast3.Dict(keys=[], values=[]), node)
|
|
243
|
+
elif any(isinstance(attr, uni.JsxSpreadAttribute) for attr in node.attributes):
|
|
244
|
+
attrs_expr = self.pass_ref.sync(ast3.Dict(keys=[], values=[]), node)
|
|
245
|
+
for attr in node.attributes:
|
|
246
|
+
attr_ast = cast(ast3.expr, attr.gen.py_ast[0])
|
|
247
|
+
if isinstance(attr, uni.JsxSpreadAttribute):
|
|
248
|
+
attrs_expr = self.pass_ref.sync(
|
|
249
|
+
ast3.Dict(keys=[None, None], values=[attrs_expr, attr_ast]),
|
|
250
|
+
attr,
|
|
251
|
+
)
|
|
252
|
+
elif isinstance(attr, uni.JsxNormalAttribute):
|
|
253
|
+
key_ast, value_ast = attr_ast.elts # type: ignore[attr-defined]
|
|
254
|
+
attrs_expr = self.pass_ref.sync(
|
|
255
|
+
ast3.Dict(
|
|
256
|
+
keys=[None, key_ast],
|
|
257
|
+
values=[attrs_expr, cast(ast3.expr, value_ast)],
|
|
258
|
+
),
|
|
259
|
+
attr,
|
|
260
|
+
)
|
|
261
|
+
else:
|
|
262
|
+
keys: list[ast3.expr | None] = []
|
|
263
|
+
values: list[ast3.expr] = []
|
|
264
|
+
for attr in node.attributes:
|
|
265
|
+
if isinstance(attr, uni.JsxNormalAttribute):
|
|
266
|
+
attr_ast = attr.gen.py_ast[0]
|
|
267
|
+
key_ast, value_ast = attr_ast.elts # type: ignore[attr-defined]
|
|
268
|
+
keys.append(cast(ast3.expr, key_ast))
|
|
269
|
+
values.append(cast(ast3.expr, value_ast))
|
|
270
|
+
attrs_expr = self.pass_ref.sync(ast3.Dict(keys=keys, values=values), node)
|
|
271
|
+
|
|
272
|
+
if node.children:
|
|
273
|
+
children_arg = self.pass_ref.sync(
|
|
274
|
+
ast3.List(
|
|
275
|
+
elts=[cast(ast3.expr, c.gen.py_ast[0]) for c in node.children],
|
|
276
|
+
ctx=ast3.Load(),
|
|
277
|
+
),
|
|
278
|
+
node,
|
|
279
|
+
)
|
|
280
|
+
else:
|
|
281
|
+
children_arg = self.pass_ref.sync(ast3.List(elts=[], ctx=ast3.Load()), node)
|
|
282
|
+
|
|
283
|
+
call = self.pass_ref.sync(
|
|
284
|
+
ast3.Call(
|
|
285
|
+
func=self.pass_ref.jaclib_obj("jsx"),
|
|
286
|
+
args=[tag_arg, attrs_expr, children_arg],
|
|
287
|
+
keywords=[],
|
|
288
|
+
),
|
|
289
|
+
node,
|
|
290
|
+
)
|
|
291
|
+
node.gen.py_ast = [call]
|
|
292
|
+
return node.gen.py_ast
|
|
293
|
+
|
|
294
|
+
def element_name(self, node: uni.JsxElementName) -> list[ast3.AST]:
|
|
295
|
+
"""Generate Python AST for JSX element names."""
|
|
296
|
+
name_str = ".".join(part.value for part in node.parts)
|
|
297
|
+
if node.parts and node.parts[0].value[0].isupper():
|
|
298
|
+
expr = self.pass_ref.sync(
|
|
299
|
+
ast3.Name(id=name_str, ctx=ast3.Load()),
|
|
300
|
+
node,
|
|
301
|
+
)
|
|
302
|
+
else:
|
|
303
|
+
expr = self.pass_ref.sync(ast3.Constant(value=name_str), node)
|
|
304
|
+
node.gen.py_ast = [expr]
|
|
305
|
+
return node.gen.py_ast
|
|
306
|
+
|
|
307
|
+
def spread_attribute(self, node: uni.JsxSpreadAttribute) -> list[ast3.AST]:
|
|
308
|
+
"""Generate Python AST for JSX spread attributes."""
|
|
309
|
+
node.gen.py_ast = [cast(ast3.expr, node.expr.gen.py_ast[0])]
|
|
310
|
+
return node.gen.py_ast
|
|
311
|
+
|
|
312
|
+
def normal_attribute(self, node: uni.JsxNormalAttribute) -> list[ast3.AST]:
|
|
313
|
+
"""Generate Python AST for JSX normal attributes."""
|
|
314
|
+
if not node.name:
|
|
315
|
+
node.gen.py_ast = []
|
|
316
|
+
return node.gen.py_ast
|
|
317
|
+
|
|
318
|
+
key_ast = self.pass_ref.sync(ast3.Constant(value=node.name.value), node.name)
|
|
319
|
+
value_ast = (
|
|
320
|
+
cast(ast3.expr, node.value.gen.py_ast[0]) # type: ignore[index]
|
|
321
|
+
if node.value
|
|
322
|
+
else self.pass_ref.sync(ast3.Constant(value=True), node)
|
|
323
|
+
)
|
|
324
|
+
node.gen.py_ast = [
|
|
325
|
+
self.pass_ref.sync(
|
|
326
|
+
ast3.Tuple(elts=[key_ast, value_ast], ctx=ast3.Load()),
|
|
327
|
+
node,
|
|
328
|
+
)
|
|
329
|
+
]
|
|
330
|
+
return node.gen.py_ast
|
|
331
|
+
|
|
332
|
+
def text(self, node: uni.JsxText) -> list[ast3.AST]:
|
|
333
|
+
"""Generate Python AST for JSX text nodes."""
|
|
334
|
+
expr = self.pass_ref.sync(ast3.Constant(value=node.value.value), node)
|
|
335
|
+
node.gen.py_ast = [expr]
|
|
336
|
+
return node.gen.py_ast
|
|
337
|
+
|
|
338
|
+
def expression(self, node: uni.JsxExpression) -> list[ast3.AST]:
|
|
339
|
+
"""Generate Python AST for JSX expression children."""
|
|
340
|
+
node.gen.py_ast = [cast(ast3.expr, node.expr.gen.py_ast[0])]
|
|
341
|
+
return node.gen.py_ast
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
__all__ = ["EsJsxProcessor", "PyJsxProcessor"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""ECMAScript/JavaScript AST generation for Jac.
|
|
2
|
+
|
|
3
|
+
This package provides ECMAScript AST generation capabilities following the ESTree
|
|
4
|
+
specification, allowing Jac code to be transpiled to JavaScript/ECMAScript.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from jaclang.compiler.passes.ecmascript.esast_gen_pass import EsastGenPass
|
|
8
|
+
from jaclang.compiler.passes.ecmascript.estree import (
|
|
9
|
+
Declaration,
|
|
10
|
+
Expression,
|
|
11
|
+
Pattern,
|
|
12
|
+
Program,
|
|
13
|
+
Statement,
|
|
14
|
+
es_node_to_dict,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"EsastGenPass",
|
|
19
|
+
"Expression",
|
|
20
|
+
"Declaration",
|
|
21
|
+
"Pattern",
|
|
22
|
+
"Program",
|
|
23
|
+
"Statement",
|
|
24
|
+
"es_node_to_dict",
|
|
25
|
+
]
|