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/unitree.py
CHANGED
|
@@ -18,6 +18,8 @@ from typing import (
|
|
|
18
18
|
Sequence,
|
|
19
19
|
Type,
|
|
20
20
|
TypeVar,
|
|
21
|
+
Union,
|
|
22
|
+
cast,
|
|
21
23
|
)
|
|
22
24
|
|
|
23
25
|
|
|
@@ -227,8 +229,12 @@ class UniNode:
|
|
|
227
229
|
return res
|
|
228
230
|
|
|
229
231
|
|
|
230
|
-
# Symbols can have
|
|
232
|
+
# Symbols can have multiple definitions but resolves decl to be the
|
|
231
233
|
# first such definition in a given scope.
|
|
234
|
+
# Symbols may exist without a parent symbol table (parent_tab=None),
|
|
235
|
+
# such as imports like 'from a.b.c {...}' or with alias.
|
|
236
|
+
# These symbols(a,b,c) are not inserted into symbol tables
|
|
237
|
+
# but are still used for go-to-def, find references, and rename.
|
|
232
238
|
class Symbol:
|
|
233
239
|
"""Symbol."""
|
|
234
240
|
|
|
@@ -236,7 +242,7 @@ class Symbol:
|
|
|
236
242
|
self,
|
|
237
243
|
defn: NameAtom,
|
|
238
244
|
access: SymbolAccess,
|
|
239
|
-
parent_tab: UniScopeNode,
|
|
245
|
+
parent_tab: Optional[UniScopeNode] = None,
|
|
240
246
|
imported: bool = False,
|
|
241
247
|
) -> None:
|
|
242
248
|
"""Initialize."""
|
|
@@ -277,7 +283,9 @@ class Symbol:
|
|
|
277
283
|
@property
|
|
278
284
|
def symbol_table(self) -> Optional[UniScopeNode]:
|
|
279
285
|
"""Get symbol table."""
|
|
280
|
-
|
|
286
|
+
if self.parent_tab:
|
|
287
|
+
return self.parent_tab.find_scope(self.sym_name)
|
|
288
|
+
return None
|
|
281
289
|
|
|
282
290
|
def add_defn(self, node: NameAtom) -> None:
|
|
283
291
|
"""Add defn."""
|
|
@@ -345,8 +353,7 @@ class UniScopeNode(UniNode):
|
|
|
345
353
|
else None
|
|
346
354
|
)
|
|
347
355
|
if force_overwrite or node.sym_name not in self.names_in_scope:
|
|
348
|
-
self.names_in_scope[node.sym_name] =
|
|
349
|
-
defn=node.name_spec,
|
|
356
|
+
self.names_in_scope[node.sym_name] = node.name_spec.create_symbol(
|
|
350
357
|
access=(
|
|
351
358
|
access_spec
|
|
352
359
|
if isinstance(access_spec, SymbolAccess)
|
|
@@ -570,6 +577,13 @@ class AstAccessNode(UniNode):
|
|
|
570
577
|
T = TypeVar("T", bound=UniNode)
|
|
571
578
|
|
|
572
579
|
|
|
580
|
+
class ClientFacingNode:
|
|
581
|
+
"""Mixin for nodes that can be marked as client-facing declarations."""
|
|
582
|
+
|
|
583
|
+
def __init__(self, is_client_decl: bool = False) -> None:
|
|
584
|
+
self.is_client_decl = is_client_decl
|
|
585
|
+
|
|
586
|
+
|
|
573
587
|
class AstDocNode(UniNode):
|
|
574
588
|
"""Nodes that have access."""
|
|
575
589
|
|
|
@@ -767,6 +781,16 @@ class NameAtom(AtomExpr, EnumBlockStmt):
|
|
|
767
781
|
def sym_category(self) -> SymbolType:
|
|
768
782
|
return self._sym_category
|
|
769
783
|
|
|
784
|
+
def create_symbol(
|
|
785
|
+
self,
|
|
786
|
+
access: SymbolAccess,
|
|
787
|
+
parent_tab: Optional[UniScopeNode] = None,
|
|
788
|
+
imported: bool = False,
|
|
789
|
+
) -> Symbol:
|
|
790
|
+
"""Create symbol."""
|
|
791
|
+
sym = Symbol(defn=self, access=access, parent_tab=parent_tab, imported=imported)
|
|
792
|
+
return sym
|
|
793
|
+
|
|
770
794
|
@property
|
|
771
795
|
def clean_type(self) -> str:
|
|
772
796
|
ret_type = self.expr_type.replace("builtins.", "").replace("NoType", "")
|
|
@@ -890,6 +914,7 @@ class Module(AstDocNode, UniScopeNode):
|
|
|
890
914
|
if not self.stub_only and (
|
|
891
915
|
self.loc.mod_path.endswith(".impl.jac")
|
|
892
916
|
or self.loc.mod_path.endswith(".test.jac")
|
|
917
|
+
or self.loc.mod_path.endswith(".cl.jac")
|
|
893
918
|
):
|
|
894
919
|
head_mod_name = self.name.split(".")[0]
|
|
895
920
|
potential_path = os.path.join(
|
|
@@ -899,7 +924,11 @@ class Module(AstDocNode, UniScopeNode):
|
|
|
899
924
|
if os.path.exists(potential_path) and potential_path != self.loc.mod_path:
|
|
900
925
|
return potential_path
|
|
901
926
|
annex_dir = os.path.split(os.path.dirname(self.loc.mod_path))[-1]
|
|
902
|
-
if
|
|
927
|
+
if (
|
|
928
|
+
annex_dir.endswith(".impl")
|
|
929
|
+
or annex_dir.endswith(".test")
|
|
930
|
+
or annex_dir.endswith(".cl")
|
|
931
|
+
):
|
|
903
932
|
head_mod_name = os.path.split(os.path.dirname(self.loc.mod_path))[
|
|
904
933
|
-1
|
|
905
934
|
].split(".")[0]
|
|
@@ -987,7 +1016,7 @@ class ProgramModule(UniNode):
|
|
|
987
1016
|
self.hub: dict[str, Module] = {self.loc.mod_path: main_mod} if main_mod else {}
|
|
988
1017
|
|
|
989
1018
|
|
|
990
|
-
class GlobalVars(ElementStmt, AstAccessNode):
|
|
1019
|
+
class GlobalVars(ClientFacingNode, ElementStmt, AstAccessNode):
|
|
991
1020
|
"""GlobalVars node type for Jac Ast."""
|
|
992
1021
|
|
|
993
1022
|
def __init__(
|
|
@@ -1003,6 +1032,7 @@ class GlobalVars(ElementStmt, AstAccessNode):
|
|
|
1003
1032
|
UniNode.__init__(self, kid=kid)
|
|
1004
1033
|
AstAccessNode.__init__(self, access=access)
|
|
1005
1034
|
AstDocNode.__init__(self, doc=doc)
|
|
1035
|
+
ClientFacingNode.__init__(self)
|
|
1006
1036
|
|
|
1007
1037
|
def normalize(self, deep: bool = False) -> bool:
|
|
1008
1038
|
res = True
|
|
@@ -1014,6 +1044,8 @@ class GlobalVars(ElementStmt, AstAccessNode):
|
|
|
1014
1044
|
new_kid: list[UniNode] = []
|
|
1015
1045
|
if self.doc:
|
|
1016
1046
|
new_kid.append(self.doc)
|
|
1047
|
+
if self.is_client_decl:
|
|
1048
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1017
1049
|
if self.is_frozen:
|
|
1018
1050
|
new_kid.append(self.gen_token(Tok.KW_LET))
|
|
1019
1051
|
else:
|
|
@@ -1028,7 +1060,7 @@ class GlobalVars(ElementStmt, AstAccessNode):
|
|
|
1028
1060
|
return res
|
|
1029
1061
|
|
|
1030
1062
|
|
|
1031
|
-
class Test(AstSymbolNode, ElementStmt, UniScopeNode):
|
|
1063
|
+
class Test(ClientFacingNode, AstSymbolNode, ElementStmt, UniScopeNode):
|
|
1032
1064
|
"""Test node type for Jac Ast."""
|
|
1033
1065
|
|
|
1034
1066
|
TEST_COUNT = 0
|
|
@@ -1074,6 +1106,7 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
|
|
|
1074
1106
|
)
|
|
1075
1107
|
AstDocNode.__init__(self, doc=doc)
|
|
1076
1108
|
UniScopeNode.__init__(self, name=self.sym_name)
|
|
1109
|
+
ClientFacingNode.__init__(self)
|
|
1077
1110
|
|
|
1078
1111
|
def normalize(self, deep: bool = False) -> bool:
|
|
1079
1112
|
res = True
|
|
@@ -1085,6 +1118,8 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
|
|
|
1085
1118
|
new_kid: list[UniNode] = []
|
|
1086
1119
|
if self.doc:
|
|
1087
1120
|
new_kid.append(self.doc)
|
|
1121
|
+
if self.is_client_decl:
|
|
1122
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1088
1123
|
new_kid.append(self.gen_token(Tok.KW_TEST))
|
|
1089
1124
|
new_kid.append(self.name)
|
|
1090
1125
|
new_kid.append(self.gen_token(Tok.LBRACE))
|
|
@@ -1095,7 +1130,7 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
|
|
|
1095
1130
|
return res
|
|
1096
1131
|
|
|
1097
1132
|
|
|
1098
|
-
class ModuleCode(ElementStmt, ArchBlockStmt, EnumBlockStmt):
|
|
1133
|
+
class ModuleCode(ClientFacingNode, ElementStmt, ArchBlockStmt, EnumBlockStmt):
|
|
1099
1134
|
"""ModuleCode node type for Jac Ast."""
|
|
1100
1135
|
|
|
1101
1136
|
def __init__(
|
|
@@ -1111,6 +1146,7 @@ class ModuleCode(ElementStmt, ArchBlockStmt, EnumBlockStmt):
|
|
|
1111
1146
|
UniNode.__init__(self, kid=kid)
|
|
1112
1147
|
AstDocNode.__init__(self, doc=doc)
|
|
1113
1148
|
EnumBlockStmt.__init__(self, is_enum_stmt=is_enum_stmt)
|
|
1149
|
+
ClientFacingNode.__init__(self)
|
|
1114
1150
|
|
|
1115
1151
|
def normalize(self, deep: bool = False) -> bool:
|
|
1116
1152
|
res = True
|
|
@@ -1122,6 +1158,8 @@ class ModuleCode(ElementStmt, ArchBlockStmt, EnumBlockStmt):
|
|
|
1122
1158
|
new_kid: list[UniNode] = []
|
|
1123
1159
|
if self.doc:
|
|
1124
1160
|
new_kid.append(self.doc)
|
|
1161
|
+
if self.is_client_decl:
|
|
1162
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1125
1163
|
new_kid.append(self.gen_token(Tok.KW_WITH))
|
|
1126
1164
|
new_kid.append(self.gen_token(Tok.KW_ENTRY))
|
|
1127
1165
|
if self.name:
|
|
@@ -1164,7 +1202,7 @@ class PyInlineCode(ElementStmt, ArchBlockStmt, EnumBlockStmt, CodeBlockStmt):
|
|
|
1164
1202
|
return res
|
|
1165
1203
|
|
|
1166
1204
|
|
|
1167
|
-
class Import(ElementStmt, CodeBlockStmt):
|
|
1205
|
+
class Import(ClientFacingNode, ElementStmt, CodeBlockStmt):
|
|
1168
1206
|
"""Import node type for Jac Ast."""
|
|
1169
1207
|
|
|
1170
1208
|
def __init__(
|
|
@@ -1182,6 +1220,7 @@ class Import(ElementStmt, CodeBlockStmt):
|
|
|
1182
1220
|
UniNode.__init__(self, kid=kid)
|
|
1183
1221
|
AstDocNode.__init__(self, doc=doc)
|
|
1184
1222
|
CodeBlockStmt.__init__(self)
|
|
1223
|
+
ClientFacingNode.__init__(self)
|
|
1185
1224
|
|
|
1186
1225
|
@property
|
|
1187
1226
|
def is_py(self) -> bool:
|
|
@@ -1235,6 +1274,8 @@ class Import(ElementStmt, CodeBlockStmt):
|
|
|
1235
1274
|
new_kid: list[UniNode] = []
|
|
1236
1275
|
if self.doc:
|
|
1237
1276
|
new_kid.append(self.doc)
|
|
1277
|
+
if self.is_client_decl:
|
|
1278
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1238
1279
|
if self.is_absorb:
|
|
1239
1280
|
new_kid.append(self.gen_token(Tok.KW_INCLUDE))
|
|
1240
1281
|
else:
|
|
@@ -1255,7 +1296,7 @@ class Import(ElementStmt, CodeBlockStmt):
|
|
|
1255
1296
|
return res
|
|
1256
1297
|
|
|
1257
1298
|
|
|
1258
|
-
class ModulePath(
|
|
1299
|
+
class ModulePath(UniNode):
|
|
1259
1300
|
"""ModulePath node type for Jac Ast."""
|
|
1260
1301
|
|
|
1261
1302
|
def __init__(
|
|
@@ -1269,33 +1310,36 @@ class ModulePath(AstSymbolNode):
|
|
|
1269
1310
|
self.level = level
|
|
1270
1311
|
self.alias = alias
|
|
1271
1312
|
self.abs_path: Optional[str] = None
|
|
1272
|
-
|
|
1273
|
-
name_spec = alias if alias else path[0] if path else None
|
|
1274
|
-
|
|
1275
1313
|
UniNode.__init__(self, kid=kid)
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
if not isinstance(name_spec, Name):
|
|
1284
|
-
raise ValueError("ModulePath should have a name spec. Impossible.")
|
|
1285
|
-
AstSymbolNode.__init__(
|
|
1286
|
-
self,
|
|
1287
|
-
sym_name=name_spec.sym_name,
|
|
1288
|
-
name_spec=name_spec,
|
|
1289
|
-
sym_category=SymbolType.MODULE,
|
|
1290
|
-
)
|
|
1314
|
+
|
|
1315
|
+
@property
|
|
1316
|
+
def is_import_from(self) -> bool:
|
|
1317
|
+
"""Check if this modulepath is from import."""
|
|
1318
|
+
if self.parent and isinstance(self.parent, Import):
|
|
1319
|
+
return self.parent.from_loc == self
|
|
1320
|
+
return False
|
|
1291
1321
|
|
|
1292
1322
|
@property
|
|
1293
1323
|
def dot_path_str(self) -> str:
|
|
1294
1324
|
"""Get path string."""
|
|
1295
1325
|
return ("." * self.level) + ".".join(
|
|
1296
|
-
[p.value for p in self.path] if self.path else [
|
|
1326
|
+
[p.value for p in self.path] if self.path else []
|
|
1297
1327
|
)
|
|
1298
1328
|
|
|
1329
|
+
def resolve_relative_path(self, target_item: Optional[str] = None) -> str:
|
|
1330
|
+
"""Convert an import target string into a relative file path."""
|
|
1331
|
+
target = self.dot_path_str + (f".{target_item}" if target_item else "")
|
|
1332
|
+
return resolve_relative_path(target, self.loc.mod_path)
|
|
1333
|
+
|
|
1334
|
+
def resolve_relative_path_list(self) -> list[str]:
|
|
1335
|
+
"""Convert an import target string into a relative file path."""
|
|
1336
|
+
parts = self.dot_path_str.split(".")
|
|
1337
|
+
paths = []
|
|
1338
|
+
for i in range(len(parts)):
|
|
1339
|
+
sub_path = ".".join(parts[: i + 1])
|
|
1340
|
+
paths.append(resolve_relative_path(sub_path, self.loc.mod_path))
|
|
1341
|
+
return paths
|
|
1342
|
+
|
|
1299
1343
|
def normalize(self, deep: bool = False) -> bool:
|
|
1300
1344
|
res = True
|
|
1301
1345
|
if deep:
|
|
@@ -1317,13 +1361,8 @@ class ModulePath(AstSymbolNode):
|
|
|
1317
1361
|
self.set_kids(nodes=new_kid)
|
|
1318
1362
|
return res
|
|
1319
1363
|
|
|
1320
|
-
def resolve_relative_path(self, target_item: Optional[str] = None) -> str:
|
|
1321
|
-
"""Convert an import target string into a relative file path."""
|
|
1322
|
-
target = self.dot_path_str + (f".{target_item}" if target_item else "")
|
|
1323
|
-
return resolve_relative_path(target, self.loc.mod_path)
|
|
1324
|
-
|
|
1325
1364
|
|
|
1326
|
-
class ModuleItem(
|
|
1365
|
+
class ModuleItem(UniNode):
|
|
1327
1366
|
"""ModuleItem node type for Jac Ast."""
|
|
1328
1367
|
|
|
1329
1368
|
def __init__(
|
|
@@ -1335,12 +1374,6 @@ class ModuleItem(AstSymbolNode):
|
|
|
1335
1374
|
self.name = name
|
|
1336
1375
|
self.alias = alias
|
|
1337
1376
|
UniNode.__init__(self, kid=kid)
|
|
1338
|
-
AstSymbolNode.__init__(
|
|
1339
|
-
self,
|
|
1340
|
-
sym_name=alias.sym_name if alias else name.sym_name,
|
|
1341
|
-
name_spec=alias or name,
|
|
1342
|
-
sym_category=SymbolType.MOD_VAR,
|
|
1343
|
-
)
|
|
1344
1377
|
self.abs_path: Optional[str] = None
|
|
1345
1378
|
|
|
1346
1379
|
@property
|
|
@@ -1371,6 +1404,7 @@ class ModuleItem(AstSymbolNode):
|
|
|
1371
1404
|
|
|
1372
1405
|
|
|
1373
1406
|
class Archetype(
|
|
1407
|
+
ClientFacingNode,
|
|
1374
1408
|
ArchSpec,
|
|
1375
1409
|
AstAccessNode,
|
|
1376
1410
|
ArchBlockStmt,
|
|
@@ -1412,10 +1446,10 @@ class Archetype(
|
|
|
1412
1446
|
ArchSpec.__init__(self, decorators=decorators)
|
|
1413
1447
|
UniScopeNode.__init__(self, name=self.sym_name)
|
|
1414
1448
|
CodeBlockStmt.__init__(self)
|
|
1449
|
+
ClientFacingNode.__init__(self)
|
|
1415
1450
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
body = (
|
|
1451
|
+
def _get_impl_resolved_body(self) -> list:
|
|
1452
|
+
return (
|
|
1419
1453
|
list(self.body)
|
|
1420
1454
|
if isinstance(self.body, Sequence)
|
|
1421
1455
|
else (
|
|
@@ -1425,8 +1459,23 @@ class Archetype(
|
|
|
1425
1459
|
else []
|
|
1426
1460
|
)
|
|
1427
1461
|
)
|
|
1462
|
+
|
|
1463
|
+
@property
|
|
1464
|
+
def is_abstract(self) -> bool:
|
|
1465
|
+
body = self._get_impl_resolved_body()
|
|
1428
1466
|
return any(isinstance(i, Ability) and i.is_abstract for i in body)
|
|
1429
1467
|
|
|
1468
|
+
def get_has_vars(self) -> list[HasVar]:
|
|
1469
|
+
body = self._get_impl_resolved_body()
|
|
1470
|
+
has_vars: list[HasVar] = []
|
|
1471
|
+
for node in body:
|
|
1472
|
+
if not isinstance(node, ArchHas):
|
|
1473
|
+
continue
|
|
1474
|
+
for has_ in node.vars:
|
|
1475
|
+
if isinstance(has_, HasVar):
|
|
1476
|
+
has_vars.append(has_)
|
|
1477
|
+
return has_vars
|
|
1478
|
+
|
|
1430
1479
|
def normalize(self, deep: bool = False) -> bool:
|
|
1431
1480
|
res = True
|
|
1432
1481
|
if deep:
|
|
@@ -1448,6 +1497,8 @@ class Archetype(
|
|
|
1448
1497
|
new_kid: list[UniNode] = []
|
|
1449
1498
|
if self.doc:
|
|
1450
1499
|
new_kid.append(self.doc)
|
|
1500
|
+
if self.is_client_decl:
|
|
1501
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1451
1502
|
if self.decorators:
|
|
1452
1503
|
new_kid.append(self.gen_token(Tok.DECOR_OP))
|
|
1453
1504
|
for idx, dec in enumerate(self.decorators):
|
|
@@ -1639,7 +1690,14 @@ class SemDef(ElementStmt, AstSymbolNode, UniScopeNode):
|
|
|
1639
1690
|
return res
|
|
1640
1691
|
|
|
1641
1692
|
|
|
1642
|
-
class Enum(
|
|
1693
|
+
class Enum(
|
|
1694
|
+
ClientFacingNode,
|
|
1695
|
+
ArchSpec,
|
|
1696
|
+
AstAccessNode,
|
|
1697
|
+
AstImplNeedingNode,
|
|
1698
|
+
ArchBlockStmt,
|
|
1699
|
+
UniScopeNode,
|
|
1700
|
+
):
|
|
1643
1701
|
"""Enum node type for Jac Ast."""
|
|
1644
1702
|
|
|
1645
1703
|
def __init__(
|
|
@@ -1666,6 +1724,7 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
|
|
|
1666
1724
|
AstDocNode.__init__(self, doc=doc)
|
|
1667
1725
|
ArchSpec.__init__(self, decorators=decorators)
|
|
1668
1726
|
UniScopeNode.__init__(self, name=self.sym_name)
|
|
1727
|
+
ClientFacingNode.__init__(self)
|
|
1669
1728
|
|
|
1670
1729
|
def normalize(self, deep: bool = False) -> bool:
|
|
1671
1730
|
res = True
|
|
@@ -1693,6 +1752,8 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
|
|
|
1693
1752
|
new_kid.append(self.gen_token(Tok.DECOR_OP))
|
|
1694
1753
|
if self.doc:
|
|
1695
1754
|
new_kid.append(self.doc)
|
|
1755
|
+
if self.is_client_decl:
|
|
1756
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1696
1757
|
new_kid.append(self.gen_token(Tok.KW_ENUM))
|
|
1697
1758
|
if self.access:
|
|
1698
1759
|
new_kid.append(self.access)
|
|
@@ -1723,6 +1784,7 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
|
|
|
1723
1784
|
|
|
1724
1785
|
|
|
1725
1786
|
class Ability(
|
|
1787
|
+
ClientFacingNode,
|
|
1726
1788
|
AstAccessNode,
|
|
1727
1789
|
ElementStmt,
|
|
1728
1790
|
AstAsyncNode,
|
|
@@ -1735,7 +1797,7 @@ class Ability(
|
|
|
1735
1797
|
|
|
1736
1798
|
def __init__(
|
|
1737
1799
|
self,
|
|
1738
|
-
name_ref: NameAtom,
|
|
1800
|
+
name_ref: Optional[NameAtom],
|
|
1739
1801
|
is_async: bool,
|
|
1740
1802
|
is_override: bool,
|
|
1741
1803
|
is_static: bool,
|
|
@@ -1756,10 +1818,36 @@ class Ability(
|
|
|
1756
1818
|
|
|
1757
1819
|
UniNode.__init__(self, kid=kid)
|
|
1758
1820
|
AstImplNeedingNode.__init__(self, body=body)
|
|
1821
|
+
|
|
1822
|
+
# Create a synthetic name_ref if none provided
|
|
1823
|
+
if name_ref is None:
|
|
1824
|
+
# Extract location info from kid for positioning
|
|
1825
|
+
# Note: kid should always contain at least KW_CAN token from parser
|
|
1826
|
+
first_tok = kid[0] if kid and isinstance(kid[0], Token) else None
|
|
1827
|
+
if first_tok is None:
|
|
1828
|
+
raise ValueError(
|
|
1829
|
+
"Cannot create synthetic name_ref without location info."
|
|
1830
|
+
)
|
|
1831
|
+
synthetic_name_ref = Name(
|
|
1832
|
+
orig_src=first_tok.orig_src,
|
|
1833
|
+
name=Tok.NAME,
|
|
1834
|
+
value=self.py_resolve_name(),
|
|
1835
|
+
line=first_tok.line_no,
|
|
1836
|
+
end_line=first_tok.end_line,
|
|
1837
|
+
col_start=first_tok.c_start,
|
|
1838
|
+
col_end=first_tok.c_end,
|
|
1839
|
+
pos_start=first_tok.pos_start,
|
|
1840
|
+
pos_end=first_tok.pos_end,
|
|
1841
|
+
is_enum_stmt=False,
|
|
1842
|
+
)
|
|
1843
|
+
name_spec_for_init: Name | NameAtom = synthetic_name_ref
|
|
1844
|
+
else:
|
|
1845
|
+
name_spec_for_init = name_ref
|
|
1846
|
+
|
|
1759
1847
|
AstSymbolNode.__init__(
|
|
1760
1848
|
self,
|
|
1761
1849
|
sym_name=self.py_resolve_name(),
|
|
1762
|
-
name_spec=
|
|
1850
|
+
name_spec=name_spec_for_init,
|
|
1763
1851
|
sym_category=SymbolType.ABILITY,
|
|
1764
1852
|
)
|
|
1765
1853
|
AstAccessNode.__init__(self, access=access)
|
|
@@ -1767,6 +1855,7 @@ class Ability(
|
|
|
1767
1855
|
AstAsyncNode.__init__(self, is_async=is_async)
|
|
1768
1856
|
UniScopeNode.__init__(self, name=self.sym_name)
|
|
1769
1857
|
CodeBlockStmt.__init__(self)
|
|
1858
|
+
ClientFacingNode.__init__(self)
|
|
1770
1859
|
|
|
1771
1860
|
@property
|
|
1772
1861
|
def is_method(self) -> bool:
|
|
@@ -1812,7 +1901,18 @@ class Ability(
|
|
|
1812
1901
|
return mn, mx
|
|
1813
1902
|
|
|
1814
1903
|
def py_resolve_name(self) -> str:
|
|
1815
|
-
if
|
|
1904
|
+
if self.name_ref is None:
|
|
1905
|
+
# Generate anonymous name based on event type and location
|
|
1906
|
+
event_type = (
|
|
1907
|
+
"entry"
|
|
1908
|
+
if isinstance(self.signature, EventSignature)
|
|
1909
|
+
and self.signature.event.name == Tok.KW_ENTRY
|
|
1910
|
+
else "exit"
|
|
1911
|
+
)
|
|
1912
|
+
return (
|
|
1913
|
+
f"__ability_{event_type}_{self.loc.first_line}_{self.loc.col_start}__"
|
|
1914
|
+
)
|
|
1915
|
+
elif isinstance(self.name_ref, Name):
|
|
1816
1916
|
return self.name_ref.value
|
|
1817
1917
|
elif isinstance(self.name_ref, SpecialVarRef):
|
|
1818
1918
|
return self.name_ref.py_resolve_name()
|
|
@@ -1822,7 +1922,7 @@ class Ability(
|
|
|
1822
1922
|
def normalize(self, deep: bool = False) -> bool:
|
|
1823
1923
|
res = True
|
|
1824
1924
|
if deep:
|
|
1825
|
-
res = self.name_ref.normalize(deep)
|
|
1925
|
+
res = self.name_ref.normalize(deep) if self.name_ref else res
|
|
1826
1926
|
res = res and self.access.normalize(deep) if self.access else res
|
|
1827
1927
|
res = res and self.signature.normalize(deep) if self.signature else res
|
|
1828
1928
|
if isinstance(self.body, ImplDef):
|
|
@@ -1838,6 +1938,8 @@ class Ability(
|
|
|
1838
1938
|
new_kid: list[UniNode] = []
|
|
1839
1939
|
if self.doc:
|
|
1840
1940
|
new_kid.append(self.doc)
|
|
1941
|
+
if self.is_client_decl:
|
|
1942
|
+
new_kid.append(self.gen_token(Tok.KW_CLIENT))
|
|
1841
1943
|
if self.decorators:
|
|
1842
1944
|
new_kid.append(self.gen_token(Tok.DECOR_OP))
|
|
1843
1945
|
for idx, dec in enumerate(self.decorators):
|
|
@@ -1858,7 +1960,8 @@ class Ability(
|
|
|
1858
1960
|
)
|
|
1859
1961
|
if self.access:
|
|
1860
1962
|
new_kid.append(self.access)
|
|
1861
|
-
|
|
1963
|
+
if self.name_ref:
|
|
1964
|
+
new_kid.append(self.name_ref)
|
|
1862
1965
|
if self.signature:
|
|
1863
1966
|
new_kid.append(self.signature)
|
|
1864
1967
|
if self.is_genai_ability:
|
|
@@ -1940,6 +2043,8 @@ class FuncSignature(UniNode):
|
|
|
1940
2043
|
new_kid = new_kid[:-1]
|
|
1941
2044
|
if not is_lambda:
|
|
1942
2045
|
new_kid.append(self.gen_token(Tok.RPAREN))
|
|
2046
|
+
elif not new_kid:
|
|
2047
|
+
new_kid.extend([self.gen_token(Tok.LPAREN), self.gen_token(Tok.RPAREN)])
|
|
1943
2048
|
if self.return_type:
|
|
1944
2049
|
new_kid.append(self.gen_token(Tok.RETURN_HINT))
|
|
1945
2050
|
new_kid.append(self.return_type)
|
|
@@ -2167,7 +2272,7 @@ class HasVar(AstSymbolNode, AstTypedVarNode):
|
|
|
2167
2272
|
return res
|
|
2168
2273
|
|
|
2169
2274
|
|
|
2170
|
-
class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
|
|
2275
|
+
class TypedCtxBlock(CodeBlockStmt, WalkerStmtOnlyNode, UniScopeNode):
|
|
2171
2276
|
"""TypedCtxBlock node type for Jac Ast."""
|
|
2172
2277
|
|
|
2173
2278
|
def __init__(
|
|
@@ -2181,6 +2286,7 @@ class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
|
|
|
2181
2286
|
UniNode.__init__(self, kid=kid)
|
|
2182
2287
|
UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
|
|
2183
2288
|
CodeBlockStmt.__init__(self)
|
|
2289
|
+
WalkerStmtOnlyNode.__init__(self)
|
|
2184
2290
|
|
|
2185
2291
|
def normalize(self, deep: bool = False) -> bool:
|
|
2186
2292
|
res = True
|
|
@@ -2959,6 +3065,8 @@ class Assignment(AstTypedVarNode, EnumBlockStmt, CodeBlockStmt):
|
|
|
2959
3065
|
res = res and self.type_tag.normalize(deep) if self.type_tag else res
|
|
2960
3066
|
res = res and self.aug_op.normalize(deep) if self.aug_op else res
|
|
2961
3067
|
new_kid: list[UniNode] = []
|
|
3068
|
+
if self.mutable and not self.is_enum_stmt:
|
|
3069
|
+
new_kid.append(self.gen_token(Tok.KW_LET))
|
|
2962
3070
|
for idx, targ in enumerate(self.target):
|
|
2963
3071
|
new_kid.append(targ)
|
|
2964
3072
|
if idx < len(self.target) - 1:
|
|
@@ -3105,12 +3213,15 @@ class LambdaExpr(Expr, UniScopeNode):
|
|
|
3105
3213
|
|
|
3106
3214
|
def __init__(
|
|
3107
3215
|
self,
|
|
3108
|
-
body: Expr,
|
|
3216
|
+
body: Union[Expr, Sequence[CodeBlockStmt]],
|
|
3109
3217
|
kid: Sequence[UniNode],
|
|
3110
3218
|
signature: Optional[FuncSignature] = None,
|
|
3111
3219
|
) -> None:
|
|
3112
3220
|
self.signature = signature
|
|
3113
|
-
|
|
3221
|
+
if isinstance(body, Sequence) and not isinstance(body, Expr):
|
|
3222
|
+
self.body: Expr | Sequence[CodeBlockStmt] = list(body)
|
|
3223
|
+
else:
|
|
3224
|
+
self.body = cast(Expr, body)
|
|
3114
3225
|
UniNode.__init__(self, kid=kid)
|
|
3115
3226
|
Expr.__init__(self)
|
|
3116
3227
|
UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
|
|
@@ -3119,11 +3230,21 @@ class LambdaExpr(Expr, UniScopeNode):
|
|
|
3119
3230
|
res = True
|
|
3120
3231
|
if deep:
|
|
3121
3232
|
res = self.signature.normalize(deep) if self.signature else res
|
|
3122
|
-
|
|
3233
|
+
if isinstance(self.body, list):
|
|
3234
|
+
for stmt in self.body:
|
|
3235
|
+
res = res and stmt.normalize(deep)
|
|
3236
|
+
elif isinstance(self.body, Expr):
|
|
3237
|
+
res = res and self.body.normalize(deep)
|
|
3123
3238
|
new_kid: list[UniNode] = [self.gen_token(Tok.KW_LAMBDA)]
|
|
3124
3239
|
if self.signature:
|
|
3125
3240
|
new_kid.append(self.signature)
|
|
3126
|
-
|
|
3241
|
+
# For code block lambdas, we add LBRACE, statements, RBRACE
|
|
3242
|
+
if isinstance(self.body, list):
|
|
3243
|
+
new_kid.append(self.gen_token(Tok.LBRACE))
|
|
3244
|
+
new_kid.extend(self.body)
|
|
3245
|
+
new_kid.append(self.gen_token(Tok.RBRACE))
|
|
3246
|
+
elif isinstance(self.body, Expr):
|
|
3247
|
+
new_kid += [self.gen_token(Tok.COLON), self.body]
|
|
3127
3248
|
self.set_kids(nodes=new_kid)
|
|
3128
3249
|
return res
|
|
3129
3250
|
|
|
@@ -3215,10 +3336,14 @@ class FString(AtomExpr):
|
|
|
3215
3336
|
|
|
3216
3337
|
def __init__(
|
|
3217
3338
|
self,
|
|
3218
|
-
|
|
3339
|
+
start: Optional[Token],
|
|
3340
|
+
parts: Sequence[String | FormattedValue],
|
|
3341
|
+
end: Optional[Token],
|
|
3219
3342
|
kid: Sequence[UniNode],
|
|
3220
3343
|
) -> None:
|
|
3221
|
-
self.
|
|
3344
|
+
self.start = start
|
|
3345
|
+
self.parts: list[String | FormattedValue] = list(parts)
|
|
3346
|
+
self.end = end
|
|
3222
3347
|
UniNode.__init__(self, kid=kid)
|
|
3223
3348
|
Expr.__init__(self)
|
|
3224
3349
|
AstSymbolStubNode.__init__(self, sym_type=SymbolType.STRING)
|
|
@@ -3228,28 +3353,53 @@ class FString(AtomExpr):
|
|
|
3228
3353
|
if deep:
|
|
3229
3354
|
for part in self.parts:
|
|
3230
3355
|
res = res and part.normalize(deep)
|
|
3231
|
-
new_kid: list[UniNode] =
|
|
3232
|
-
|
|
3233
|
-
isinstance(self.kid[0], Token) and self.kid[0].name == Tok.FSTR_SQ_START
|
|
3356
|
+
new_kid: list[UniNode] = (
|
|
3357
|
+
[self.gen_token(self.start)] if self.start is not None else []
|
|
3234
3358
|
)
|
|
3235
|
-
|
|
3236
|
-
new_kid.append(
|
|
3237
|
-
|
|
3238
|
-
new_kid.append(self.gen_token(
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3359
|
+
for part in self.parts:
|
|
3360
|
+
new_kid.append(part)
|
|
3361
|
+
if self.end is not None:
|
|
3362
|
+
new_kid.append(self.gen_token(self.end))
|
|
3363
|
+
self.set_kids(nodes=new_kid)
|
|
3364
|
+
return res
|
|
3365
|
+
|
|
3366
|
+
def unparse(self) -> str:
|
|
3367
|
+
valid = self.normalize()
|
|
3368
|
+
res = "".join([i.unparse() for i in self.kid])
|
|
3369
|
+
if not valid:
|
|
3370
|
+
raise NotImplementedError(f"Node {type(self).__name__} is not valid.")
|
|
3371
|
+
return res
|
|
3372
|
+
|
|
3373
|
+
|
|
3374
|
+
class FormattedValue(Expr):
|
|
3375
|
+
"""FormattedValue node type for Jac Ast."""
|
|
3376
|
+
|
|
3377
|
+
def __init__(
|
|
3378
|
+
self,
|
|
3379
|
+
format_part: Expr,
|
|
3380
|
+
conversion: int,
|
|
3381
|
+
format_spec: Expr | None,
|
|
3382
|
+
kid: Sequence[UniNode],
|
|
3383
|
+
) -> None:
|
|
3384
|
+
self.format_part: Expr = format_part
|
|
3385
|
+
self.conversion: int = conversion
|
|
3386
|
+
self.format_spec: Expr | None = format_spec
|
|
3387
|
+
UniNode.__init__(self, kid=kid)
|
|
3388
|
+
Expr.__init__(self)
|
|
3389
|
+
|
|
3390
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
3391
|
+
res = True
|
|
3392
|
+
if deep:
|
|
3393
|
+
res = self.format_part.normalize(deep)
|
|
3394
|
+
res = res and self.format_spec.normalize(deep) if self.format_spec else res
|
|
3395
|
+
new_kid: list[UniNode] = [self.gen_token(Tok.LBRACE)]
|
|
3396
|
+
new_kid.append(self.format_part)
|
|
3397
|
+
if self.conversion != -1:
|
|
3398
|
+
new_kid.append(self.gen_token(Tok.CONV, value="!" + chr(self.conversion)))
|
|
3399
|
+
if self.format_spec:
|
|
3400
|
+
new_kid.append(self.gen_token(Tok.COLON))
|
|
3401
|
+
new_kid.append(self.format_spec)
|
|
3402
|
+
new_kid.append(self.gen_token(Tok.RBRACE))
|
|
3253
3403
|
self.set_kids(nodes=new_kid)
|
|
3254
3404
|
return res
|
|
3255
3405
|
|
|
@@ -3643,7 +3793,7 @@ class AtomUnit(Expr):
|
|
|
3643
3793
|
|
|
3644
3794
|
def __init__(
|
|
3645
3795
|
self,
|
|
3646
|
-
value: Expr | YieldExpr,
|
|
3796
|
+
value: Expr | YieldExpr | Ability,
|
|
3647
3797
|
kid: Sequence[UniNode],
|
|
3648
3798
|
) -> None:
|
|
3649
3799
|
self.value = value
|
|
@@ -3712,7 +3862,10 @@ class FuncCall(Expr):
|
|
|
3712
3862
|
res = self.target.normalize(deep)
|
|
3713
3863
|
for prm in self.params:
|
|
3714
3864
|
res = res and prm.normalize(deep)
|
|
3715
|
-
new_kids = [self.target
|
|
3865
|
+
new_kids: list[UniNode] = [self.target]
|
|
3866
|
+
is_gencompr = len(self.params) == 1 and isinstance(self.params[0], GenCompr)
|
|
3867
|
+
if not is_gencompr:
|
|
3868
|
+
new_kids.append(self.gen_token(Tok.LPAREN))
|
|
3716
3869
|
for i, prm in enumerate(self.params):
|
|
3717
3870
|
new_kids.append(prm)
|
|
3718
3871
|
if i < len(self.params) - 1:
|
|
@@ -3720,7 +3873,8 @@ class FuncCall(Expr):
|
|
|
3720
3873
|
if self.genai_call:
|
|
3721
3874
|
new_kids.append(self.gen_token(Tok.KW_BY))
|
|
3722
3875
|
new_kids.append(self.genai_call)
|
|
3723
|
-
|
|
3876
|
+
if not is_gencompr:
|
|
3877
|
+
new_kids.append(self.gen_token(Tok.RPAREN, ")"))
|
|
3724
3878
|
self.set_kids(nodes=new_kids)
|
|
3725
3879
|
return res
|
|
3726
3880
|
|
|
@@ -4040,6 +4194,206 @@ class AssignCompr(AtomExpr):
|
|
|
4040
4194
|
return res
|
|
4041
4195
|
|
|
4042
4196
|
|
|
4197
|
+
# JSX Nodes
|
|
4198
|
+
# ---------
|
|
4199
|
+
|
|
4200
|
+
|
|
4201
|
+
class JsxElement(AtomExpr):
|
|
4202
|
+
"""JsxElement node type for Jac Ast."""
|
|
4203
|
+
|
|
4204
|
+
def __init__(
|
|
4205
|
+
self,
|
|
4206
|
+
name: Optional["JsxElementName"],
|
|
4207
|
+
attributes: Optional[Sequence["JsxAttribute"]],
|
|
4208
|
+
children: Optional[Sequence["JsxChild"]],
|
|
4209
|
+
is_self_closing: bool,
|
|
4210
|
+
is_fragment: bool,
|
|
4211
|
+
kid: Sequence[UniNode],
|
|
4212
|
+
) -> None:
|
|
4213
|
+
self.name = name
|
|
4214
|
+
self.attributes = list(attributes) if attributes else []
|
|
4215
|
+
self.children = list(children) if children else []
|
|
4216
|
+
self.is_self_closing = is_self_closing
|
|
4217
|
+
self.is_fragment = is_fragment
|
|
4218
|
+
UniNode.__init__(self, kid=kid)
|
|
4219
|
+
Expr.__init__(self)
|
|
4220
|
+
AstSymbolStubNode.__init__(self, sym_type=SymbolType.OBJECT_ARCH)
|
|
4221
|
+
|
|
4222
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4223
|
+
"""Normalize JSX element by recursively normalizing children.
|
|
4224
|
+
|
|
4225
|
+
Unlike most normalize methods, JSX elements don't need to rebuild
|
|
4226
|
+
their kid structure since the parser already creates it correctly.
|
|
4227
|
+
We just need to normalize child nodes if deep=True.
|
|
4228
|
+
"""
|
|
4229
|
+
res = True
|
|
4230
|
+
if deep:
|
|
4231
|
+
if self.name:
|
|
4232
|
+
res = res and self.name.normalize(deep)
|
|
4233
|
+
if self.attributes:
|
|
4234
|
+
for attr in self.attributes:
|
|
4235
|
+
res = res and attr.normalize(deep)
|
|
4236
|
+
if self.children:
|
|
4237
|
+
for child in self.children:
|
|
4238
|
+
res = res and child.normalize(deep)
|
|
4239
|
+
return res
|
|
4240
|
+
|
|
4241
|
+
|
|
4242
|
+
class JsxElementName(UniNode):
|
|
4243
|
+
"""JsxElementName node type for Jac Ast."""
|
|
4244
|
+
|
|
4245
|
+
def __init__(
|
|
4246
|
+
self,
|
|
4247
|
+
parts: Sequence[Name],
|
|
4248
|
+
kid: Sequence[UniNode],
|
|
4249
|
+
) -> None:
|
|
4250
|
+
self.parts = list(parts)
|
|
4251
|
+
UniNode.__init__(self, kid=kid)
|
|
4252
|
+
|
|
4253
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4254
|
+
res = True
|
|
4255
|
+
if deep:
|
|
4256
|
+
for part in self.parts:
|
|
4257
|
+
res = res and part.normalize(deep)
|
|
4258
|
+
new_kid: list[UniNode] = []
|
|
4259
|
+
for i, part in enumerate(self.parts):
|
|
4260
|
+
new_kid.append(part)
|
|
4261
|
+
if i < len(self.parts) - 1:
|
|
4262
|
+
new_kid.append(self.gen_token(Tok.DOT))
|
|
4263
|
+
self.set_kids(nodes=new_kid)
|
|
4264
|
+
return res
|
|
4265
|
+
|
|
4266
|
+
|
|
4267
|
+
class JsxAttribute(UniNode):
|
|
4268
|
+
"""JsxAttribute node type for Jac Ast (base class)."""
|
|
4269
|
+
|
|
4270
|
+
def __init__(self, kid: Sequence[UniNode]) -> None:
|
|
4271
|
+
UniNode.__init__(self, kid=kid)
|
|
4272
|
+
|
|
4273
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4274
|
+
"""Normalize the node (base implementation)."""
|
|
4275
|
+
# Base class normalize - subclasses should override if needed
|
|
4276
|
+
return True
|
|
4277
|
+
|
|
4278
|
+
|
|
4279
|
+
class JsxSpreadAttribute(JsxAttribute):
|
|
4280
|
+
"""JsxSpreadAttribute node type for Jac Ast."""
|
|
4281
|
+
|
|
4282
|
+
def __init__(
|
|
4283
|
+
self,
|
|
4284
|
+
expr: Expr,
|
|
4285
|
+
kid: Sequence[UniNode],
|
|
4286
|
+
) -> None:
|
|
4287
|
+
self.expr = expr
|
|
4288
|
+
JsxAttribute.__init__(self, kid=kid)
|
|
4289
|
+
|
|
4290
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4291
|
+
res = True
|
|
4292
|
+
if deep:
|
|
4293
|
+
res = self.expr.normalize(deep)
|
|
4294
|
+
new_kid: list[UniNode] = [
|
|
4295
|
+
self.gen_token(Tok.LBRACE),
|
|
4296
|
+
self.gen_token(Tok.ELLIPSIS),
|
|
4297
|
+
self.expr,
|
|
4298
|
+
self.gen_token(Tok.RBRACE),
|
|
4299
|
+
]
|
|
4300
|
+
self.set_kids(nodes=new_kid)
|
|
4301
|
+
return res
|
|
4302
|
+
|
|
4303
|
+
|
|
4304
|
+
class JsxNormalAttribute(JsxAttribute):
|
|
4305
|
+
"""JsxNormalAttribute node type for Jac Ast."""
|
|
4306
|
+
|
|
4307
|
+
def __init__(
|
|
4308
|
+
self,
|
|
4309
|
+
name: Name,
|
|
4310
|
+
value: Optional[Union[String, Expr]],
|
|
4311
|
+
kid: Sequence[UniNode],
|
|
4312
|
+
) -> None:
|
|
4313
|
+
self.name = name
|
|
4314
|
+
self.value = value
|
|
4315
|
+
JsxAttribute.__init__(self, kid=kid)
|
|
4316
|
+
|
|
4317
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4318
|
+
res = True
|
|
4319
|
+
if deep:
|
|
4320
|
+
res = self.name.normalize(deep)
|
|
4321
|
+
if self.value:
|
|
4322
|
+
res = res and self.value.normalize(deep)
|
|
4323
|
+
new_kid: list[UniNode] = [self.name]
|
|
4324
|
+
if self.value:
|
|
4325
|
+
new_kid.append(self.gen_token(Tok.EQ))
|
|
4326
|
+
if isinstance(self.value, String):
|
|
4327
|
+
new_kid.append(self.value)
|
|
4328
|
+
else: # Expression in braces
|
|
4329
|
+
new_kid.extend(
|
|
4330
|
+
[
|
|
4331
|
+
self.gen_token(Tok.LBRACE),
|
|
4332
|
+
self.value,
|
|
4333
|
+
self.gen_token(Tok.RBRACE),
|
|
4334
|
+
]
|
|
4335
|
+
)
|
|
4336
|
+
self.set_kids(nodes=new_kid)
|
|
4337
|
+
return res
|
|
4338
|
+
|
|
4339
|
+
|
|
4340
|
+
class JsxChild(UniNode):
|
|
4341
|
+
"""JsxChild node type for Jac Ast (base class)."""
|
|
4342
|
+
|
|
4343
|
+
def __init__(self, kid: Sequence[UniNode]) -> None:
|
|
4344
|
+
UniNode.__init__(self, kid=kid)
|
|
4345
|
+
|
|
4346
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4347
|
+
"""Normalize the node (base implementation)."""
|
|
4348
|
+
# Base class normalize - subclasses should override if needed
|
|
4349
|
+
return True
|
|
4350
|
+
|
|
4351
|
+
|
|
4352
|
+
class JsxText(JsxChild):
|
|
4353
|
+
"""JsxText node type for Jac Ast."""
|
|
4354
|
+
|
|
4355
|
+
def __init__(
|
|
4356
|
+
self,
|
|
4357
|
+
value: str,
|
|
4358
|
+
kid: Sequence[UniNode],
|
|
4359
|
+
) -> None:
|
|
4360
|
+
self.value = value
|
|
4361
|
+
JsxChild.__init__(self, kid=kid)
|
|
4362
|
+
|
|
4363
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4364
|
+
# JSX text is represented as a token
|
|
4365
|
+
if isinstance(self.value, Token):
|
|
4366
|
+
new_kid: list[UniNode] = [self.value]
|
|
4367
|
+
else:
|
|
4368
|
+
new_kid = [self.gen_token(Tok.JSX_TEXT, value=str(self.value))]
|
|
4369
|
+
self.set_kids(nodes=new_kid)
|
|
4370
|
+
return True
|
|
4371
|
+
|
|
4372
|
+
|
|
4373
|
+
class JsxExpression(JsxChild):
|
|
4374
|
+
"""JsxExpression node type for Jac Ast."""
|
|
4375
|
+
|
|
4376
|
+
def __init__(
|
|
4377
|
+
self,
|
|
4378
|
+
expr: Expr,
|
|
4379
|
+
kid: Sequence[UniNode],
|
|
4380
|
+
) -> None:
|
|
4381
|
+
self.expr = expr
|
|
4382
|
+
JsxChild.__init__(self, kid=kid)
|
|
4383
|
+
|
|
4384
|
+
def normalize(self, deep: bool = False) -> bool:
|
|
4385
|
+
res = True
|
|
4386
|
+
if deep:
|
|
4387
|
+
res = self.expr.normalize(deep)
|
|
4388
|
+
new_kid: list[UniNode] = [
|
|
4389
|
+
self.gen_token(Tok.LBRACE),
|
|
4390
|
+
self.expr,
|
|
4391
|
+
self.gen_token(Tok.RBRACE),
|
|
4392
|
+
]
|
|
4393
|
+
self.set_kids(nodes=new_kid)
|
|
4394
|
+
return res
|
|
4395
|
+
|
|
4396
|
+
|
|
4043
4397
|
# Match Nodes
|
|
4044
4398
|
# ------------
|
|
4045
4399
|
|
|
@@ -4646,6 +5000,8 @@ class String(Literal):
|
|
|
4646
5000
|
|
|
4647
5001
|
def unparse(self) -> str:
|
|
4648
5002
|
super().unparse()
|
|
5003
|
+
if self.parent and isinstance(self.parent, FString):
|
|
5004
|
+
return self.lit_value
|
|
4649
5005
|
return self.value
|
|
4650
5006
|
|
|
4651
5007
|
|