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/compiler/parser.py
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import keyword
|
|
6
|
-
import logging
|
|
7
6
|
import os
|
|
8
7
|
import sys
|
|
9
|
-
from
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from threading import Event
|
|
10
|
+
from typing import Callable, Optional, Sequence, TYPE_CHECKING, TypeAlias, TypeVar, cast
|
|
10
11
|
|
|
11
12
|
import jaclang.compiler.unitree as uni
|
|
12
13
|
from jaclang.compiler import TOKEN_MAP, jac_lark as jl
|
|
13
14
|
from jaclang.compiler.constant import EdgeDir, Tokens as Tok
|
|
14
15
|
from jaclang.compiler.passes.main import Transform
|
|
15
16
|
from jaclang.utils.helpers import ANSIColors
|
|
16
|
-
from jaclang.vendor.lark import Lark, Transformer, Tree, logger
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from jaclang.compiler.program import JacProgram
|
|
@@ -22,25 +22,70 @@ T = TypeVar("T", bound=uni.UniNode)
|
|
|
22
22
|
TL = TypeVar("TL", bound=(uni.UniNode | list))
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
@dataclass
|
|
26
|
+
class LarkParseInput:
|
|
27
|
+
"""Input for Lark parser transform."""
|
|
28
|
+
|
|
29
|
+
ir_value: str
|
|
30
|
+
on_error: Callable[[jl.UnexpectedInput], bool]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class LarkParseOutput:
|
|
35
|
+
"""Output from Lark parser transform."""
|
|
36
|
+
|
|
37
|
+
tree: jl.Tree[jl.Tree[str]]
|
|
38
|
+
comments: list[jl.Token]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class LarkParseTransform(Transform[LarkParseInput, LarkParseOutput]):
|
|
42
|
+
"""Transform for Lark parsing step."""
|
|
43
|
+
|
|
44
|
+
comment_cache: list[jl.Token] = []
|
|
45
|
+
parser = jl.Lark_StandAlone(
|
|
46
|
+
lexer_callbacks={"COMMENT": lambda comment: LarkParseTransform.comment_cache.append(comment)} # type: ignore
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def __init__(self, ir_in: LarkParseInput, prog: JacProgram) -> None:
|
|
50
|
+
"""Initialize Lark parser transform."""
|
|
51
|
+
Transform.__init__(self, ir_in=ir_in, prog=prog)
|
|
52
|
+
|
|
53
|
+
def transform(self, ir_in: LarkParseInput) -> LarkParseOutput:
|
|
54
|
+
"""Transform input IR by parsing with Lark."""
|
|
55
|
+
LarkParseTransform.comment_cache = []
|
|
56
|
+
tree = LarkParseTransform.parser.parse(ir_in.ir_value, on_error=ir_in.on_error)
|
|
57
|
+
return LarkParseOutput(
|
|
58
|
+
tree=tree,
|
|
59
|
+
comments=LarkParseTransform.comment_cache.copy(),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
25
63
|
class JacParser(Transform[uni.Source, uni.Module]):
|
|
26
64
|
"""Jac Parser."""
|
|
27
65
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
66
|
+
def __init__(
|
|
67
|
+
self, root_ir: uni.Source, prog: JacProgram, cancel_token: Event | None = None
|
|
68
|
+
) -> None:
|
|
31
69
|
"""Initialize parser."""
|
|
32
70
|
self.mod_path = root_ir.loc.mod_path
|
|
33
71
|
self.node_list: list[uni.UniNode] = []
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Transform.__init__(self, ir_in=root_ir, prog=prog)
|
|
72
|
+
self._node_ids: set[int] = set()
|
|
73
|
+
Transform.__init__(self, ir_in=root_ir, prog=prog, cancel_token=cancel_token)
|
|
37
74
|
|
|
38
75
|
def transform(self, ir_in: uni.Source) -> uni.Module:
|
|
39
76
|
"""Transform input IR."""
|
|
40
77
|
try:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
78
|
+
# Create input for Lark parser transform
|
|
79
|
+
lark_input = LarkParseInput(
|
|
80
|
+
ir_value=ir_in.value,
|
|
81
|
+
on_error=self.error_callback,
|
|
82
|
+
)
|
|
83
|
+
# Use LarkParseTransform instead of direct parser call
|
|
84
|
+
lark_transform = LarkParseTransform(ir_in=lark_input, prog=self.prog)
|
|
85
|
+
parse_output = lark_transform.ir_out
|
|
86
|
+
# Transform parse tree to AST
|
|
87
|
+
mod = JacParser.TreeToAST(parser=self).transform(parse_output.tree)
|
|
88
|
+
ir_in.comments = [self.proc_comment(i, mod) for i in parse_output.comments]
|
|
44
89
|
if not isinstance(mod, uni.Module):
|
|
45
90
|
raise self.ice()
|
|
46
91
|
if len(self.errors_had) != 0:
|
|
@@ -108,9 +153,14 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
108
153
|
|
|
109
154
|
def feed_current_token(iparser: jl.InteractiveParser, tok: jl.Token) -> bool:
|
|
110
155
|
"""Feed the current token to the parser."""
|
|
156
|
+
max_attempts = 100 # Prevent infinite loops
|
|
157
|
+
attempts = 0
|
|
111
158
|
while tok.type not in iparser.accepts():
|
|
159
|
+
if attempts >= max_attempts:
|
|
160
|
+
return False # Give up after too many attempts
|
|
112
161
|
if not try_feed_missing_token(iparser):
|
|
113
162
|
return False
|
|
163
|
+
attempts += 1
|
|
114
164
|
iparser.feed_token(tok)
|
|
115
165
|
return True
|
|
116
166
|
|
|
@@ -185,37 +235,6 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
185
235
|
print(error_label, end=" ", file=sys.stderr)
|
|
186
236
|
print(alrt.pretty_print(colors=colors), file=sys.stderr)
|
|
187
237
|
|
|
188
|
-
@staticmethod
|
|
189
|
-
def _comment_callback(comment: jl.Token) -> None:
|
|
190
|
-
JacParser.comment_cache.append(comment)
|
|
191
|
-
|
|
192
|
-
@staticmethod
|
|
193
|
-
def parse(
|
|
194
|
-
ir: str, on_error: Callable[[jl.UnexpectedInput], bool]
|
|
195
|
-
) -> tuple[jl.Tree[jl.Tree[str]], list[jl.Token]]:
|
|
196
|
-
"""Parse input IR."""
|
|
197
|
-
JacParser.comment_cache = []
|
|
198
|
-
return (
|
|
199
|
-
JacParser.parser.parse(ir, on_error=on_error),
|
|
200
|
-
JacParser.comment_cache,
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
@staticmethod
|
|
204
|
-
def make_dev() -> None:
|
|
205
|
-
"""Make parser in dev mode."""
|
|
206
|
-
JacParser.parser = Lark.open(
|
|
207
|
-
"jac.lark",
|
|
208
|
-
parser="lalr",
|
|
209
|
-
rel_to=__file__,
|
|
210
|
-
debug=True,
|
|
211
|
-
lexer_callbacks={"COMMENT": JacParser._comment_callback},
|
|
212
|
-
)
|
|
213
|
-
JacParser.JacTransformer = Transformer[Tree[str], uni.UniNode] # type: ignore
|
|
214
|
-
logger.setLevel(logging.DEBUG)
|
|
215
|
-
|
|
216
|
-
comment_cache: list[jl.Token] = []
|
|
217
|
-
|
|
218
|
-
parser = jl.Lark_StandAlone(lexer_callbacks={"COMMENT": _comment_callback}) # type: ignore
|
|
219
238
|
JacTransformer: TypeAlias = jl.Transformer[jl.Tree[str], uni.UniNode]
|
|
220
239
|
|
|
221
240
|
class TreeToAST(JacTransformer):
|
|
@@ -240,7 +259,9 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
240
259
|
|
|
241
260
|
def _node_update(self, node: T) -> T:
|
|
242
261
|
self.parse_ref.cur_node = node
|
|
243
|
-
|
|
262
|
+
node_id = id(node)
|
|
263
|
+
if node_id not in self.parse_ref._node_ids:
|
|
264
|
+
self.parse_ref._node_ids.add(node_id)
|
|
244
265
|
self.parse_ref.node_list.append(node)
|
|
245
266
|
return node
|
|
246
267
|
|
|
@@ -248,6 +269,8 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
248
269
|
self, tree: jl.Tree, new_children: None | list[uni.UniNode] = None
|
|
249
270
|
) -> uni.UniNode:
|
|
250
271
|
self.cur_nodes = new_children or tree.children # type: ignore[assignment]
|
|
272
|
+
if self.parse_ref.is_canceled():
|
|
273
|
+
raise StopIteration
|
|
251
274
|
try:
|
|
252
275
|
return self._node_update(super()._call_userfunc(tree, new_children))
|
|
253
276
|
finally:
|
|
@@ -367,17 +390,29 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
367
390
|
| STRING (tl_stmt_with_doc | toplevel_stmt)*
|
|
368
391
|
"""
|
|
369
392
|
doc = self.match(uni.String)
|
|
370
|
-
|
|
393
|
+
# Collect all statements, flattening lists from cl { ... } blocks
|
|
394
|
+
body: list[uni.ElementStmt] = []
|
|
395
|
+
flat_kids: list[uni.UniNode] = []
|
|
396
|
+
|
|
397
|
+
for node in self.cur_nodes:
|
|
398
|
+
if isinstance(node, list):
|
|
399
|
+
# This is a list from cl { } block
|
|
400
|
+
body.extend(node)
|
|
401
|
+
flat_kids.extend(node)
|
|
402
|
+
elif isinstance(node, uni.ElementStmt):
|
|
403
|
+
body.append(node)
|
|
404
|
+
flat_kids.append(node)
|
|
405
|
+
else:
|
|
406
|
+
flat_kids.append(node)
|
|
407
|
+
|
|
371
408
|
mod = uni.Module(
|
|
372
409
|
name=self.parse_ref.mod_path.split(os.path.sep)[-1].rstrip(".jac"),
|
|
373
410
|
source=self.parse_ref.ir_in,
|
|
374
411
|
doc=doc,
|
|
375
412
|
body=body,
|
|
376
413
|
terminals=self.terminals,
|
|
377
|
-
kid=
|
|
378
|
-
|
|
379
|
-
or [uni.EmptyToken(uni.Source("", self.parse_ref.mod_path))]
|
|
380
|
-
),
|
|
414
|
+
kid=flat_kids
|
|
415
|
+
or [uni.EmptyToken(uni.Source("", self.parse_ref.mod_path))],
|
|
381
416
|
)
|
|
382
417
|
return mod
|
|
383
418
|
|
|
@@ -392,19 +427,48 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
392
427
|
element.add_kids_left([doc])
|
|
393
428
|
return element
|
|
394
429
|
|
|
395
|
-
def
|
|
430
|
+
def onelang_stmt(self, _: None) -> uni.ElementStmt:
|
|
396
431
|
"""Grammar rule.
|
|
397
432
|
|
|
398
|
-
|
|
433
|
+
onelang_stmt: import_stmt
|
|
399
434
|
| archetype
|
|
400
435
|
| ability
|
|
401
436
|
| global_var
|
|
402
437
|
| free_code
|
|
403
|
-
| py_code_block
|
|
404
438
|
| test
|
|
439
|
+
| impl_def
|
|
440
|
+
| sem_def
|
|
405
441
|
"""
|
|
406
442
|
return self.consume(uni.ElementStmt)
|
|
407
443
|
|
|
444
|
+
def toplevel_stmt(self, _: None) -> uni.ElementStmt | list[uni.ElementStmt]:
|
|
445
|
+
"""Grammar rule.
|
|
446
|
+
|
|
447
|
+
toplevel_stmt: KW_CLIENT? onelang_stmt
|
|
448
|
+
| KW_CLIENT LBRACE onelang_stmt* RBRACE
|
|
449
|
+
| py_code_block
|
|
450
|
+
"""
|
|
451
|
+
client_tok = self.match_token(Tok.KW_CLIENT)
|
|
452
|
+
if client_tok:
|
|
453
|
+
lbrace = self.match_token(Tok.LBRACE)
|
|
454
|
+
if lbrace:
|
|
455
|
+
# Collect all statements in the block
|
|
456
|
+
elements: list[uni.ElementStmt] = []
|
|
457
|
+
while elem := self.match(uni.ElementStmt):
|
|
458
|
+
if isinstance(elem, uni.ClientFacingNode):
|
|
459
|
+
elem.is_client_decl = True
|
|
460
|
+
elements.append(elem)
|
|
461
|
+
self.consume(uni.Token) # RBRACE
|
|
462
|
+
return elements
|
|
463
|
+
else:
|
|
464
|
+
element = self.consume(uni.ElementStmt)
|
|
465
|
+
if isinstance(element, uni.ClientFacingNode):
|
|
466
|
+
element.is_client_decl = True
|
|
467
|
+
element.add_kids_left([client_tok])
|
|
468
|
+
return element
|
|
469
|
+
else:
|
|
470
|
+
return self.consume(uni.ElementStmt)
|
|
471
|
+
|
|
408
472
|
def global_var(self, _: None) -> uni.GlobalVars:
|
|
409
473
|
"""Grammar rule.
|
|
410
474
|
|
|
@@ -650,11 +714,12 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
650
714
|
def sem_def(self, _: None) -> uni.SemDef:
|
|
651
715
|
"""Grammar rule.
|
|
652
716
|
|
|
653
|
-
sem_def: KW_SEM dotted_name EQ
|
|
717
|
+
sem_def: KW_SEM dotted_name (EQ | KW_IS) STRING SEMI
|
|
654
718
|
"""
|
|
655
719
|
self.consume_token(Tok.KW_SEM)
|
|
656
720
|
target = self.extract_from_list(self.consume(list), uni.NameAtom)
|
|
657
|
-
self.
|
|
721
|
+
if not self.match_token(Tok.KW_IS):
|
|
722
|
+
self.consume_token(Tok.EQ)
|
|
658
723
|
value = self.consume(uni.String)
|
|
659
724
|
self.consume_token(Tok.SEMI)
|
|
660
725
|
return uni.SemDef(
|
|
@@ -860,14 +925,14 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
860
925
|
def ability_decl(self, _: None) -> uni.Ability:
|
|
861
926
|
"""Grammar rule.
|
|
862
927
|
|
|
863
|
-
ability_decl: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? named_ref
|
|
928
|
+
ability_decl: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? named_ref?
|
|
864
929
|
event_clause (block_tail | KW_ABSTRACT? SEMI)
|
|
865
930
|
"""
|
|
866
931
|
is_override = self.match_token(Tok.KW_OVERRIDE) is not None
|
|
867
932
|
is_static = self.match_token(Tok.KW_STATIC) is not None
|
|
868
933
|
self.consume_token(Tok.KW_CAN)
|
|
869
934
|
access = self.match(uni.SubTag)
|
|
870
|
-
name = self.
|
|
935
|
+
name = self.match(uni.NameAtom)
|
|
871
936
|
signature = self.consume(uni.EventSignature)
|
|
872
937
|
|
|
873
938
|
# Handle block_tail
|
|
@@ -1702,37 +1767,90 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
1702
1767
|
def lambda_expr(self, _: None) -> uni.LambdaExpr:
|
|
1703
1768
|
"""Grammar rule.
|
|
1704
1769
|
|
|
1705
|
-
lambda_expr: KW_LAMBDA func_decl_params? (RETURN_HINT expression)? COLON expression
|
|
1770
|
+
lambda_expr: KW_LAMBDA func_decl_params? (RETURN_HINT expression)? ( COLON expression | code_block )
|
|
1706
1771
|
"""
|
|
1707
1772
|
return_type: uni.Expr | None = None
|
|
1773
|
+
return_hint_tok: uni.Token | None = None
|
|
1708
1774
|
sig_kid: list[uni.UniNode] = []
|
|
1709
1775
|
self.consume_token(Tok.KW_LAMBDA)
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
)
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1776
|
+
param_nodes: list[uni.UniNode] | None = None
|
|
1777
|
+
signature = self.match(uni.FuncSignature)
|
|
1778
|
+
signature_created = False
|
|
1779
|
+
if not signature:
|
|
1780
|
+
if self.node_idx < len(self.cur_nodes) and isinstance(
|
|
1781
|
+
self.cur_nodes[self.node_idx], list
|
|
1782
|
+
):
|
|
1783
|
+
candidate: list[uni.UniNode] = self.cur_nodes[self.node_idx] # type: ignore[assignment]
|
|
1784
|
+
first = candidate[0] if candidate else None
|
|
1785
|
+
if not (
|
|
1786
|
+
isinstance(first, uni.Token) and first.name == Tok.LBRACE.name
|
|
1787
|
+
):
|
|
1788
|
+
param_nodes = self.consume(list)
|
|
1789
|
+
elif (
|
|
1790
|
+
self.node_idx < len(self.cur_nodes)
|
|
1791
|
+
and isinstance(self.cur_nodes[self.node_idx], uni.Token)
|
|
1792
|
+
and self.cur_nodes[self.node_idx].name == Tok.LPAREN.name
|
|
1793
|
+
):
|
|
1794
|
+
self.consume_token(Tok.LPAREN)
|
|
1795
|
+
param_nodes = self.match(list)
|
|
1796
|
+
self.consume_token(Tok.RPAREN)
|
|
1797
|
+
if return_hint_tok := self.match_token(Tok.RETURN_HINT):
|
|
1798
|
+
return_type = self.consume(uni.Expr)
|
|
1799
|
+
if param_nodes:
|
|
1800
|
+
sig_kid.extend(param_nodes)
|
|
1801
|
+
if return_hint_tok:
|
|
1802
|
+
sig_kid.append(return_hint_tok)
|
|
1803
|
+
if return_type:
|
|
1804
|
+
sig_kid.append(return_type)
|
|
1805
|
+
signature = (
|
|
1806
|
+
uni.FuncSignature(
|
|
1807
|
+
posonly_params=[],
|
|
1808
|
+
params=(
|
|
1809
|
+
self.extract_from_list(param_nodes, uni.ParamVar)
|
|
1810
|
+
if param_nodes
|
|
1811
|
+
else []
|
|
1812
|
+
),
|
|
1813
|
+
varargs=None,
|
|
1814
|
+
kwonlyargs=[],
|
|
1815
|
+
kwargs=None,
|
|
1816
|
+
return_type=return_type,
|
|
1817
|
+
kid=sig_kid,
|
|
1818
|
+
)
|
|
1819
|
+
if param_nodes or return_type
|
|
1820
|
+
else None
|
|
1730
1821
|
)
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1822
|
+
signature_created = signature is not None
|
|
1823
|
+
|
|
1824
|
+
# Check if body is a code block or expression
|
|
1825
|
+
block_nodes: list[uni.UniNode] | None = None
|
|
1826
|
+
if self.match_token(Tok.COLON):
|
|
1827
|
+
# Single-expression body
|
|
1828
|
+
body: uni.Expr | list[uni.CodeBlockStmt] = self.consume(uni.Expr)
|
|
1829
|
+
else:
|
|
1830
|
+
if self.node_idx < len(self.cur_nodes) and isinstance(
|
|
1831
|
+
self.cur_nodes[self.node_idx], list
|
|
1832
|
+
):
|
|
1833
|
+
block_nodes = self.consume(list)
|
|
1834
|
+
body = self.extract_from_list(block_nodes, uni.CodeBlockStmt)
|
|
1835
|
+
else:
|
|
1836
|
+
self.consume_token(Tok.LBRACE)
|
|
1837
|
+
body_stmts: list[uni.CodeBlockStmt] = []
|
|
1838
|
+
while not self.match_token(Tok.RBRACE):
|
|
1839
|
+
body_stmts.append(self.consume(uni.CodeBlockStmt))
|
|
1840
|
+
body = body_stmts
|
|
1841
|
+
|
|
1842
|
+
new_kid: list[uni.UniNode] = []
|
|
1843
|
+
for item in self.cur_nodes:
|
|
1844
|
+
if param_nodes is not None and item is param_nodes:
|
|
1845
|
+
continue
|
|
1846
|
+
if item is return_type or item is return_hint_tok:
|
|
1847
|
+
continue
|
|
1848
|
+
if block_nodes is not None and item is block_nodes:
|
|
1849
|
+
new_kid.extend(block_nodes)
|
|
1850
|
+
else:
|
|
1851
|
+
new_kid.append(item)
|
|
1852
|
+
if signature_created and signature:
|
|
1853
|
+
new_kid.insert(1, signature)
|
|
1736
1854
|
return uni.LambdaExpr(
|
|
1737
1855
|
signature=signature,
|
|
1738
1856
|
body=body,
|
|
@@ -1965,25 +2083,31 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
1965
2083
|
)
|
|
1966
2084
|
return self._binary_expr_unwind(self.cur_nodes)
|
|
1967
2085
|
|
|
2086
|
+
def await_expr(self, _: None) -> uni.Expr:
|
|
2087
|
+
"""Grammar rule.
|
|
2088
|
+
|
|
2089
|
+
await_expr: KW_AWAIT? pipe_call
|
|
2090
|
+
"""
|
|
2091
|
+
if self.match_token(Tok.KW_AWAIT):
|
|
2092
|
+
operand = self.consume(uni.Expr)
|
|
2093
|
+
return uni.AwaitExpr(
|
|
2094
|
+
target=operand,
|
|
2095
|
+
kid=self.cur_nodes,
|
|
2096
|
+
)
|
|
2097
|
+
return self._binary_expr_unwind(self.cur_nodes)
|
|
2098
|
+
|
|
1968
2099
|
def pipe_call(self, _: None) -> uni.Expr:
|
|
1969
2100
|
"""Grammar rule.
|
|
1970
2101
|
|
|
1971
|
-
pipe_call: (PIPE_FWD | A_PIPE_FWD | KW_SPAWN
|
|
2102
|
+
pipe_call: (PIPE_FWD | A_PIPE_FWD | KW_SPAWN)? atomic_chain
|
|
1972
2103
|
"""
|
|
1973
|
-
if len(self.cur_nodes) == 2:
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
elif op := self.match(uni.Token):
|
|
1981
|
-
operand = self.consume(uni.Expr)
|
|
1982
|
-
return uni.UnaryExpr(
|
|
1983
|
-
op=op,
|
|
1984
|
-
operand=operand,
|
|
1985
|
-
kid=self.cur_nodes,
|
|
1986
|
-
)
|
|
2104
|
+
if len(self.cur_nodes) == 2 and (op := self.match(uni.Token)):
|
|
2105
|
+
operand = self.consume(uni.Expr)
|
|
2106
|
+
return uni.UnaryExpr(
|
|
2107
|
+
op=op,
|
|
2108
|
+
operand=operand,
|
|
2109
|
+
kid=self.cur_nodes,
|
|
2110
|
+
)
|
|
1987
2111
|
return self._binary_expr_unwind(self.cur_nodes)
|
|
1988
2112
|
|
|
1989
2113
|
def aug_op(self, _: None) -> uni.Token:
|
|
@@ -1991,7 +2115,6 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
1991
2115
|
|
|
1992
2116
|
aug_op: RSHIFT_EQ
|
|
1993
2117
|
| LSHIFT_EQ
|
|
1994
|
-
| BW_NOT_EQ
|
|
1995
2118
|
| BW_XOR_EQ
|
|
1996
2119
|
| BW_OR_EQ
|
|
1997
2120
|
| BW_AND_EQ
|
|
@@ -2045,6 +2168,14 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2045
2168
|
atomic_call: atomic_chain LPAREN param_list? by_llm? RPAREN
|
|
2046
2169
|
"""
|
|
2047
2170
|
target = self.consume(uni.Expr)
|
|
2171
|
+
gencompr = self.match(uni.GenCompr)
|
|
2172
|
+
if gencompr:
|
|
2173
|
+
return uni.FuncCall(
|
|
2174
|
+
target=target,
|
|
2175
|
+
params=[gencompr],
|
|
2176
|
+
genai_call=None,
|
|
2177
|
+
kid=self.cur_nodes,
|
|
2178
|
+
)
|
|
2048
2179
|
self.consume_token(Tok.LPAREN)
|
|
2049
2180
|
params_sn = self.match(list)
|
|
2050
2181
|
genai_call = self.match(uni.Expr)
|
|
@@ -2115,13 +2246,19 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2115
2246
|
"""Grammar rule.
|
|
2116
2247
|
|
|
2117
2248
|
atom: named_ref
|
|
2118
|
-
| LPAREN (expression | yield_expr) RPAREN
|
|
2249
|
+
| LPAREN (expression | yield_expr | function_decl) RPAREN
|
|
2119
2250
|
| atom_collection
|
|
2120
2251
|
| atom_literal
|
|
2121
2252
|
| type_ref
|
|
2253
|
+
| jsx_element
|
|
2122
2254
|
"""
|
|
2123
2255
|
if self.match_token(Tok.LPAREN):
|
|
2124
|
-
|
|
2256
|
+
# Try to match expression first, then yield_expr, then function_decl
|
|
2257
|
+
value = self.match(uni.Expr)
|
|
2258
|
+
if value is None:
|
|
2259
|
+
value = self.match(uni.YieldExpr)
|
|
2260
|
+
if value is None:
|
|
2261
|
+
value = self.consume(uni.Ability)
|
|
2125
2262
|
self.consume_token(Tok.RPAREN)
|
|
2126
2263
|
return uni.AtomUnit(value=value, kid=self.cur_nodes)
|
|
2127
2264
|
return self.consume(uni.AtomExpr)
|
|
@@ -2186,58 +2323,142 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2186
2323
|
def fstring(self, _: None) -> uni.FString:
|
|
2187
2324
|
"""Grammar rule.
|
|
2188
2325
|
|
|
2189
|
-
fstring:
|
|
2190
|
-
|
|
2326
|
+
fstring: F_DQ_START fstr_dq_part* F_DQ_END
|
|
2327
|
+
| F_SQ_START fstr_sq_part* F_SQ_END
|
|
2191
2328
|
"""
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2329
|
+
fstring_configs = [
|
|
2330
|
+
([Tok.F_DQ_START, Tok.RF_DQ_START], Tok.F_DQ_END),
|
|
2331
|
+
([Tok.F_SQ_START, Tok.RF_SQ_START], Tok.F_SQ_END),
|
|
2332
|
+
([Tok.F_TDQ_START, Tok.RF_TDQ_START], Tok.F_TDQ_END),
|
|
2333
|
+
([Tok.F_TSQ_START, Tok.RF_TSQ_START], Tok.F_TSQ_END),
|
|
2334
|
+
]
|
|
2335
|
+
|
|
2336
|
+
for start_toks, end_tok in fstring_configs:
|
|
2337
|
+
if fstr := self._process_fstring(start_toks, end_tok):
|
|
2338
|
+
return fstr
|
|
2339
|
+
|
|
2340
|
+
raise self.ice()
|
|
2341
|
+
|
|
2342
|
+
def _process_fstring(
|
|
2343
|
+
self, start_tok: list[Tok], end_tok: Tok
|
|
2344
|
+
) -> Optional[uni.FString]:
|
|
2345
|
+
"""Process fstring nodes."""
|
|
2346
|
+
tok_start = self.match_token(start_tok[0]) or self.match_token(start_tok[1])
|
|
2347
|
+
if not tok_start:
|
|
2348
|
+
return None
|
|
2349
|
+
parts = []
|
|
2350
|
+
while part := self.match(uni.String) or self.match(uni.FormattedValue):
|
|
2351
|
+
parts.append(part)
|
|
2352
|
+
tok_end = self.consume_token(end_tok)
|
|
2195
2353
|
return uni.FString(
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
else []
|
|
2200
|
-
),
|
|
2354
|
+
start=tok_start,
|
|
2355
|
+
parts=parts,
|
|
2356
|
+
end=tok_end,
|
|
2201
2357
|
kid=self.flat_cur_nodes,
|
|
2202
2358
|
)
|
|
2203
2359
|
|
|
2204
|
-
def
|
|
2360
|
+
def fstr_dq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2205
2361
|
"""Grammar rule.
|
|
2206
2362
|
|
|
2207
|
-
|
|
2363
|
+
fstr_dq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2208
2364
|
"""
|
|
2209
|
-
|
|
2210
|
-
(
|
|
2211
|
-
i
|
|
2212
|
-
if isinstance(i, uni.String)
|
|
2213
|
-
else (
|
|
2214
|
-
uni.ExprStmt(expr=i, in_fstring=True, kid=[i])
|
|
2215
|
-
if isinstance(i, uni.Expr)
|
|
2216
|
-
else i
|
|
2217
|
-
)
|
|
2218
|
-
)
|
|
2219
|
-
for i in self.cur_nodes
|
|
2220
|
-
]
|
|
2221
|
-
return valid_parts
|
|
2365
|
+
return self._process_f_expr(Tok.F_TEXT_DQ, self.cur_nodes)
|
|
2222
2366
|
|
|
2223
|
-
def
|
|
2367
|
+
def fstr_sq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2224
2368
|
"""Grammar rule.
|
|
2225
2369
|
|
|
2226
|
-
|
|
2370
|
+
fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2227
2371
|
"""
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2372
|
+
return self._process_f_expr(Tok.F_TEXT_SQ, self.cur_nodes)
|
|
2373
|
+
|
|
2374
|
+
def fstr_tdq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2375
|
+
"""Grammar rule.
|
|
2376
|
+
|
|
2377
|
+
fstr_tdq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2378
|
+
"""
|
|
2379
|
+
return self._process_f_expr(Tok.F_TEXT_TDQ, self.cur_nodes)
|
|
2380
|
+
|
|
2381
|
+
def fstr_tsq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2382
|
+
"""Grammar rule.
|
|
2383
|
+
|
|
2384
|
+
fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2385
|
+
"""
|
|
2386
|
+
return self._process_f_expr(Tok.F_TEXT_TSQ, self.cur_nodes)
|
|
2387
|
+
|
|
2388
|
+
def rfstr_dq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2389
|
+
"""Grammar rule.
|
|
2390
|
+
|
|
2391
|
+
fstr_dq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2392
|
+
"""
|
|
2393
|
+
return self._process_f_expr(Tok.RF_TEXT_DQ, self.cur_nodes)
|
|
2394
|
+
|
|
2395
|
+
def rfstr_sq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2396
|
+
"""Grammar rule.
|
|
2397
|
+
|
|
2398
|
+
fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2399
|
+
"""
|
|
2400
|
+
return self._process_f_expr(Tok.RF_TEXT_SQ, self.cur_nodes)
|
|
2401
|
+
|
|
2402
|
+
def rfstr_tdq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2403
|
+
"""Grammar rule.
|
|
2404
|
+
|
|
2405
|
+
fstr_tdq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2406
|
+
"""
|
|
2407
|
+
return self._process_f_expr(Tok.RF_TEXT_TDQ, self.cur_nodes)
|
|
2408
|
+
|
|
2409
|
+
def rfstr_tsq_part(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2410
|
+
"""Grammar rule.
|
|
2411
|
+
|
|
2412
|
+
fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2413
|
+
"""
|
|
2414
|
+
return self._process_f_expr(Tok.RF_TEXT_TSQ, self.cur_nodes)
|
|
2415
|
+
|
|
2416
|
+
def fformat(self, _: None) -> uni.Token | uni.FormattedValue:
|
|
2417
|
+
"""Grammar rule.
|
|
2418
|
+
|
|
2419
|
+
fformat: F_FORMAT_TEXT | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE
|
|
2420
|
+
"""
|
|
2421
|
+
return self._process_f_expr(Tok.F_FORMAT_TEXT, self.cur_nodes)
|
|
2422
|
+
|
|
2423
|
+
def _process_f_expr(
|
|
2424
|
+
self, token: Tok, nodes: list[uni.UniNode]
|
|
2425
|
+
) -> uni.Token | uni.FormattedValue:
|
|
2426
|
+
"""Process fexpression nodes."""
|
|
2427
|
+
if (
|
|
2428
|
+
tok := self.match_token(token)
|
|
2429
|
+
or self.match_token(Tok.D_LBRACE)
|
|
2430
|
+
or self.match_token(Tok.D_RBRACE)
|
|
2431
|
+
):
|
|
2432
|
+
return tok
|
|
2433
|
+
else:
|
|
2434
|
+
conversion = -1
|
|
2435
|
+
format_spec = None
|
|
2436
|
+
self.consume_token(Tok.LBRACE)
|
|
2437
|
+
expr = self.consume(uni.Expr)
|
|
2438
|
+
if conv_tok := self.match_token(Tok.CONV):
|
|
2439
|
+
conversion = ord(conv_tok.value[1:])
|
|
2440
|
+
if self.match_token(Tok.COLON):
|
|
2441
|
+
parts = []
|
|
2442
|
+
while part := self.match(uni.String) or self.match(
|
|
2443
|
+
uni.FormattedValue
|
|
2444
|
+
):
|
|
2445
|
+
parts.append(part)
|
|
2446
|
+
if len(parts) == 1 and isinstance(parts[0], uni.String):
|
|
2447
|
+
format_spec = parts[0]
|
|
2448
|
+
elif parts:
|
|
2449
|
+
format_spec = uni.FString(
|
|
2450
|
+
start=None,
|
|
2451
|
+
parts=parts,
|
|
2452
|
+
end=None,
|
|
2453
|
+
kid=parts,
|
|
2454
|
+
)
|
|
2455
|
+
self.consume_token(Tok.RBRACE)
|
|
2456
|
+
return uni.FormattedValue(
|
|
2457
|
+
format_part=expr,
|
|
2458
|
+
conversion=conversion,
|
|
2459
|
+
format_spec=format_spec,
|
|
2460
|
+
kid=self.cur_nodes,
|
|
2237
2461
|
)
|
|
2238
|
-
for i in self.cur_nodes
|
|
2239
|
-
]
|
|
2240
|
-
return valid_parts
|
|
2241
2462
|
|
|
2242
2463
|
def list_val(self, _: None) -> uni.ListVal:
|
|
2243
2464
|
"""Grammar rule.
|
|
@@ -2468,7 +2689,7 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2468
2689
|
def assignment_list(self, _: None) -> list[uni.UniNode]:
|
|
2469
2690
|
"""Grammar rule.
|
|
2470
2691
|
|
|
2471
|
-
assignment_list: (
|
|
2692
|
+
assignment_list: (assignment | named_ref) (COMMA (assignment | named_ref))* COMMA?
|
|
2472
2693
|
"""
|
|
2473
2694
|
|
|
2474
2695
|
def name_to_assign(name_consume: uni.NameAtom) -> uni.Assignment:
|
|
@@ -2476,15 +2697,23 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2476
2697
|
target=[name_consume], value=None, type_tag=None, kid=[name_consume]
|
|
2477
2698
|
)
|
|
2478
2699
|
|
|
2479
|
-
|
|
2480
|
-
self.consume_token(Tok.COMMA)
|
|
2700
|
+
# Match first (assignment | named_ref)
|
|
2481
2701
|
if self.match(uni.Assignment):
|
|
2482
2702
|
pass
|
|
2483
2703
|
elif name_consume := self.match(uni.NameAtom):
|
|
2484
2704
|
self.cur_nodes[self.node_idx - 1] = name_to_assign(name_consume)
|
|
2485
2705
|
else:
|
|
2486
|
-
|
|
2487
|
-
|
|
2706
|
+
raise self.ice()
|
|
2707
|
+
|
|
2708
|
+
# Match (COMMA (assignment | named_ref))* COMMA?
|
|
2709
|
+
while self.match_token(Tok.COMMA):
|
|
2710
|
+
if self.match(uni.Assignment):
|
|
2711
|
+
pass
|
|
2712
|
+
elif name_consume := self.match(uni.NameAtom):
|
|
2713
|
+
self.cur_nodes[self.node_idx - 1] = name_to_assign(name_consume)
|
|
2714
|
+
else:
|
|
2715
|
+
break # trailing comma
|
|
2716
|
+
|
|
2488
2717
|
return self.flat_cur_nodes
|
|
2489
2718
|
|
|
2490
2719
|
def type_ref(self, kid: list[uni.UniNode]) -> uni.TypeRef:
|
|
@@ -2499,6 +2728,244 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2499
2728
|
kid=self.cur_nodes,
|
|
2500
2729
|
)
|
|
2501
2730
|
|
|
2731
|
+
def jsx_element(self, _: None) -> uni.JsxElement:
|
|
2732
|
+
"""Grammar rule.
|
|
2733
|
+
|
|
2734
|
+
jsx_element: jsx_self_closing
|
|
2735
|
+
| jsx_fragment
|
|
2736
|
+
| jsx_opening_closing
|
|
2737
|
+
"""
|
|
2738
|
+
return self.consume(uni.JsxElement)
|
|
2739
|
+
|
|
2740
|
+
def jsx_self_closing(self, _: None) -> uni.JsxElement:
|
|
2741
|
+
"""Grammar rule.
|
|
2742
|
+
|
|
2743
|
+
jsx_self_closing: JSX_OPEN_START jsx_element_name jsx_attributes? JSX_SELF_CLOSE
|
|
2744
|
+
"""
|
|
2745
|
+
self.consume_token(Tok.JSX_OPEN_START)
|
|
2746
|
+
name = self.consume(uni.JsxElementName)
|
|
2747
|
+
# jsx_attributes is optional and returns a list when present
|
|
2748
|
+
attrs_list = self.match(
|
|
2749
|
+
list
|
|
2750
|
+
) # Will match jsx_attributes which returns a list
|
|
2751
|
+
attrs = attrs_list if attrs_list else []
|
|
2752
|
+
self.consume_token(Tok.JSX_SELF_CLOSE)
|
|
2753
|
+
|
|
2754
|
+
return uni.JsxElement(
|
|
2755
|
+
name=name,
|
|
2756
|
+
attributes=attrs,
|
|
2757
|
+
children=None,
|
|
2758
|
+
is_self_closing=True,
|
|
2759
|
+
is_fragment=False,
|
|
2760
|
+
kid=self.flat_cur_nodes,
|
|
2761
|
+
)
|
|
2762
|
+
|
|
2763
|
+
def jsx_opening_closing(self, _: None) -> uni.JsxElement:
|
|
2764
|
+
"""Grammar rule.
|
|
2765
|
+
|
|
2766
|
+
jsx_opening_closing: jsx_opening_element jsx_children? jsx_closing_element
|
|
2767
|
+
"""
|
|
2768
|
+
opening = self.consume(uni.JsxElement) # From jsx_opening_element
|
|
2769
|
+
# jsx_children is optional and returns a list when present
|
|
2770
|
+
children_list = self.match(
|
|
2771
|
+
list
|
|
2772
|
+
) # Will match jsx_children which returns a list
|
|
2773
|
+
children = children_list if children_list else []
|
|
2774
|
+
self.consume(uni.JsxElement) # From jsx_closing_element (closing tag)
|
|
2775
|
+
|
|
2776
|
+
# Merge opening and closing into single element
|
|
2777
|
+
return uni.JsxElement(
|
|
2778
|
+
name=opening.name,
|
|
2779
|
+
attributes=opening.attributes,
|
|
2780
|
+
children=children if children else None,
|
|
2781
|
+
is_self_closing=False,
|
|
2782
|
+
is_fragment=False,
|
|
2783
|
+
kid=self.flat_cur_nodes,
|
|
2784
|
+
)
|
|
2785
|
+
|
|
2786
|
+
def jsx_fragment(self, _: None) -> uni.JsxElement:
|
|
2787
|
+
"""Grammar rule.
|
|
2788
|
+
|
|
2789
|
+
jsx_fragment: JSX_FRAG_OPEN jsx_children? JSX_FRAG_CLOSE
|
|
2790
|
+
"""
|
|
2791
|
+
self.consume_token(Tok.JSX_FRAG_OPEN)
|
|
2792
|
+
# jsx_children is optional and returns a list when present
|
|
2793
|
+
children_list = self.match(
|
|
2794
|
+
list
|
|
2795
|
+
) # Will match jsx_children which returns a list
|
|
2796
|
+
children = children_list if children_list else []
|
|
2797
|
+
self.consume_token(Tok.JSX_FRAG_CLOSE)
|
|
2798
|
+
|
|
2799
|
+
return uni.JsxElement(
|
|
2800
|
+
name=None,
|
|
2801
|
+
attributes=None,
|
|
2802
|
+
children=children if children else None,
|
|
2803
|
+
is_self_closing=False,
|
|
2804
|
+
is_fragment=True,
|
|
2805
|
+
kid=self.flat_cur_nodes,
|
|
2806
|
+
)
|
|
2807
|
+
|
|
2808
|
+
def jsx_opening_element(self, _: None) -> uni.JsxElement:
|
|
2809
|
+
"""Grammar rule.
|
|
2810
|
+
|
|
2811
|
+
jsx_opening_element: JSX_OPEN_START jsx_element_name jsx_attributes? JSX_TAG_END
|
|
2812
|
+
"""
|
|
2813
|
+
self.consume_token(Tok.JSX_OPEN_START)
|
|
2814
|
+
name = self.consume(uni.JsxElementName)
|
|
2815
|
+
# jsx_attributes is optional and returns a list when present
|
|
2816
|
+
attrs_list = self.match(
|
|
2817
|
+
list
|
|
2818
|
+
) # Will match jsx_attributes which returns a list
|
|
2819
|
+
attrs = attrs_list if attrs_list else []
|
|
2820
|
+
self.consume_token(Tok.JSX_TAG_END)
|
|
2821
|
+
|
|
2822
|
+
# Return partial element (will be completed in jsx_opening_closing)
|
|
2823
|
+
return uni.JsxElement(
|
|
2824
|
+
name=name,
|
|
2825
|
+
attributes=attrs,
|
|
2826
|
+
children=None,
|
|
2827
|
+
is_self_closing=False,
|
|
2828
|
+
is_fragment=False,
|
|
2829
|
+
kid=self.flat_cur_nodes,
|
|
2830
|
+
)
|
|
2831
|
+
|
|
2832
|
+
def jsx_closing_element(self, _: None) -> uni.JsxElement:
|
|
2833
|
+
"""Grammar rule.
|
|
2834
|
+
|
|
2835
|
+
jsx_closing_element: JSX_CLOSE_START jsx_element_name JSX_TAG_END
|
|
2836
|
+
"""
|
|
2837
|
+
self.consume_token(Tok.JSX_CLOSE_START)
|
|
2838
|
+
name = self.consume(uni.JsxElementName)
|
|
2839
|
+
self.consume_token(Tok.JSX_TAG_END)
|
|
2840
|
+
# Return stub element with just closing info
|
|
2841
|
+
return uni.JsxElement(
|
|
2842
|
+
name=name,
|
|
2843
|
+
attributes=None,
|
|
2844
|
+
children=None,
|
|
2845
|
+
is_self_closing=False,
|
|
2846
|
+
is_fragment=False,
|
|
2847
|
+
kid=self.cur_nodes,
|
|
2848
|
+
)
|
|
2849
|
+
|
|
2850
|
+
def jsx_element_name(self, _: None) -> uni.JsxElementName:
|
|
2851
|
+
"""Grammar rule.
|
|
2852
|
+
|
|
2853
|
+
jsx_element_name: JSX_NAME (DOT JSX_NAME)*
|
|
2854
|
+
"""
|
|
2855
|
+
parts = [self.consume_token(Tok.JSX_NAME)]
|
|
2856
|
+
while self.match_token(Tok.DOT):
|
|
2857
|
+
parts.append(self.consume_token(Tok.JSX_NAME))
|
|
2858
|
+
return uni.JsxElementName(
|
|
2859
|
+
parts=parts,
|
|
2860
|
+
kid=self.cur_nodes,
|
|
2861
|
+
)
|
|
2862
|
+
|
|
2863
|
+
def jsx_attributes(self, _: None) -> list[uni.JsxAttribute]:
|
|
2864
|
+
"""Grammar rule.
|
|
2865
|
+
|
|
2866
|
+
jsx_attributes: jsx_attribute+
|
|
2867
|
+
"""
|
|
2868
|
+
return self.consume_many(uni.JsxAttribute)
|
|
2869
|
+
|
|
2870
|
+
def jsx_attribute(self, _: None) -> uni.JsxAttribute:
|
|
2871
|
+
"""Grammar rule.
|
|
2872
|
+
|
|
2873
|
+
jsx_attribute: jsx_spread_attribute | jsx_normal_attribute
|
|
2874
|
+
"""
|
|
2875
|
+
return self.consume(uni.JsxAttribute)
|
|
2876
|
+
|
|
2877
|
+
def jsx_spread_attribute(self, _: None) -> uni.JsxSpreadAttribute:
|
|
2878
|
+
"""Grammar rule.
|
|
2879
|
+
|
|
2880
|
+
jsx_spread_attribute: LBRACE ELLIPSIS expression RBRACE
|
|
2881
|
+
"""
|
|
2882
|
+
self.consume_token(Tok.LBRACE)
|
|
2883
|
+
self.consume_token(Tok.ELLIPSIS)
|
|
2884
|
+
expr = self.consume(uni.Expr)
|
|
2885
|
+
self.consume_token(Tok.RBRACE)
|
|
2886
|
+
return uni.JsxSpreadAttribute(
|
|
2887
|
+
expr=expr,
|
|
2888
|
+
kid=self.cur_nodes,
|
|
2889
|
+
)
|
|
2890
|
+
|
|
2891
|
+
def jsx_normal_attribute(self, _: None) -> uni.JsxNormalAttribute:
|
|
2892
|
+
"""Grammar rule.
|
|
2893
|
+
|
|
2894
|
+
jsx_normal_attribute: JSX_NAME (EQ jsx_attr_value)?
|
|
2895
|
+
"""
|
|
2896
|
+
name = self.consume_token(Tok.JSX_NAME)
|
|
2897
|
+
value = None
|
|
2898
|
+
if self.match_token(Tok.EQ):
|
|
2899
|
+
value = self.consume(uni.Expr)
|
|
2900
|
+
return uni.JsxNormalAttribute(
|
|
2901
|
+
name=name,
|
|
2902
|
+
value=value,
|
|
2903
|
+
kid=self.cur_nodes,
|
|
2904
|
+
)
|
|
2905
|
+
|
|
2906
|
+
def jsx_attr_value(self, _: None) -> uni.String | uni.Expr:
|
|
2907
|
+
"""Grammar rule.
|
|
2908
|
+
|
|
2909
|
+
jsx_attr_value: STRING | LBRACE expression RBRACE
|
|
2910
|
+
"""
|
|
2911
|
+
if string := self.match(uni.String):
|
|
2912
|
+
return string
|
|
2913
|
+
self.consume_token(Tok.LBRACE)
|
|
2914
|
+
expr = self.consume(uni.Expr)
|
|
2915
|
+
self.consume_token(Tok.RBRACE)
|
|
2916
|
+
return expr
|
|
2917
|
+
|
|
2918
|
+
def jsx_children(self, _: None) -> list[uni.JsxChild]:
|
|
2919
|
+
"""Grammar rule.
|
|
2920
|
+
|
|
2921
|
+
jsx_children: jsx_child+
|
|
2922
|
+
"""
|
|
2923
|
+
# The grammar already produces a list of children
|
|
2924
|
+
# Just collect all JsxChild nodes from cur_nodes
|
|
2925
|
+
children = []
|
|
2926
|
+
while self.node_idx < len(self.cur_nodes):
|
|
2927
|
+
if isinstance(
|
|
2928
|
+
self.cur_nodes[self.node_idx], (uni.JsxChild, uni.JsxElement)
|
|
2929
|
+
):
|
|
2930
|
+
children.append(self.cur_nodes[self.node_idx]) # type: ignore[arg-type]
|
|
2931
|
+
self.node_idx += 1
|
|
2932
|
+
else:
|
|
2933
|
+
break
|
|
2934
|
+
return children
|
|
2935
|
+
|
|
2936
|
+
def jsx_child(self, _: None) -> uni.JsxChild:
|
|
2937
|
+
"""Grammar rule.
|
|
2938
|
+
|
|
2939
|
+
jsx_child: jsx_element | jsx_expression
|
|
2940
|
+
"""
|
|
2941
|
+
if jsx_elem := self.match(uni.JsxElement):
|
|
2942
|
+
return jsx_elem # type: ignore[return-value]
|
|
2943
|
+
return self.consume(uni.JsxChild)
|
|
2944
|
+
|
|
2945
|
+
def jsx_expression(self, _: None) -> uni.JsxExpression:
|
|
2946
|
+
"""Grammar rule.
|
|
2947
|
+
|
|
2948
|
+
jsx_expression: LBRACE expression RBRACE
|
|
2949
|
+
"""
|
|
2950
|
+
self.consume_token(Tok.LBRACE)
|
|
2951
|
+
expr = self.consume(uni.Expr)
|
|
2952
|
+
self.consume_token(Tok.RBRACE)
|
|
2953
|
+
return uni.JsxExpression(
|
|
2954
|
+
expr=expr,
|
|
2955
|
+
kid=self.cur_nodes,
|
|
2956
|
+
)
|
|
2957
|
+
|
|
2958
|
+
def jsx_text(self, _: None) -> uni.JsxText:
|
|
2959
|
+
"""Grammar rule.
|
|
2960
|
+
|
|
2961
|
+
jsx_text: JSX_TEXT
|
|
2962
|
+
"""
|
|
2963
|
+
text = self.consume_token(Tok.JSX_TEXT)
|
|
2964
|
+
return uni.JsxText(
|
|
2965
|
+
value=text,
|
|
2966
|
+
kid=self.cur_nodes,
|
|
2967
|
+
)
|
|
2968
|
+
|
|
2502
2969
|
def edge_ref_chain(self, _: None) -> uni.EdgeRefTrailer:
|
|
2503
2970
|
"""Grammar rule.
|
|
2504
2971
|
|
|
@@ -2946,6 +3413,36 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
2946
3413
|
value = self.consume(uni.MatchPattern)
|
|
2947
3414
|
return uni.MatchKVPair(key=pattern, value=value, kid=self.cur_nodes)
|
|
2948
3415
|
|
|
3416
|
+
def attr_pattern(self, _: None) -> uni.MatchValue:
|
|
3417
|
+
"""Grammar rule.
|
|
3418
|
+
|
|
3419
|
+
attr_pattern: NAME (DOT NAME)+
|
|
3420
|
+
"""
|
|
3421
|
+
name_idx = 0
|
|
3422
|
+
cur_element = self.consume(uni.NameAtom)
|
|
3423
|
+
name_idx += 1
|
|
3424
|
+
trailer: uni.AtomTrailer | None = None
|
|
3425
|
+
while dot := self.match_token(Tok.DOT):
|
|
3426
|
+
target = trailer if trailer else cur_element
|
|
3427
|
+
right = self.consume(uni.NameAtom)
|
|
3428
|
+
name_idx += 2
|
|
3429
|
+
trailer = uni.AtomTrailer(
|
|
3430
|
+
target=target,
|
|
3431
|
+
right=right,
|
|
3432
|
+
is_attr=True,
|
|
3433
|
+
is_null_ok=False,
|
|
3434
|
+
kid=[target, dot, right],
|
|
3435
|
+
)
|
|
3436
|
+
name = trailer if trailer else cur_element
|
|
3437
|
+
if not isinstance(name, (uni.NameAtom, uni.AtomTrailer)):
|
|
3438
|
+
raise TypeError(
|
|
3439
|
+
f"Expected name to be either NameAtom or AtomTrailer, got {type(name)}"
|
|
3440
|
+
)
|
|
3441
|
+
return uni.MatchValue(
|
|
3442
|
+
value=name,
|
|
3443
|
+
kid=[name, *self.flat_cur_nodes[name_idx:]],
|
|
3444
|
+
)
|
|
3445
|
+
|
|
2949
3446
|
def class_pattern(self, _: None) -> uni.MatchArch:
|
|
2950
3447
|
"""Grammar rule.
|
|
2951
3448
|
|
|
@@ -3049,13 +3546,23 @@ class JacParser(Transform[uni.Source, uni.Module]):
|
|
|
3049
3546
|
ret_type = uni.Int
|
|
3050
3547
|
elif token.type in [
|
|
3051
3548
|
Tok.STRING,
|
|
3052
|
-
Tok.
|
|
3053
|
-
Tok.
|
|
3054
|
-
Tok.
|
|
3549
|
+
Tok.D_LBRACE,
|
|
3550
|
+
Tok.D_RBRACE,
|
|
3551
|
+
Tok.F_TEXT_DQ,
|
|
3552
|
+
Tok.F_TEXT_SQ,
|
|
3553
|
+
Tok.F_TEXT_TDQ,
|
|
3554
|
+
Tok.F_TEXT_TSQ,
|
|
3555
|
+
Tok.RF_TEXT_DQ,
|
|
3556
|
+
Tok.RF_TEXT_SQ,
|
|
3557
|
+
Tok.RF_TEXT_TDQ,
|
|
3558
|
+
Tok.RF_TEXT_TSQ,
|
|
3559
|
+
Tok.F_FORMAT_TEXT,
|
|
3055
3560
|
]:
|
|
3056
3561
|
ret_type = uni.String
|
|
3057
|
-
if token.type == Tok.
|
|
3058
|
-
token.value =
|
|
3562
|
+
if token.type == Tok.D_LBRACE:
|
|
3563
|
+
token.value = "{"
|
|
3564
|
+
elif token.type == Tok.D_RBRACE:
|
|
3565
|
+
token.value = "}"
|
|
3059
3566
|
elif token.type == Tok.BOOL:
|
|
3060
3567
|
ret_type = uni.Bool
|
|
3061
3568
|
elif token.type == Tok.PYNLINE and isinstance(token.value, str):
|