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,576 @@
|
|
|
1
|
+
"""ECMAScript/JavaScript code generation from ESTree AST.
|
|
2
|
+
|
|
3
|
+
This module provides functionality to convert ESTree AST nodes back to
|
|
4
|
+
JavaScript source code (unparsing).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from jaclang.compiler.passes.ecmascript import estree as es
|
|
10
|
+
from jaclang.utils.helpers import pascal_to_snake
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class JSCodeGenerator:
|
|
14
|
+
"""Generate JavaScript code from ESTree AST."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, indent: str = " ") -> None:
|
|
17
|
+
"""Initialize the code generator."""
|
|
18
|
+
self.indent_str = indent
|
|
19
|
+
self.indent_level = 0
|
|
20
|
+
|
|
21
|
+
def indent(self) -> str:
|
|
22
|
+
"""Get current indentation."""
|
|
23
|
+
return self.indent_str * self.indent_level
|
|
24
|
+
|
|
25
|
+
def generate(self, node: es.Node) -> str:
|
|
26
|
+
"""Generate JavaScript code for a node."""
|
|
27
|
+
method_name = f"gen_{pascal_to_snake(node.type)}"
|
|
28
|
+
method = getattr(self, method_name, None)
|
|
29
|
+
if method:
|
|
30
|
+
return method(node)
|
|
31
|
+
else:
|
|
32
|
+
return f"/* Unsupported node type: {node.type} */"
|
|
33
|
+
|
|
34
|
+
# Program and Statements
|
|
35
|
+
# ======================
|
|
36
|
+
|
|
37
|
+
def gen_program(self, node: es.Program) -> str:
|
|
38
|
+
"""Generate program."""
|
|
39
|
+
return "\n".join(self.generate(stmt) for stmt in node.body)
|
|
40
|
+
|
|
41
|
+
def gen_expression_statement(self, node: es.ExpressionStatement) -> str:
|
|
42
|
+
"""Generate expression statement."""
|
|
43
|
+
return f"{self.indent()}{self.generate(node.expression)};"
|
|
44
|
+
|
|
45
|
+
def gen_block_statement(self, node: es.BlockStatement) -> str:
|
|
46
|
+
"""Generate block statement."""
|
|
47
|
+
if not node.body:
|
|
48
|
+
return "{}"
|
|
49
|
+
self.indent_level += 1
|
|
50
|
+
body = "\n".join(self.generate(stmt) for stmt in node.body)
|
|
51
|
+
self.indent_level -= 1
|
|
52
|
+
return f"{{\n{body}\n{self.indent()}}}"
|
|
53
|
+
|
|
54
|
+
def gen_empty_statement(self, node: es.EmptyStatement) -> str:
|
|
55
|
+
"""Generate empty statement."""
|
|
56
|
+
return f"{self.indent()};"
|
|
57
|
+
|
|
58
|
+
def gen_return_statement(self, node: es.ReturnStatement) -> str:
|
|
59
|
+
"""Generate return statement."""
|
|
60
|
+
if node.argument:
|
|
61
|
+
return f"{self.indent()}return {self.generate(node.argument)};"
|
|
62
|
+
return f"{self.indent()}return;"
|
|
63
|
+
|
|
64
|
+
def gen_if_statement(self, node: es.IfStatement) -> str:
|
|
65
|
+
"""Generate if statement."""
|
|
66
|
+
test = self.generate(node.test)
|
|
67
|
+
consequent = self.generate(node.consequent)
|
|
68
|
+
result = f"{self.indent()}if ({test}) {consequent}"
|
|
69
|
+
if node.alternate:
|
|
70
|
+
if isinstance(node.alternate, es.IfStatement):
|
|
71
|
+
# else if
|
|
72
|
+
result += f" else {self.generate(node.alternate).lstrip()}"
|
|
73
|
+
else:
|
|
74
|
+
result += f" else {self.generate(node.alternate)}"
|
|
75
|
+
return result
|
|
76
|
+
|
|
77
|
+
def gen_while_statement(self, node: es.WhileStatement) -> str:
|
|
78
|
+
"""Generate while statement."""
|
|
79
|
+
test = self.generate(node.test)
|
|
80
|
+
body = self.generate(node.body)
|
|
81
|
+
return f"{self.indent()}while ({test}) {body}"
|
|
82
|
+
|
|
83
|
+
def gen_do_while_statement(self, node: es.DoWhileStatement) -> str:
|
|
84
|
+
"""Generate do-while statement."""
|
|
85
|
+
body = self.generate(node.body)
|
|
86
|
+
test = self.generate(node.test)
|
|
87
|
+
return f"{self.indent()}do {body} while ({test});"
|
|
88
|
+
|
|
89
|
+
def gen_for_statement(self, node: es.ForStatement) -> str:
|
|
90
|
+
"""Generate for statement."""
|
|
91
|
+
init = self.generate(node.init) if node.init else ""
|
|
92
|
+
test = self.generate(node.test) if node.test else ""
|
|
93
|
+
update = self.generate(node.update) if node.update else ""
|
|
94
|
+
body = self.generate(node.body)
|
|
95
|
+
return f"{self.indent()}for ({init}; {test}; {update}) {body}"
|
|
96
|
+
|
|
97
|
+
def gen_for_in_statement(self, node: es.ForInStatement) -> str:
|
|
98
|
+
"""Generate for-in statement."""
|
|
99
|
+
left = self.generate(node.left)
|
|
100
|
+
right = self.generate(node.right)
|
|
101
|
+
body = self.generate(node.body)
|
|
102
|
+
return f"{self.indent()}for ({left} in {right}) {body}"
|
|
103
|
+
|
|
104
|
+
def gen_for_of_statement(self, node: es.ForOfStatement) -> str:
|
|
105
|
+
"""Generate for-of statement."""
|
|
106
|
+
await_str = "await " if node.await_ else ""
|
|
107
|
+
if isinstance(node.left, es.VariableDeclaration):
|
|
108
|
+
declarators = ", ".join(
|
|
109
|
+
self.generate(decl) for decl in node.left.declarations
|
|
110
|
+
)
|
|
111
|
+
left = f"{node.left.kind} {declarators}"
|
|
112
|
+
else:
|
|
113
|
+
left = self.generate(node.left)
|
|
114
|
+
right = self.generate(node.right)
|
|
115
|
+
body = self.generate(node.body)
|
|
116
|
+
return f"{self.indent()}for {await_str}({left} of {right}) {body}"
|
|
117
|
+
|
|
118
|
+
def gen_break_statement(self, node: es.BreakStatement) -> str:
|
|
119
|
+
"""Generate break statement."""
|
|
120
|
+
if node.label:
|
|
121
|
+
return f"{self.indent()}break {self.generate(node.label)};"
|
|
122
|
+
return f"{self.indent()}break;"
|
|
123
|
+
|
|
124
|
+
def gen_continue_statement(self, node: es.ContinueStatement) -> str:
|
|
125
|
+
"""Generate continue statement."""
|
|
126
|
+
if node.label:
|
|
127
|
+
return f"{self.indent()}continue {self.generate(node.label)};"
|
|
128
|
+
return f"{self.indent()}continue;"
|
|
129
|
+
|
|
130
|
+
def gen_throw_statement(self, node: es.ThrowStatement) -> str:
|
|
131
|
+
"""Generate throw statement."""
|
|
132
|
+
return f"{self.indent()}throw {self.generate(node.argument)};"
|
|
133
|
+
|
|
134
|
+
def gen_try_statement(self, node: es.TryStatement) -> str:
|
|
135
|
+
"""Generate try statement."""
|
|
136
|
+
result = f"{self.indent()}try {self.generate(node.block)}"
|
|
137
|
+
if node.handler:
|
|
138
|
+
result += f" {self.generate(node.handler)}"
|
|
139
|
+
if node.finalizer:
|
|
140
|
+
result += f" finally {self.generate(node.finalizer)}"
|
|
141
|
+
return result
|
|
142
|
+
|
|
143
|
+
def gen_catch_clause(self, node: es.CatchClause) -> str:
|
|
144
|
+
"""Generate catch clause."""
|
|
145
|
+
if node.param:
|
|
146
|
+
return f"catch ({self.generate(node.param)}) {self.generate(node.body)}"
|
|
147
|
+
return f"catch {self.generate(node.body)}"
|
|
148
|
+
|
|
149
|
+
def gen_switch_statement(self, node: es.SwitchStatement) -> str:
|
|
150
|
+
"""Generate switch statement."""
|
|
151
|
+
discriminant = self.generate(node.discriminant)
|
|
152
|
+
self.indent_level += 1
|
|
153
|
+
cases = "\n".join(self.generate(case) for case in node.cases)
|
|
154
|
+
self.indent_level -= 1
|
|
155
|
+
return f"{self.indent()}switch ({discriminant}) {{\n{cases}\n{self.indent()}}}"
|
|
156
|
+
|
|
157
|
+
def gen_switch_case(self, node: es.SwitchCase) -> str:
|
|
158
|
+
"""Generate switch case."""
|
|
159
|
+
if node.test:
|
|
160
|
+
result = f"{self.indent()}case {self.generate(node.test)}:\n"
|
|
161
|
+
else:
|
|
162
|
+
result = f"{self.indent()}default:\n"
|
|
163
|
+
self.indent_level += 1
|
|
164
|
+
for stmt in node.consequent:
|
|
165
|
+
result += f"{self.generate(stmt)}\n"
|
|
166
|
+
self.indent_level -= 1
|
|
167
|
+
return result.rstrip()
|
|
168
|
+
|
|
169
|
+
# Declarations
|
|
170
|
+
# ============
|
|
171
|
+
|
|
172
|
+
def gen_function_declaration(self, node: es.FunctionDeclaration) -> str:
|
|
173
|
+
"""Generate function declaration."""
|
|
174
|
+
async_str = "async " if node.async_ else ""
|
|
175
|
+
generator_str = "*" if node.generator else ""
|
|
176
|
+
name = self.generate(node.id) if node.id else ""
|
|
177
|
+
params = ", ".join(self.generate(p) for p in node.params)
|
|
178
|
+
body = self.generate(node.body)
|
|
179
|
+
return (
|
|
180
|
+
f"{self.indent()}{async_str}function{generator_str} {name}({params}) {body}"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def gen_variable_declaration(self, node: es.VariableDeclaration) -> str:
|
|
184
|
+
"""Generate variable declaration."""
|
|
185
|
+
declarators = ", ".join(self.generate(d) for d in node.declarations)
|
|
186
|
+
return f"{self.indent()}{node.kind} {declarators};"
|
|
187
|
+
|
|
188
|
+
def gen_variable_declarator(self, node: es.VariableDeclarator) -> str:
|
|
189
|
+
"""Generate variable declarator."""
|
|
190
|
+
id_str = self.generate(node.id)
|
|
191
|
+
if node.init:
|
|
192
|
+
return f"{id_str} = {self.generate(node.init)}"
|
|
193
|
+
return id_str
|
|
194
|
+
|
|
195
|
+
def gen_class_declaration(self, node: es.ClassDeclaration) -> str:
|
|
196
|
+
"""Generate class declaration."""
|
|
197
|
+
name = self.generate(node.id) if node.id else ""
|
|
198
|
+
extends = (
|
|
199
|
+
f" extends {self.generate(node.superClass)}" if node.superClass else ""
|
|
200
|
+
)
|
|
201
|
+
body = self.generate(node.body)
|
|
202
|
+
return f"{self.indent()}class {name}{extends} {body}"
|
|
203
|
+
|
|
204
|
+
def gen_class_expression(self, node: es.ClassExpression) -> str:
|
|
205
|
+
"""Generate class expression."""
|
|
206
|
+
name = self.generate(node.id) if node.id else ""
|
|
207
|
+
extends = (
|
|
208
|
+
f" extends {self.generate(node.superClass)}" if node.superClass else ""
|
|
209
|
+
)
|
|
210
|
+
body = self.generate(node.body)
|
|
211
|
+
return f"class {name}{extends} {body}"
|
|
212
|
+
|
|
213
|
+
def gen_class_body(self, node: es.ClassBody) -> str:
|
|
214
|
+
"""Generate class body."""
|
|
215
|
+
if not node.body:
|
|
216
|
+
return "{}"
|
|
217
|
+
self.indent_level += 1
|
|
218
|
+
methods = "\n".join(self.generate(m) for m in node.body)
|
|
219
|
+
self.indent_level -= 1
|
|
220
|
+
return f"{{\n{methods}\n{self.indent()}}}"
|
|
221
|
+
|
|
222
|
+
def gen_method_definition(self, node: es.MethodDefinition) -> str:
|
|
223
|
+
"""Generate method definition."""
|
|
224
|
+
static_str = "static " if node.static else ""
|
|
225
|
+
key = self.generate(node.key)
|
|
226
|
+
value = self.generate(node.value)
|
|
227
|
+
|
|
228
|
+
# Extract function parts
|
|
229
|
+
if isinstance(node.value, es.FunctionExpression):
|
|
230
|
+
async_str = "async " if node.value.async_ else ""
|
|
231
|
+
params = ", ".join(self.generate(p) for p in node.value.params)
|
|
232
|
+
body = self.generate(node.value.body)
|
|
233
|
+
|
|
234
|
+
if node.kind == "constructor":
|
|
235
|
+
return f"{self.indent()}constructor({params}) {body}"
|
|
236
|
+
elif node.kind == "get":
|
|
237
|
+
return f"{self.indent()}{static_str}get {key}() {body}"
|
|
238
|
+
elif node.kind == "set":
|
|
239
|
+
return f"{self.indent()}{static_str}set {key}({params}) {body}"
|
|
240
|
+
else:
|
|
241
|
+
return f"{self.indent()}{static_str}{async_str}{key}({params}) {body}"
|
|
242
|
+
|
|
243
|
+
return f"{self.indent()}{static_str}{key}{value}"
|
|
244
|
+
|
|
245
|
+
def gen_property_definition(self, node: es.PropertyDefinition) -> str:
|
|
246
|
+
"""Generate class field definition."""
|
|
247
|
+
static_str = "static " if node.static else ""
|
|
248
|
+
key = self.generate(node.key) if node.key else ""
|
|
249
|
+
if node.computed:
|
|
250
|
+
key = f"[{key}]"
|
|
251
|
+
value = f" = {self.generate(node.value)}" if node.value else ""
|
|
252
|
+
return f"{self.indent()}{static_str}{key}{value};"
|
|
253
|
+
|
|
254
|
+
def gen_static_block(self, node: es.StaticBlock) -> str:
|
|
255
|
+
"""Generate static initialization block."""
|
|
256
|
+
block = self.generate(es.BlockStatement(body=node.body))
|
|
257
|
+
return f"{self.indent()}static {block}"
|
|
258
|
+
|
|
259
|
+
# Expressions
|
|
260
|
+
# ===========
|
|
261
|
+
|
|
262
|
+
def gen_identifier(self, node: es.Identifier) -> str:
|
|
263
|
+
"""Generate identifier."""
|
|
264
|
+
return node.name
|
|
265
|
+
|
|
266
|
+
def gen_private_identifier(self, node: es.PrivateIdentifier) -> str:
|
|
267
|
+
"""Generate private identifier."""
|
|
268
|
+
return f"#{node.name}"
|
|
269
|
+
|
|
270
|
+
def gen_literal(self, node: es.Literal) -> str:
|
|
271
|
+
"""Generate literal."""
|
|
272
|
+
if node.raw:
|
|
273
|
+
return node.raw
|
|
274
|
+
if isinstance(node.value, str):
|
|
275
|
+
return f'"{node.value}"'
|
|
276
|
+
elif node.value is None:
|
|
277
|
+
return "null"
|
|
278
|
+
elif isinstance(node.value, bool):
|
|
279
|
+
return "true" if node.value else "false"
|
|
280
|
+
else:
|
|
281
|
+
return str(node.value)
|
|
282
|
+
|
|
283
|
+
def gen_this_expression(self, node: es.ThisExpression) -> str:
|
|
284
|
+
"""Generate this expression."""
|
|
285
|
+
return "this"
|
|
286
|
+
|
|
287
|
+
def gen_array_expression(self, node: es.ArrayExpression) -> str:
|
|
288
|
+
"""Generate array expression."""
|
|
289
|
+
elements = ", ".join(self.generate(e) if e else "" for e in node.elements)
|
|
290
|
+
return f"[{elements}]"
|
|
291
|
+
|
|
292
|
+
def gen_object_expression(self, node: es.ObjectExpression) -> str:
|
|
293
|
+
"""Generate object expression."""
|
|
294
|
+
if not node.properties:
|
|
295
|
+
return "{}"
|
|
296
|
+
props = ", ".join(self.generate(p) for p in node.properties)
|
|
297
|
+
return f"{{{props}}}"
|
|
298
|
+
|
|
299
|
+
def gen_property(self, node: es.Property) -> str:
|
|
300
|
+
"""Generate property."""
|
|
301
|
+
key = self.generate(node.key)
|
|
302
|
+
value = self.generate(node.value)
|
|
303
|
+
|
|
304
|
+
if node.shorthand:
|
|
305
|
+
return key
|
|
306
|
+
elif node.computed:
|
|
307
|
+
return f"[{key}]: {value}"
|
|
308
|
+
elif node.kind == "get":
|
|
309
|
+
return f"get {key}() {value}"
|
|
310
|
+
elif node.kind == "set":
|
|
311
|
+
return f"set {key}({value})"
|
|
312
|
+
else:
|
|
313
|
+
return f"{key}: {value}"
|
|
314
|
+
|
|
315
|
+
def gen_function_expression(self, node: es.FunctionExpression) -> str:
|
|
316
|
+
"""Generate function expression."""
|
|
317
|
+
async_str = "async " if node.async_ else ""
|
|
318
|
+
generator_str = "*" if node.generator else ""
|
|
319
|
+
name = self.generate(node.id) if node.id else ""
|
|
320
|
+
params = ", ".join(self.generate(p) for p in node.params)
|
|
321
|
+
body = self.generate(node.body)
|
|
322
|
+
return f"{async_str}function{generator_str} {name}({params}) {body}".strip()
|
|
323
|
+
|
|
324
|
+
def gen_arrow_function_expression(self, node: es.ArrowFunctionExpression) -> str:
|
|
325
|
+
"""Generate arrow function expression."""
|
|
326
|
+
async_str = "async " if node.async_ else ""
|
|
327
|
+
params = ", ".join(self.generate(p) for p in node.params)
|
|
328
|
+
if len(node.params) == 1:
|
|
329
|
+
params = self.generate(node.params[0])
|
|
330
|
+
else:
|
|
331
|
+
params = f"({params})"
|
|
332
|
+
|
|
333
|
+
if node.expression:
|
|
334
|
+
body = self.generate(node.body)
|
|
335
|
+
return f"{async_str}{params} => {body}"
|
|
336
|
+
else:
|
|
337
|
+
body = self.generate(node.body)
|
|
338
|
+
return f"{async_str}{params} => {body}"
|
|
339
|
+
|
|
340
|
+
def gen_unary_expression(self, node: es.UnaryExpression) -> str:
|
|
341
|
+
"""Generate unary expression."""
|
|
342
|
+
arg = self.generate(node.argument)
|
|
343
|
+
if node.prefix:
|
|
344
|
+
if node.operator in ("typeof", "void", "delete"):
|
|
345
|
+
return f"{node.operator} {arg}"
|
|
346
|
+
return f"{node.operator}{arg}"
|
|
347
|
+
else:
|
|
348
|
+
return f"{arg}{node.operator}"
|
|
349
|
+
|
|
350
|
+
def gen_update_expression(self, node: es.UpdateExpression) -> str:
|
|
351
|
+
"""Generate update expression."""
|
|
352
|
+
arg = self.generate(node.argument)
|
|
353
|
+
if node.prefix:
|
|
354
|
+
return f"{node.operator}{arg}"
|
|
355
|
+
else:
|
|
356
|
+
return f"{arg}{node.operator}"
|
|
357
|
+
|
|
358
|
+
def gen_binary_expression(self, node: es.BinaryExpression) -> str:
|
|
359
|
+
"""Generate binary expression."""
|
|
360
|
+
left = self.generate(node.left)
|
|
361
|
+
right = self.generate(node.right)
|
|
362
|
+
if isinstance(node.left, es.AssignmentExpression):
|
|
363
|
+
left = f"({left})"
|
|
364
|
+
if isinstance(node.right, es.AssignmentExpression):
|
|
365
|
+
right = f"({right})"
|
|
366
|
+
return f"{left} {node.operator} {right}"
|
|
367
|
+
|
|
368
|
+
def gen_logical_expression(self, node: es.LogicalExpression) -> str:
|
|
369
|
+
"""Generate logical expression."""
|
|
370
|
+
left = self.generate(node.left)
|
|
371
|
+
right = self.generate(node.right)
|
|
372
|
+
return f"{left} {node.operator} {right}"
|
|
373
|
+
|
|
374
|
+
def gen_assignment_expression(self, node: es.AssignmentExpression) -> str:
|
|
375
|
+
"""Generate assignment expression."""
|
|
376
|
+
left = self.generate(node.left)
|
|
377
|
+
right = self.generate(node.right)
|
|
378
|
+
return f"{left} {node.operator} {right}"
|
|
379
|
+
|
|
380
|
+
def gen_member_expression(self, node: es.MemberExpression) -> str:
|
|
381
|
+
"""Generate member expression."""
|
|
382
|
+
obj = self.generate(node.object)
|
|
383
|
+
optional = "?." if node.optional else ""
|
|
384
|
+
if node.computed:
|
|
385
|
+
prop = self.generate(node.property)
|
|
386
|
+
return f"{obj}{optional}[{prop}]"
|
|
387
|
+
else:
|
|
388
|
+
prop = self.generate(node.property)
|
|
389
|
+
if optional:
|
|
390
|
+
return f"{obj}{optional}{prop}"
|
|
391
|
+
return f"{obj}.{prop}"
|
|
392
|
+
|
|
393
|
+
def gen_conditional_expression(self, node: es.ConditionalExpression) -> str:
|
|
394
|
+
"""Generate conditional expression."""
|
|
395
|
+
test = self.generate(node.test)
|
|
396
|
+
consequent = self.generate(node.consequent)
|
|
397
|
+
alternate = self.generate(node.alternate)
|
|
398
|
+
return f"{test} ? {consequent} : {alternate}"
|
|
399
|
+
|
|
400
|
+
def gen_call_expression(self, node: es.CallExpression) -> str:
|
|
401
|
+
"""Generate call expression."""
|
|
402
|
+
callee = self.generate(node.callee)
|
|
403
|
+
optional = "?." if node.optional else ""
|
|
404
|
+
args = ", ".join(self.generate(arg) for arg in node.arguments)
|
|
405
|
+
return f"{callee}{optional}({args})"
|
|
406
|
+
|
|
407
|
+
def gen_chain_expression(self, node: es.ChainExpression) -> str:
|
|
408
|
+
"""Generate optional chaining expression."""
|
|
409
|
+
return self.generate(node.expression)
|
|
410
|
+
|
|
411
|
+
def gen_new_expression(self, node: es.NewExpression) -> str:
|
|
412
|
+
"""Generate new expression."""
|
|
413
|
+
callee = self.generate(node.callee)
|
|
414
|
+
args = ", ".join(self.generate(arg) for arg in node.arguments)
|
|
415
|
+
return f"new {callee}({args})"
|
|
416
|
+
|
|
417
|
+
def gen_import_expression(self, node: es.ImportExpression) -> str:
|
|
418
|
+
"""Generate dynamic import expression."""
|
|
419
|
+
source = self.generate(node.source) if node.source else ""
|
|
420
|
+
return f"import({source})"
|
|
421
|
+
|
|
422
|
+
def gen_sequence_expression(self, node: es.SequenceExpression) -> str:
|
|
423
|
+
"""Generate sequence expression."""
|
|
424
|
+
exprs = ", ".join(self.generate(e) for e in node.expressions)
|
|
425
|
+
return f"({exprs})"
|
|
426
|
+
|
|
427
|
+
def gen_yield_expression(self, node: es.YieldExpression) -> str:
|
|
428
|
+
"""Generate yield expression."""
|
|
429
|
+
delegate = "*" if node.delegate else ""
|
|
430
|
+
if node.argument:
|
|
431
|
+
return f"yield{delegate} {self.generate(node.argument)}"
|
|
432
|
+
return f"yield{delegate}"
|
|
433
|
+
|
|
434
|
+
def gen_await_expression(self, node: es.AwaitExpression) -> str:
|
|
435
|
+
"""Generate await expression."""
|
|
436
|
+
return f"await {self.generate(node.argument)}"
|
|
437
|
+
|
|
438
|
+
def gen_template_literal(self, node: es.TemplateLiteral) -> str:
|
|
439
|
+
"""Generate template literal."""
|
|
440
|
+
parts: list[str] = []
|
|
441
|
+
for idx, quasi in enumerate(node.quasis):
|
|
442
|
+
parts.append(self.generate(quasi))
|
|
443
|
+
if idx < len(node.expressions):
|
|
444
|
+
parts.append(f"${{{self.generate(node.expressions[idx])}}}")
|
|
445
|
+
return f"`{''.join(parts)}`"
|
|
446
|
+
|
|
447
|
+
def gen_template_element(self, node: es.TemplateElement) -> str:
|
|
448
|
+
"""Generate template element."""
|
|
449
|
+
value = node.value.get("raw") if node.value else ""
|
|
450
|
+
return value or ""
|
|
451
|
+
|
|
452
|
+
def gen_tagged_template_expression(self, node: es.TaggedTemplateExpression) -> str:
|
|
453
|
+
"""Generate tagged template expression."""
|
|
454
|
+
tag = self.generate(node.tag)
|
|
455
|
+
quasi = self.generate(node.quasi)
|
|
456
|
+
return f"{tag}{quasi}"
|
|
457
|
+
|
|
458
|
+
def gen_spread_element(self, node: es.SpreadElement) -> str:
|
|
459
|
+
"""Generate spread element."""
|
|
460
|
+
return f"...{self.generate(node.argument)}"
|
|
461
|
+
|
|
462
|
+
def gen_super(self, node: es.Super) -> str:
|
|
463
|
+
"""Generate super."""
|
|
464
|
+
return "super"
|
|
465
|
+
|
|
466
|
+
def gen_meta_property(self, node: es.MetaProperty) -> str:
|
|
467
|
+
"""Generate meta property (e.g., new.target)."""
|
|
468
|
+
meta = self.generate(node.meta) if node.meta else ""
|
|
469
|
+
prop = self.generate(node.property) if node.property else ""
|
|
470
|
+
return f"{meta}.{prop}"
|
|
471
|
+
|
|
472
|
+
# Patterns
|
|
473
|
+
# ========
|
|
474
|
+
|
|
475
|
+
def gen_array_pattern(self, node: es.ArrayPattern) -> str:
|
|
476
|
+
"""Generate array pattern."""
|
|
477
|
+
elements = ", ".join(self.generate(e) if e else "" for e in node.elements)
|
|
478
|
+
return f"[{elements}]"
|
|
479
|
+
|
|
480
|
+
def gen_object_pattern(self, node: es.ObjectPattern) -> str:
|
|
481
|
+
"""Generate object pattern."""
|
|
482
|
+
props = ", ".join(self.generate(p) for p in node.properties)
|
|
483
|
+
return f"{{{props}}}"
|
|
484
|
+
|
|
485
|
+
def gen_assignment_pattern(self, node: es.AssignmentPattern) -> str:
|
|
486
|
+
"""Generate assignment pattern."""
|
|
487
|
+
left = self.generate(node.left)
|
|
488
|
+
right = self.generate(node.right)
|
|
489
|
+
return f"{left} = {right}"
|
|
490
|
+
|
|
491
|
+
def gen_rest_element(self, node: es.RestElement) -> str:
|
|
492
|
+
"""Generate rest element."""
|
|
493
|
+
return f"...{self.generate(node.argument)}"
|
|
494
|
+
|
|
495
|
+
# Modules
|
|
496
|
+
# =======
|
|
497
|
+
|
|
498
|
+
def gen_import_declaration(self, node: es.ImportDeclaration) -> str:
|
|
499
|
+
"""Generate import declaration."""
|
|
500
|
+
default_spec: str | None = None
|
|
501
|
+
namespace_spec: str | None = None
|
|
502
|
+
named_specs: list[str] = []
|
|
503
|
+
|
|
504
|
+
for spec in node.specifiers:
|
|
505
|
+
if isinstance(spec, es.ImportDefaultSpecifier):
|
|
506
|
+
default_spec = self.generate(spec)
|
|
507
|
+
elif isinstance(spec, es.ImportNamespaceSpecifier):
|
|
508
|
+
namespace_spec = self.generate(spec)
|
|
509
|
+
elif isinstance(spec, es.ImportSpecifier):
|
|
510
|
+
named_specs.append(self.generate(spec))
|
|
511
|
+
|
|
512
|
+
clause_parts: list[str] = []
|
|
513
|
+
if default_spec:
|
|
514
|
+
clause_parts.append(default_spec)
|
|
515
|
+
if namespace_spec:
|
|
516
|
+
clause_parts.append(namespace_spec)
|
|
517
|
+
if named_specs:
|
|
518
|
+
clause_parts.append("{ " + ", ".join(named_specs) + " }")
|
|
519
|
+
|
|
520
|
+
source = self.generate(node.source)
|
|
521
|
+
if clause_parts:
|
|
522
|
+
clause = ", ".join(clause_parts)
|
|
523
|
+
return f"{self.indent()}import {clause} from {source};"
|
|
524
|
+
return f"{self.indent()}import {source};"
|
|
525
|
+
|
|
526
|
+
def gen_import_specifier(self, node: es.ImportSpecifier) -> str:
|
|
527
|
+
"""Generate import specifier."""
|
|
528
|
+
imported = self.generate(node.imported)
|
|
529
|
+
local = self.generate(node.local)
|
|
530
|
+
if imported != local:
|
|
531
|
+
return f"{imported} as {local}"
|
|
532
|
+
return imported
|
|
533
|
+
|
|
534
|
+
def gen_import_default_specifier(self, node: es.ImportDefaultSpecifier) -> str:
|
|
535
|
+
"""Generate import default specifier."""
|
|
536
|
+
return self.generate(node.local)
|
|
537
|
+
|
|
538
|
+
def gen_import_namespace_specifier(self, node: es.ImportNamespaceSpecifier) -> str:
|
|
539
|
+
"""Generate import namespace specifier."""
|
|
540
|
+
return f"* as {self.generate(node.local)}"
|
|
541
|
+
|
|
542
|
+
def gen_export_named_declaration(self, node: es.ExportNamedDeclaration) -> str:
|
|
543
|
+
"""Generate export named declaration."""
|
|
544
|
+
if node.declaration:
|
|
545
|
+
return f"{self.indent()}export {self.generate(node.declaration).lstrip()}"
|
|
546
|
+
specs = ", ".join(self.generate(s) for s in node.specifiers)
|
|
547
|
+
if node.source:
|
|
548
|
+
source = self.generate(node.source)
|
|
549
|
+
return f"{self.indent()}export {{{specs}}} from {source};"
|
|
550
|
+
return f"{self.indent()}export {{{specs}}};"
|
|
551
|
+
|
|
552
|
+
def gen_export_specifier(self, node: es.ExportSpecifier) -> str:
|
|
553
|
+
"""Generate export specifier."""
|
|
554
|
+
local = self.generate(node.local)
|
|
555
|
+
exported = self.generate(node.exported)
|
|
556
|
+
if local != exported:
|
|
557
|
+
return f"{local} as {exported}"
|
|
558
|
+
return local
|
|
559
|
+
|
|
560
|
+
def gen_export_default_declaration(self, node: es.ExportDefaultDeclaration) -> str:
|
|
561
|
+
"""Generate export default declaration."""
|
|
562
|
+
return f"{self.indent()}export default {self.generate(node.declaration)};"
|
|
563
|
+
|
|
564
|
+
def gen_export_all_declaration(self, node: es.ExportAllDeclaration) -> str:
|
|
565
|
+
"""Generate export all declaration."""
|
|
566
|
+
source = self.generate(node.source)
|
|
567
|
+
if node.exported:
|
|
568
|
+
exported = self.generate(node.exported)
|
|
569
|
+
return f"{self.indent()}export * as {exported} from {source};"
|
|
570
|
+
return f"{self.indent()}export * from {source};"
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def es_to_js(node: es.Node, indent: str = " ") -> str:
|
|
574
|
+
"""Convert an ESTree node to JavaScript code."""
|
|
575
|
+
generator = JSCodeGenerator(indent=indent)
|
|
576
|
+
return generator.generate(node)
|