jaclang 0.8.0__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (77) hide show
  1. jaclang/cli/cli.py +11 -9
  2. jaclang/compiler/jac.lark +2 -12
  3. jaclang/compiler/larkparse/jac_parser.py +1 -1
  4. jaclang/compiler/parser.py +360 -521
  5. jaclang/compiler/passes/main/cfg_build_pass.py +2 -2
  6. jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
  7. jaclang/compiler/passes/main/def_use_pass.py +4 -7
  8. jaclang/compiler/passes/main/import_pass.py +3 -3
  9. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +196 -218
  11. jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
  13. jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
  14. jaclang/compiler/passes/main/sym_tab_link_pass.py +4 -4
  15. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
  16. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
  17. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +4 -2
  18. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +197 -120
  19. jaclang/compiler/program.py +2 -7
  20. jaclang/compiler/tests/fixtures/fam.jac +2 -2
  21. jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
  22. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
  23. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
  24. jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
  25. jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +11 -0
  26. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +7 -0
  27. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
  28. jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
  29. jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
  30. jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
  31. jaclang/compiler/tests/test_importer.py +20 -0
  32. jaclang/compiler/tests/test_parser.py +1 -0
  33. jaclang/compiler/unitree.py +456 -304
  34. jaclang/langserve/engine.jac +498 -0
  35. jaclang/langserve/sem_manager.jac +309 -0
  36. jaclang/langserve/server.jac +186 -0
  37. jaclang/langserve/tests/server_test/test_lang_serve.py +6 -7
  38. jaclang/langserve/tests/server_test/utils.py +4 -1
  39. jaclang/langserve/tests/session.jac +294 -0
  40. jaclang/langserve/tests/test_sem_tokens.py +2 -2
  41. jaclang/langserve/tests/test_server.py +12 -7
  42. jaclang/langserve/utils.jac +51 -30
  43. jaclang/runtimelib/archetype.py +1 -1
  44. jaclang/runtimelib/builtin.py +17 -14
  45. jaclang/runtimelib/importer.py +26 -8
  46. jaclang/runtimelib/machine.py +96 -55
  47. jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
  48. jaclang/runtimelib/utils.py +3 -3
  49. jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
  50. jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
  51. jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
  52. jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
  53. jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
  54. jaclang/tests/fixtures/concurrency.jac +1 -1
  55. jaclang/tests/fixtures/edge_ability.jac +49 -0
  56. jaclang/tests/fixtures/guess_game.jac +1 -1
  57. jaclang/tests/fixtures/here_usage_error.jac +21 -0
  58. jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
  59. jaclang/tests/fixtures/node_del.jac +30 -36
  60. jaclang/tests/fixtures/visit_traversal.jac +47 -0
  61. jaclang/tests/test_cli.py +12 -7
  62. jaclang/tests/test_language.py +91 -16
  63. jaclang/utils/helpers.py +14 -6
  64. jaclang/utils/lang_tools.py +2 -3
  65. jaclang/utils/tests/test_lang_tools.py +2 -1
  66. jaclang/utils/treeprinter.py +3 -4
  67. {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/METADATA +4 -3
  68. {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/RECORD +71 -55
  69. {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/WHEEL +1 -1
  70. jaclang/langserve/engine.py +0 -553
  71. jaclang/langserve/sem_manager.py +0 -383
  72. jaclang/langserve/server.py +0 -167
  73. jaclang/langserve/tests/session.py +0 -255
  74. jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
  75. jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
  76. /jaclang/langserve/{__init__.py → __init__.jac} +0 -0
  77. {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/entry_points.txt +0 -0
@@ -32,10 +32,10 @@ from jaclang.compiler.constant import (
32
32
  from jaclang.compiler.constant import DELIM_MAP, SymbolAccess, Tokens as Tok
33
33
  from jaclang.utils import resolve_relative_path
34
34
  from jaclang.utils.treeprinter import (
35
- dotgen_ast_tree,
36
- dotgen_symtab_tree,
37
35
  print_ast_tree,
38
36
  print_symtab_tree,
37
+ printgraph_ast_tree,
38
+ printgraph_symtab_tree,
39
39
  )
40
40
 
41
41
 
@@ -203,9 +203,9 @@ class UniNode:
203
203
  """Print ast."""
204
204
  return print_ast_tree(self, max_depth=depth)
205
205
 
206
- def dotgen(self) -> str:
206
+ def printgraph(self) -> str:
207
207
  """Print ast."""
208
- return dotgen_ast_tree(self)
208
+ return printgraph_ast_tree(self)
209
209
 
210
210
  def flatten(self) -> list[UniNode]:
211
211
  """Flatten ast."""
@@ -471,7 +471,7 @@ class UniScopeNode(UniNode):
471
471
  if isinstance(item.operand, AstSymbolNode):
472
472
  item.operand.name_spec.py_ctx_func = ast3.Store
473
473
  elif isinstance(item, (TupleVal, ListVal)):
474
- for i in item.values.items if item.values else []:
474
+ for i in item.values:
475
475
  if isinstance(i, AstSymbolNode):
476
476
  i.name_spec.py_ctx_func = ast3.Store
477
477
  elif isinstance(i, AtomTrailer):
@@ -484,7 +484,7 @@ class UniScopeNode(UniNode):
484
484
  def inherit_baseclasses_sym(self, node: Archetype | Enum) -> None:
485
485
  """Inherit base classes symbol tables."""
486
486
  if node.base_classes:
487
- for base_cls in node.base_classes.items:
487
+ for base_cls in node.base_classes:
488
488
  if (
489
489
  isinstance(base_cls, AstSymbolNode)
490
490
  and (found := self.use_lookup(base_cls))
@@ -501,9 +501,9 @@ class UniScopeNode(UniNode):
501
501
  """Pretty print."""
502
502
  return print_symtab_tree(root=self, depth=depth)
503
503
 
504
- def sym_dotgen(self) -> str:
504
+ def sym_printgraph(self) -> str:
505
505
  """Generate dot graph for sym table."""
506
- return dotgen_symtab_tree(self)
506
+ return printgraph_symtab_tree(self)
507
507
 
508
508
  def __repr__(self) -> str:
509
509
  """Repr."""
@@ -747,6 +747,9 @@ class ArchBlockStmt(UniNode):
747
747
  class EnumBlockStmt(UniNode):
748
748
  """EnumBlockStmt node type for Jac Ast."""
749
749
 
750
+ def __init__(self, is_enum_stmt: bool) -> None:
751
+ self.is_enum_stmt = is_enum_stmt
752
+
750
753
 
751
754
  class CodeBlockStmt(UniCFGNode):
752
755
  """CodeBlockStmt node type for Jac Ast."""
@@ -770,13 +773,14 @@ class AstImplNeedingNode(AstSymbolNode, Generic[T]):
770
773
  class NameAtom(AtomExpr, EnumBlockStmt):
771
774
  """NameAtom node type for Jac Ast."""
772
775
 
773
- def __init__(self) -> None:
776
+ def __init__(self, is_enum_stmt: bool) -> None:
774
777
  self.name_of: AstSymbolNode = self
775
778
  self._sym: Optional[Symbol] = None
776
779
  self._sym_name: str = ""
777
780
  self._sym_category: SymbolType = SymbolType.UNKNOWN
778
781
  self._py_ctx_func: Type[ast3.expr_context] = ast3.Load
779
782
  AtomExpr.__init__(self)
783
+ EnumBlockStmt.__init__(self, is_enum_stmt=is_enum_stmt)
780
784
 
781
785
  @property
782
786
  def sym(self) -> Optional[Symbol]:
@@ -849,7 +853,7 @@ class ArchSpec(ElementStmt, CodeBlockStmt, AstSymbolNode, AstDocNode):
849
853
  """ArchSpec node type for Jac Ast."""
850
854
 
851
855
  def __init__(
852
- self, decorators: Optional[SubNodeList[Expr]] = None, is_async: bool = False
856
+ self, decorators: Sequence[Expr] | None, is_async: bool = False
853
857
  ) -> None:
854
858
  self.decorators = decorators
855
859
  self.is_async = is_async
@@ -877,47 +881,6 @@ class SubTag(UniNode, Generic[T]):
877
881
  return res
878
882
 
879
883
 
880
- # SubNodeList were created to simplify the type safety of the
881
- # parser's implementation. We basically need to maintain tokens
882
- # of mixed type in the kid list of the subnodelist as well as
883
- # separating out typed items of interest in the ast node class body.
884
- class SubNodeList(UniNode, Generic[T]):
885
- """SubNodeList node type for Jac Ast."""
886
-
887
- def __init__(
888
- self,
889
- items: list[T],
890
- delim: Optional[Tok],
891
- kid: Sequence[UniNode],
892
- left_enc: Optional[Token] = None,
893
- right_enc: Optional[Token] = None,
894
- ) -> None:
895
- self.items: list[T] = items
896
- self.delim = delim
897
- self.left_enc = left_enc
898
- self.right_enc = right_enc
899
- UniNode.__init__(self, kid=kid)
900
-
901
- def normalize(self, deep: bool = False) -> bool:
902
- res = True
903
- if deep:
904
- for i in self.items:
905
- res = res and i.normalize()
906
- new_kid: list[UniNode] = []
907
- if self.left_enc:
908
- new_kid.append(self.left_enc)
909
- for i in self.items:
910
- new_kid.append(i)
911
- if self.delim:
912
- new_kid.append(self.gen_token(self.delim))
913
- if self.delim and self.items:
914
- new_kid.pop()
915
- if self.right_enc:
916
- new_kid.append(self.right_enc)
917
- self.set_kids(nodes=new_kid if len(new_kid) else [EmptyToken()])
918
- return res
919
-
920
-
921
884
  # AST Mid Level Node Types
922
885
  # --------------------------
923
886
  class Module(AstDocNode, UniScopeNode):
@@ -1053,7 +1016,7 @@ class GlobalVars(ElementStmt, AstAccessNode):
1053
1016
  def __init__(
1054
1017
  self,
1055
1018
  access: Optional[SubTag[Token]],
1056
- assignments: SubNodeList[Assignment],
1019
+ assignments: Sequence[Assignment],
1057
1020
  is_frozen: bool,
1058
1021
  kid: Sequence[UniNode],
1059
1022
  doc: Optional[String] = None,
@@ -1068,7 +1031,8 @@ class GlobalVars(ElementStmt, AstAccessNode):
1068
1031
  res = True
1069
1032
  if deep:
1070
1033
  res = self.access.normalize(deep) if self.access else True
1071
- res = res and self.assignments.normalize(deep)
1034
+ for assign in self.assignments:
1035
+ res = res and assign.normalize(deep)
1072
1036
  res = res and self.doc.normalize(deep) if self.doc else res
1073
1037
  new_kid: list[UniNode] = []
1074
1038
  if self.doc:
@@ -1079,7 +1043,10 @@ class GlobalVars(ElementStmt, AstAccessNode):
1079
1043
  new_kid.append(self.gen_token(Tok.KW_GLOBAL))
1080
1044
  if self.access:
1081
1045
  new_kid.append(self.access)
1082
- new_kid.append(self.assignments)
1046
+ for i, assign in enumerate(self.assignments):
1047
+ new_kid.append(assign)
1048
+ if i < len(self.assignments) - 1:
1049
+ new_kid.append(self.gen_token(Tok.COMMA))
1083
1050
  self.set_kids(nodes=new_kid)
1084
1051
  return res
1085
1052
 
@@ -1092,7 +1059,7 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
1092
1059
  def __init__(
1093
1060
  self,
1094
1061
  name: Name | Token,
1095
- body: SubNodeList[CodeBlockStmt],
1062
+ body: Sequence[CodeBlockStmt],
1096
1063
  kid: Sequence[UniNode],
1097
1064
  doc: Optional[String] = None,
1098
1065
  ) -> None:
@@ -1118,7 +1085,7 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
1118
1085
  if not self.name.value.startswith("test_")
1119
1086
  else self.name.value
1120
1087
  )
1121
- self.body = body
1088
+ self.body: list[CodeBlockStmt] = list(body)
1122
1089
  UniNode.__init__(self, kid=kid)
1123
1090
  if self.name not in self.kid:
1124
1091
  self.insert_kids_at_pos([self.name], pos=1, pos_update=False)
@@ -1135,14 +1102,18 @@ class Test(AstSymbolNode, ElementStmt, UniScopeNode):
1135
1102
  res = True
1136
1103
  if deep:
1137
1104
  res = self.name.normalize(deep)
1138
- res = res and self.body.normalize(deep)
1105
+ for stmt in self.body:
1106
+ res = res and stmt.normalize(deep)
1139
1107
  res = res and self.doc.normalize(deep) if self.doc else res
1140
1108
  new_kid: list[UniNode] = []
1141
1109
  if self.doc:
1142
1110
  new_kid.append(self.doc)
1143
1111
  new_kid.append(self.gen_token(Tok.KW_TEST))
1144
1112
  new_kid.append(self.name)
1145
- new_kid.append(self.body)
1113
+ new_kid.append(self.gen_token(Tok.LBRACE))
1114
+ for stmt in self.body:
1115
+ new_kid.append(stmt)
1116
+ new_kid.append(self.gen_token(Tok.RBRACE))
1146
1117
  self.set_kids(nodes=new_kid)
1147
1118
  return res
1148
1119
 
@@ -1153,20 +1124,23 @@ class ModuleCode(ElementStmt, ArchBlockStmt, EnumBlockStmt):
1153
1124
  def __init__(
1154
1125
  self,
1155
1126
  name: Optional[Name],
1156
- body: SubNodeList[CodeBlockStmt],
1127
+ body: Sequence[CodeBlockStmt],
1157
1128
  kid: Sequence[UniNode],
1129
+ is_enum_stmt: bool = False,
1158
1130
  doc: Optional[String] = None,
1159
1131
  ) -> None:
1160
1132
  self.name = name
1161
1133
  self.body = body
1162
1134
  UniNode.__init__(self, kid=kid)
1163
1135
  AstDocNode.__init__(self, doc=doc)
1136
+ EnumBlockStmt.__init__(self, is_enum_stmt=is_enum_stmt)
1164
1137
 
1165
1138
  def normalize(self, deep: bool = False) -> bool:
1166
1139
  res = True
1167
1140
  if deep:
1168
1141
  res = self.name.normalize(deep) if self.name else res
1169
- res = res and self.body.normalize(deep)
1142
+ for stmt in self.body:
1143
+ res = res and stmt.normalize(deep)
1170
1144
  res = res and self.doc.normalize(deep) if self.doc else res
1171
1145
  new_kid: list[UniNode] = []
1172
1146
  if self.doc:
@@ -1176,7 +1150,10 @@ class ModuleCode(ElementStmt, ArchBlockStmt, EnumBlockStmt):
1176
1150
  if self.name:
1177
1151
  new_kid.append(self.gen_token(Tok.COLON))
1178
1152
  new_kid.append(self.name)
1179
- new_kid.append(self.body)
1153
+ new_kid.append(self.gen_token(Tok.LBRACE))
1154
+ for stmt in self.body:
1155
+ new_kid.append(stmt)
1156
+ new_kid.append(self.gen_token(Tok.RBRACE))
1180
1157
  self.set_kids(nodes=new_kid)
1181
1158
  return res
1182
1159
 
@@ -1188,12 +1165,14 @@ class PyInlineCode(ElementStmt, ArchBlockStmt, EnumBlockStmt, CodeBlockStmt):
1188
1165
  self,
1189
1166
  code: Token,
1190
1167
  kid: Sequence[UniNode],
1168
+ is_enum_stmt: bool = False,
1191
1169
  doc: Optional[String] = None,
1192
1170
  ) -> None:
1193
1171
  self.code = code
1194
1172
  UniNode.__init__(self, kid=kid)
1195
1173
  AstDocNode.__init__(self, doc=doc)
1196
1174
  CodeBlockStmt.__init__(self)
1175
+ EnumBlockStmt.__init__(self, is_enum_stmt=is_enum_stmt)
1197
1176
 
1198
1177
  def normalize(self, deep: bool = False) -> bool:
1199
1178
  res = True
@@ -1214,7 +1193,7 @@ class Import(ElementStmt, CodeBlockStmt):
1214
1193
  def __init__(
1215
1194
  self,
1216
1195
  from_loc: Optional[ModulePath],
1217
- items: SubNodeList[ModuleItem] | SubNodeList[ModulePath],
1196
+ items: Sequence[ModuleItem] | Sequence[ModulePath],
1218
1197
  is_absorb: bool, # For includes
1219
1198
  kid: Sequence[UniNode],
1220
1199
  doc: Optional[String] = None,
@@ -1256,7 +1235,7 @@ class Import(ElementStmt, CodeBlockStmt):
1256
1235
  os.path.join(self.from_loc.resolve_relative_path(), "__init__.jac")
1257
1236
  ):
1258
1237
  return True
1259
- for i in self.items.items:
1238
+ for i in self.items:
1260
1239
  if isinstance(
1261
1240
  i, ModuleItem
1262
1241
  ) and self.from_loc.resolve_relative_path(i.name.value).endswith(
@@ -1265,7 +1244,7 @@ class Import(ElementStmt, CodeBlockStmt):
1265
1244
  return True
1266
1245
  return any(
1267
1246
  isinstance(i, ModulePath) and i.resolve_relative_path().endswith(".jac")
1268
- for i in self.items.items
1247
+ for i in self.items
1269
1248
  )
1270
1249
 
1271
1250
  def normalize(self, deep: bool = False) -> bool:
@@ -1273,7 +1252,8 @@ class Import(ElementStmt, CodeBlockStmt):
1273
1252
  if deep:
1274
1253
  res = self.hint.normalize(deep) if self.hint else res
1275
1254
  res = res and self.from_loc.normalize(deep) if self.from_loc else res
1276
- res = res and self.items.normalize(deep)
1255
+ for item in self.items:
1256
+ res = res and item.normalize(deep)
1277
1257
  res = res and self.doc.normalize(deep) if self.doc else res
1278
1258
  new_kid: list[UniNode] = []
1279
1259
  if self.doc:
@@ -1286,7 +1266,10 @@ class Import(ElementStmt, CodeBlockStmt):
1286
1266
  new_kid.append(self.gen_token(Tok.KW_FROM))
1287
1267
  new_kid.append(self.from_loc)
1288
1268
  new_kid.append(self.gen_token(Tok.LBRACE))
1289
- new_kid.append(self.items)
1269
+ for idx, itm in enumerate(self.items):
1270
+ new_kid.append(itm)
1271
+ if idx < len(self.items) - 1:
1272
+ new_kid.append(self.gen_token(Tok.COMMA))
1290
1273
  if self.from_loc:
1291
1274
  new_kid.append(self.gen_token(Tok.RBRACE))
1292
1275
  else:
@@ -1300,7 +1283,7 @@ class ModulePath(AstSymbolNode):
1300
1283
 
1301
1284
  def __init__(
1302
1285
  self,
1303
- path: Optional[SubNodeList[Name]],
1286
+ path: Optional[Sequence[Name]],
1304
1287
  level: int,
1305
1288
  alias: Optional[Name],
1306
1289
  kid: Sequence[UniNode],
@@ -1310,7 +1293,7 @@ class ModulePath(AstSymbolNode):
1310
1293
  self.alias = alias
1311
1294
  self.abs_path: Optional[str] = None
1312
1295
 
1313
- name_spec = alias if alias else path.items[0] if path else None
1296
+ name_spec = alias if alias else path[0] if path else None
1314
1297
 
1315
1298
  UniNode.__init__(self, kid=kid)
1316
1299
  if not name_spec:
@@ -1333,21 +1316,24 @@ class ModulePath(AstSymbolNode):
1333
1316
  def dot_path_str(self) -> str:
1334
1317
  """Get path string."""
1335
1318
  return ("." * self.level) + ".".join(
1336
- [p.value for p in self.path.items]
1337
- if self.path
1338
- else [self.name_spec.sym_name]
1319
+ [p.value for p in self.path] if self.path else [self.name_spec.sym_name]
1339
1320
  )
1340
1321
 
1341
1322
  def normalize(self, deep: bool = False) -> bool:
1342
1323
  res = True
1343
1324
  if deep:
1344
- res = self.path.normalize(deep) if self.path else res
1325
+ if self.path:
1326
+ for item in self.path:
1327
+ res = res and item.normalize(deep)
1345
1328
  res = res and self.alias.normalize(deep) if self.alias else res
1346
1329
  new_kid: list[UniNode] = []
1347
1330
  for _ in range(self.level):
1348
1331
  new_kid.append(self.gen_token(Tok.DOT))
1349
1332
  if self.path:
1350
- new_kid.append(self.path)
1333
+ for idx, item in enumerate(self.path):
1334
+ new_kid.append(item)
1335
+ if idx < len(self.path) - 1:
1336
+ new_kid.append(self.gen_token(Tok.DOT))
1351
1337
  if self.alias:
1352
1338
  new_kid.append(self.gen_token(Tok.KW_AS))
1353
1339
  new_kid.append(self.alias)
@@ -1426,15 +1412,15 @@ class Archetype(
1426
1412
  name: Name,
1427
1413
  arch_type: Token,
1428
1414
  access: Optional[SubTag[Token]],
1429
- base_classes: Optional[SubNodeList[Expr]],
1430
- body: Optional[SubNodeList[ArchBlockStmt] | ImplDef],
1415
+ base_classes: Sequence[Expr] | None,
1416
+ body: Sequence[ArchBlockStmt] | ImplDef | None,
1431
1417
  kid: Sequence[UniNode],
1432
1418
  doc: Optional[String] = None,
1433
- decorators: Optional[SubNodeList[Expr]] = None,
1419
+ decorators: Sequence[Expr] | None = None,
1434
1420
  ) -> None:
1435
1421
  self.name = name
1436
1422
  self.arch_type = arch_type
1437
- self.base_classes = base_classes
1423
+ self.base_classes: list[Expr] = list(base_classes) if base_classes else []
1438
1424
  UniNode.__init__(self, kid=kid)
1439
1425
  AstSymbolNode.__init__(
1440
1426
  self,
@@ -1468,12 +1454,12 @@ class Archetype(
1468
1454
  @property
1469
1455
  def is_abstract(self) -> bool:
1470
1456
  body = (
1471
- self.body.items
1472
- if isinstance(self.body, SubNodeList)
1457
+ list(self.body)
1458
+ if isinstance(self.body, Sequence)
1473
1459
  else (
1474
- self.body.body.items
1460
+ list(self.body.body)
1475
1461
  if isinstance(self.body, ImplDef)
1476
- and isinstance(self.body.body, SubNodeList)
1462
+ and isinstance(self.body.body, Sequence)
1477
1463
  else []
1478
1464
  )
1479
1465
  )
@@ -1485,18 +1471,27 @@ class Archetype(
1485
1471
  res = self.name.normalize(deep)
1486
1472
  res = res and self.arch_type.normalize(deep)
1487
1473
  res = res and self.access.normalize(deep) if self.access else res
1488
- res = (
1489
- res and self.base_classes.normalize(deep) if self.base_classes else res
1490
- )
1491
- res = res and self.body.normalize(deep) if self.body else res
1474
+ for base in self.base_classes:
1475
+ res = res and base.normalize(deep)
1476
+ if isinstance(self.body, ImplDef):
1477
+ res = res and self.body.normalize(deep)
1478
+ elif isinstance(self.body, Sequence):
1479
+ for stmt in self.body:
1480
+ res = res and stmt.normalize(deep)
1481
+ else:
1482
+ res = res and self.body.normalize(deep) if self.body else res
1492
1483
  res = res and self.doc.normalize(deep) if self.doc else res
1493
- res = res and self.decorators.normalize(deep) if self.decorators else res
1484
+ for dec in self.decorators or []:
1485
+ res = res and dec.normalize(deep)
1494
1486
  new_kid: list[UniNode] = []
1495
1487
  if self.doc:
1496
1488
  new_kid.append(self.doc)
1497
1489
  if self.decorators:
1498
1490
  new_kid.append(self.gen_token(Tok.DECOR_OP))
1499
- new_kid.append(self.decorators)
1491
+ for idx, dec in enumerate(self.decorators):
1492
+ new_kid.append(dec)
1493
+ if idx < len(self.decorators) - 1:
1494
+ new_kid.append(self.gen_token(Tok.DECOR_OP))
1500
1495
  if self.is_async:
1501
1496
  new_kid.append(self.gen_token(Tok.KW_ASYNC))
1502
1497
  new_kid.append(self.arch_type)
@@ -1505,13 +1500,19 @@ class Archetype(
1505
1500
  new_kid.append(self.name)
1506
1501
  if self.base_classes:
1507
1502
  new_kid.append(self.gen_token(Tok.LPAREN))
1508
- new_kid.append(self.base_classes)
1503
+ for idx, base in enumerate(self.base_classes):
1504
+ new_kid.append(base)
1505
+ if idx < len(self.base_classes) - 1:
1506
+ new_kid.append(self.gen_token(Tok.COMMA))
1509
1507
  new_kid.append(self.gen_token(Tok.RPAREN))
1510
1508
  if self.body:
1511
1509
  if isinstance(self.body, ImplDef):
1512
1510
  new_kid.append(self.gen_token(Tok.SEMI))
1513
1511
  else:
1514
- new_kid.append(self.body)
1512
+ new_kid.append(self.gen_token(Tok.LBRACE))
1513
+ for stmt in self.body:
1514
+ new_kid.append(stmt)
1515
+ new_kid.append(self.gen_token(Tok.RBRACE))
1515
1516
  else:
1516
1517
  new_kid.append(self.gen_token(Tok.SEMI))
1517
1518
  self.set_kids(nodes=new_kid)
@@ -1523,24 +1524,24 @@ class ImplDef(CodeBlockStmt, ElementStmt, ArchBlockStmt, AstSymbolNode, UniScope
1523
1524
 
1524
1525
  def __init__(
1525
1526
  self,
1526
- decorators: Optional[SubNodeList[Expr]],
1527
- target: SubNodeList[NameAtom],
1528
- spec: SubNodeList[Expr] | FuncSignature | EventSignature | None,
1529
- body: SubNodeList[CodeBlockStmt] | FuncCall,
1527
+ decorators: Optional[Sequence[Expr]],
1528
+ target: Sequence[NameAtom],
1529
+ spec: Sequence[Expr] | FuncSignature | EventSignature | None,
1530
+ body: Sequence[CodeBlockStmt] | Sequence[EnumBlockStmt] | FuncCall,
1530
1531
  kid: Sequence[UniNode],
1531
1532
  doc: Optional[String] = None,
1532
1533
  decl_link: Optional[UniNode] = None,
1533
1534
  ) -> None:
1534
1535
  self.decorators = decorators
1535
1536
  self.target = target
1536
- self.spec = spec
1537
+ self.spec = list(spec) if isinstance(spec, Sequence) else spec
1537
1538
  self.body = body
1538
1539
  self.doc = doc
1539
1540
  self.decl_link = decl_link
1540
1541
  UniNode.__init__(self, kid=kid)
1541
1542
  AstSymbolNode.__init__(
1542
1543
  self,
1543
- sym_name="impl." + ".".join([x.sym_name for x in self.target.items]),
1544
+ sym_name="impl." + ".".join([x.sym_name for x in self.target]),
1544
1545
  name_spec=self.create_impl_name_node(),
1545
1546
  sym_category=SymbolType.IMPL,
1546
1547
  )
@@ -1549,15 +1550,15 @@ class ImplDef(CodeBlockStmt, ElementStmt, ArchBlockStmt, AstSymbolNode, UniScope
1549
1550
 
1550
1551
  def create_impl_name_node(self) -> Name:
1551
1552
  ret = Name(
1552
- orig_src=self.target.items[-1].loc.orig_src,
1553
+ orig_src=self.target[-1].loc.orig_src,
1553
1554
  name=Tok.NAME.value,
1554
- value="impl." + ".".join([x.sym_name for x in self.target.items]),
1555
- col_start=self.target.items[0].loc.col_start,
1556
- col_end=self.target.items[-1].loc.col_end,
1557
- line=self.target.items[0].loc.first_line,
1558
- end_line=self.target.items[-1].loc.last_line,
1559
- pos_start=self.target.items[0].loc.pos_start,
1560
- pos_end=self.target.items[-1].loc.pos_end,
1555
+ value="impl." + ".".join([x.sym_name for x in self.target]),
1556
+ col_start=self.target[0].loc.col_start,
1557
+ col_end=self.target[-1].loc.col_end,
1558
+ line=self.target[0].loc.first_line,
1559
+ end_line=self.target[-1].loc.last_line,
1560
+ pos_start=self.target[0].loc.pos_start,
1561
+ pos_end=self.target[-1].loc.pos_end,
1561
1562
  )
1562
1563
  ret.parent = self
1563
1564
  return ret
@@ -1565,22 +1566,57 @@ class ImplDef(CodeBlockStmt, ElementStmt, ArchBlockStmt, AstSymbolNode, UniScope
1565
1566
  def normalize(self, deep: bool = False) -> bool:
1566
1567
  res = True
1567
1568
  if deep:
1568
- res = self.target.normalize(deep)
1569
- res = res and self.spec.normalize(deep) if self.spec else res
1570
- res = res and self.body.normalize(deep)
1569
+ for item in self.target:
1570
+ res = res and item.normalize(deep)
1571
+ if isinstance(self.spec, Sequence):
1572
+ for sp in self.spec:
1573
+ res = res and sp.normalize(deep)
1574
+ else:
1575
+ res = res and self.spec.normalize(deep) if self.spec else res
1576
+ if isinstance(self.body, FuncCall):
1577
+ res = res and self.body.normalize(deep)
1578
+ else:
1579
+ for stmt in self.body:
1580
+ res = res and stmt.normalize(deep)
1571
1581
  res = res and self.doc.normalize(deep) if self.doc else res
1572
- res = res and self.decorators.normalize(deep) if self.decorators else res
1582
+ if self.decorators:
1583
+ for dec in self.decorators:
1584
+ res = res and dec.normalize(deep)
1573
1585
  new_kid: list[UniNode] = []
1574
1586
  if self.doc:
1575
1587
  new_kid.append(self.doc)
1576
1588
  if self.decorators:
1577
1589
  new_kid.append(self.gen_token(Tok.DECOR_OP))
1578
- new_kid.append(self.decorators)
1590
+ for i, dec in enumerate(self.decorators):
1591
+ new_kid.append(dec)
1592
+ if i < len(self.decorators) - 1:
1593
+ new_kid.append(self.gen_token(Tok.DECOR_OP))
1579
1594
  new_kid.append(self.gen_token(Tok.KW_IMPL))
1580
- new_kid.append(self.target)
1595
+ for idx, item in enumerate(self.target):
1596
+ new_kid.append(item)
1597
+ if idx < len(self.target) - 1:
1598
+ new_kid.append(self.gen_token(Tok.DOT))
1581
1599
  if self.spec:
1582
- new_kid.append(self.spec)
1583
- new_kid.append(self.body)
1600
+ if isinstance(self.spec, Sequence):
1601
+ new_kid.append(self.gen_token(Tok.LPAREN))
1602
+ for idx, sp in enumerate(self.spec):
1603
+ new_kid.append(sp)
1604
+ if idx < len(self.spec) - 1:
1605
+ new_kid.append(self.gen_token(Tok.COMMA))
1606
+ new_kid.append(self.gen_token(Tok.RPAREN))
1607
+ else:
1608
+ new_kid.append(self.spec)
1609
+ if isinstance(self.body, FuncCall):
1610
+ new_kid.append(self.body)
1611
+ else:
1612
+ new_kid.append(self.gen_token(Tok.LBRACE))
1613
+ prev_stmt = None
1614
+ for stmt in self.body:
1615
+ if isinstance(prev_stmt, EnumBlockStmt) and prev_stmt.is_enum_stmt:
1616
+ new_kid.append(self.gen_token(Tok.COMMA))
1617
+ new_kid.append(stmt)
1618
+ prev_stmt = stmt
1619
+ new_kid.append(self.gen_token(Tok.RBRACE))
1584
1620
  self.set_kids(nodes=new_kid)
1585
1621
  return res
1586
1622
 
@@ -1592,14 +1628,14 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
1592
1628
  self,
1593
1629
  name: Name,
1594
1630
  access: Optional[SubTag[Token]],
1595
- base_classes: Optional[SubNodeList[Expr]],
1596
- body: Optional[SubNodeList[Assignment] | ImplDef],
1631
+ base_classes: Sequence[Expr] | None,
1632
+ body: Sequence[EnumBlockStmt] | ImplDef | None,
1597
1633
  kid: Sequence[UniNode],
1598
1634
  doc: Optional[String] = None,
1599
- decorators: Optional[SubNodeList[Expr]] = None,
1635
+ decorators: Sequence[Expr] | None = None,
1600
1636
  ) -> None:
1601
1637
  self.name = name
1602
- self.base_classes = base_classes
1638
+ self.base_classes: list[Expr] = list(base_classes) if base_classes else []
1603
1639
  UniNode.__init__(self, kid=kid)
1604
1640
  AstSymbolNode.__init__(
1605
1641
  self,
@@ -1618,16 +1654,25 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
1618
1654
  if deep:
1619
1655
  res = self.name.normalize(deep)
1620
1656
  res = res and self.access.normalize(deep) if self.access else res
1621
- res = (
1622
- res and self.base_classes.normalize(deep) if self.base_classes else res
1623
- )
1624
- res = res and self.body.normalize(deep) if self.body else res
1657
+ for base in self.base_classes:
1658
+ res = res and base.normalize(deep)
1659
+ if isinstance(self.body, ImplDef):
1660
+ res = res and self.body.normalize(deep)
1661
+ elif isinstance(self.body, Sequence):
1662
+ for stmt in self.body:
1663
+ res = res and stmt.normalize(deep)
1664
+ else:
1665
+ res = res and self.body.normalize(deep) if self.body else res
1625
1666
  res = res and self.doc.normalize(deep) if self.doc else res
1626
- res = res and self.decorators.normalize(deep) if self.decorators else res
1667
+ for dec in self.decorators or []:
1668
+ res = res and dec.normalize(deep)
1627
1669
  new_kid: list[UniNode] = []
1628
1670
  if self.decorators:
1629
1671
  new_kid.append(self.gen_token(Tok.DECOR_OP))
1630
- new_kid.append(self.decorators)
1672
+ for idx, dec in enumerate(self.decorators):
1673
+ new_kid.append(dec)
1674
+ if idx < len(self.decorators) - 1:
1675
+ new_kid.append(self.gen_token(Tok.DECOR_OP))
1631
1676
  if self.doc:
1632
1677
  new_kid.append(self.doc)
1633
1678
  new_kid.append(self.gen_token(Tok.KW_ENUM))
@@ -1636,13 +1681,23 @@ class Enum(ArchSpec, AstAccessNode, AstImplNeedingNode, ArchBlockStmt, UniScopeN
1636
1681
  new_kid.append(self.name)
1637
1682
  if self.base_classes:
1638
1683
  new_kid.append(self.gen_token(Tok.COLON))
1639
- new_kid.append(self.base_classes)
1684
+ for idx, base in enumerate(self.base_classes):
1685
+ new_kid.append(base)
1686
+ if idx < len(self.base_classes) - 1:
1687
+ new_kid.append(self.gen_token(Tok.COMMA))
1640
1688
  new_kid.append(self.gen_token(Tok.COLON))
1641
1689
  if self.body:
1642
1690
  if isinstance(self.body, ImplDef):
1643
1691
  new_kid.append(self.gen_token(Tok.SEMI))
1644
1692
  else:
1645
- new_kid.append(self.body)
1693
+ new_kid.append(self.gen_token(Tok.LBRACE))
1694
+ prev_stmt = None
1695
+ for stmt in self.body:
1696
+ if isinstance(prev_stmt, EnumBlockStmt) and prev_stmt.is_enum_stmt:
1697
+ new_kid.append(self.gen_token(Tok.COMMA))
1698
+ new_kid.append(stmt)
1699
+ prev_stmt = stmt
1700
+ new_kid.append(self.gen_token(Tok.RBRACE))
1646
1701
  else:
1647
1702
  new_kid.append(self.gen_token(Tok.SEMI))
1648
1703
  self.set_kids(nodes=new_kid)
@@ -1669,10 +1724,10 @@ class Ability(
1669
1724
  is_abstract: bool,
1670
1725
  access: Optional[SubTag[Token]],
1671
1726
  signature: FuncSignature | EventSignature | None,
1672
- body: Optional[SubNodeList[CodeBlockStmt] | ImplDef | FuncCall],
1727
+ body: Sequence[CodeBlockStmt] | ImplDef | FuncCall | None,
1673
1728
  kid: Sequence[UniNode],
1674
1729
  doc: Optional[String] = None,
1675
- decorators: Optional[SubNodeList[Expr]] = None,
1730
+ decorators: Sequence[Expr] | None = None,
1676
1731
  ) -> None:
1677
1732
  self.name_ref = name_ref
1678
1733
  self.is_override = is_override
@@ -1706,17 +1761,14 @@ class Ability(
1706
1761
  @property
1707
1762
  def method_owner(self) -> Optional[Archetype | Enum]:
1708
1763
  found = (
1709
- self.parent.parent
1710
- if self.parent
1711
- and self.parent.parent
1712
- and isinstance(self.parent.parent, (Archetype, Enum))
1764
+ self.parent
1765
+ if self.parent and isinstance(self.parent, (Archetype, Enum))
1713
1766
  else None
1714
1767
  ) or (
1715
- self.parent.parent.decl_link
1768
+ self.parent.decl_link
1716
1769
  if self.parent
1717
- and self.parent.parent
1718
- and isinstance(self.parent.parent, ImplDef)
1719
- and isinstance(self.parent.parent.decl_link, Archetype)
1770
+ and isinstance(self.parent, ImplDef)
1771
+ and isinstance(self.parent.decl_link, (Archetype, Enum))
1720
1772
  else None
1721
1773
  )
1722
1774
  return found
@@ -1739,15 +1791,25 @@ class Ability(
1739
1791
  res = self.name_ref.normalize(deep)
1740
1792
  res = res and self.access.normalize(deep) if self.access else res
1741
1793
  res = res and self.signature.normalize(deep) if self.signature else res
1742
- res = res and self.body.normalize(deep) if self.body else res
1743
- res = res and self.decorators.normalize(deep) if self.decorators else res
1794
+ if isinstance(self.body, ImplDef):
1795
+ res = res and self.body.normalize(deep)
1796
+ elif isinstance(self.body, Sequence):
1797
+ for stmt in self.body:
1798
+ res = res and stmt.normalize(deep)
1799
+ else:
1800
+ res = res and self.body.normalize(deep) if self.body else res
1801
+ for dec in self.decorators or []:
1802
+ res = res and dec.normalize(deep)
1744
1803
  res = res and self.doc.normalize(deep) if self.doc else res
1745
1804
  new_kid: list[UniNode] = []
1746
1805
  if self.doc:
1747
1806
  new_kid.append(self.doc)
1748
1807
  if self.decorators:
1749
1808
  new_kid.append(self.gen_token(Tok.DECOR_OP))
1750
- new_kid.append(self.decorators)
1809
+ for idx, dec in enumerate(self.decorators):
1810
+ new_kid.append(dec)
1811
+ if idx < len(self.decorators) - 1:
1812
+ new_kid.append(self.gen_token(Tok.DECOR_OP))
1751
1813
  new_kid.append(self.gen_token(Tok.WS))
1752
1814
  if self.is_async:
1753
1815
  new_kid.append(self.gen_token(Tok.KW_ASYNC))
@@ -1769,9 +1831,14 @@ class Ability(
1769
1831
  new_kid.append(self.gen_token(Tok.KW_BY))
1770
1832
  if self.is_abstract:
1771
1833
  new_kid.append(self.gen_token(Tok.KW_ABSTRACT))
1772
- if self.body:
1834
+ if self.body is not None:
1773
1835
  if isinstance(self.body, ImplDef):
1774
1836
  new_kid.append(self.gen_token(Tok.SEMI))
1837
+ elif isinstance(self.body, Sequence):
1838
+ new_kid.append(self.gen_token(Tok.LBRACE))
1839
+ for stmt in self.body:
1840
+ new_kid.append(stmt)
1841
+ new_kid.append(self.gen_token(Tok.RBRACE))
1775
1842
  else:
1776
1843
  new_kid.append(self.body)
1777
1844
  if self.is_genai_ability:
@@ -1787,11 +1854,11 @@ class FuncSignature(UniNode):
1787
1854
 
1788
1855
  def __init__(
1789
1856
  self,
1790
- params: Optional[SubNodeList[ParamVar]],
1857
+ params: Sequence[ParamVar] | None,
1791
1858
  return_type: Optional[Expr],
1792
1859
  kid: Sequence[UniNode],
1793
1860
  ) -> None:
1794
- self.params = params
1861
+ self.params: list[ParamVar] = list(params) if params else []
1795
1862
  self.return_type = return_type
1796
1863
  UniNode.__init__(self, kid=kid)
1797
1864
 
@@ -1799,11 +1866,14 @@ class FuncSignature(UniNode):
1799
1866
  res = True
1800
1867
  is_lambda = self.parent and isinstance(self.parent, LambdaExpr)
1801
1868
  if deep:
1802
- res = self.params.normalize(deep) if self.params else res
1869
+ for prm in self.params:
1870
+ res = res and prm.normalize(deep)
1803
1871
  res = res and self.return_type.normalize(deep) if self.return_type else res
1804
1872
  new_kid: list[UniNode] = [self.gen_token(Tok.LPAREN)] if not is_lambda else []
1805
- if self.params:
1806
- new_kid.append(self.params)
1873
+ for idx, prm in enumerate(self.params):
1874
+ new_kid.append(prm)
1875
+ if idx < len(self.params) - 1:
1876
+ new_kid.append(self.gen_token(Tok.COMMA))
1807
1877
  if not is_lambda:
1808
1878
  new_kid.append(self.gen_token(Tok.RPAREN))
1809
1879
  if self.return_type:
@@ -1837,7 +1907,7 @@ class FuncSignature(UniNode):
1837
1907
  )
1838
1908
 
1839
1909
 
1840
- class EventSignature(UniNode):
1910
+ class EventSignature(WalkerStmtOnlyNode):
1841
1911
  """EventSignature node type for Jac Ast."""
1842
1912
 
1843
1913
  def __init__(
@@ -1851,6 +1921,7 @@ class EventSignature(UniNode):
1851
1921
  self.arch_tag_info = arch_tag_info
1852
1922
  self.return_type = return_type
1853
1923
  UniNode.__init__(self, kid=kid)
1924
+ WalkerStmtOnlyNode.__init__(self)
1854
1925
 
1855
1926
  def normalize(self, deep: bool = False) -> bool:
1856
1927
  res = True
@@ -1926,13 +1997,13 @@ class ArchHas(AstAccessNode, AstDocNode, ArchBlockStmt, CodeBlockStmt):
1926
1997
  self,
1927
1998
  is_static: bool,
1928
1999
  access: Optional[SubTag[Token]],
1929
- vars: SubNodeList[HasVar],
2000
+ vars: Sequence[HasVar],
1930
2001
  is_frozen: bool,
1931
2002
  kid: Sequence[UniNode],
1932
2003
  doc: Optional[String] = None,
1933
2004
  ) -> None:
1934
2005
  self.is_static = is_static
1935
- self.vars = vars
2006
+ self.vars: list[HasVar] = list(vars)
1936
2007
  self.is_frozen = is_frozen
1937
2008
  UniNode.__init__(self, kid=kid)
1938
2009
  AstAccessNode.__init__(self, access=access)
@@ -1943,7 +2014,8 @@ class ArchHas(AstAccessNode, AstDocNode, ArchBlockStmt, CodeBlockStmt):
1943
2014
  res = True
1944
2015
  if deep:
1945
2016
  res = self.access.normalize(deep) if self.access else res
1946
- res = res and self.vars.normalize(deep) if self.vars else res
2017
+ for var in self.vars:
2018
+ res = res and var.normalize(deep)
1947
2019
  res = res and self.doc.normalize(deep) if self.doc else res
1948
2020
  new_kid: list[UniNode] = []
1949
2021
  if self.doc:
@@ -1957,7 +2029,10 @@ class ArchHas(AstAccessNode, AstDocNode, ArchBlockStmt, CodeBlockStmt):
1957
2029
  )
1958
2030
  if self.access:
1959
2031
  new_kid.append(self.access)
1960
- new_kid.append(self.vars)
2032
+ for i, var in enumerate(self.vars):
2033
+ new_kid.append(var)
2034
+ if i < len(self.vars) - 1:
2035
+ new_kid.append(self.gen_token(Tok.COMMA))
1961
2036
  new_kid.append(self.gen_token(Tok.SEMI))
1962
2037
  self.set_kids(nodes=new_kid)
1963
2038
  return res
@@ -2011,7 +2086,7 @@ class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
2011
2086
  def __init__(
2012
2087
  self,
2013
2088
  type_ctx: Expr,
2014
- body: SubNodeList[CodeBlockStmt],
2089
+ body: Sequence[CodeBlockStmt],
2015
2090
  kid: Sequence[UniNode],
2016
2091
  ) -> None:
2017
2092
  self.type_ctx = type_ctx
@@ -2024,12 +2099,16 @@ class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
2024
2099
  res = True
2025
2100
  if deep:
2026
2101
  res = self.type_ctx.normalize(deep)
2027
- res = res and self.body.normalize(deep)
2102
+ for stmt in self.body:
2103
+ res = res and stmt.normalize(deep)
2028
2104
  new_kid: list[UniNode] = [
2029
2105
  self.gen_token(Tok.RETURN_HINT),
2030
2106
  self.type_ctx,
2031
- self.body,
2107
+ self.gen_token(Tok.LBRACE),
2032
2108
  ]
2109
+ for stmt in self.body:
2110
+ new_kid.append(stmt)
2111
+ new_kid.append(self.gen_token(Tok.RBRACE))
2033
2112
  self.set_kids(nodes=new_kid)
2034
2113
  return res
2035
2114
 
@@ -2040,12 +2119,12 @@ class IfStmt(CodeBlockStmt, AstElseBodyNode, UniScopeNode):
2040
2119
  def __init__(
2041
2120
  self,
2042
2121
  condition: Expr,
2043
- body: SubNodeList[CodeBlockStmt],
2122
+ body: Sequence[CodeBlockStmt],
2044
2123
  else_body: Optional[ElseStmt | ElseIf],
2045
2124
  kid: Sequence[UniNode],
2046
2125
  ) -> None:
2047
2126
  self.condition = condition
2048
- self.body = body
2127
+ self.body: list[CodeBlockStmt] = list(body)
2049
2128
  UniNode.__init__(self, kid=kid)
2050
2129
  AstElseBodyNode.__init__(self, else_body=else_body)
2051
2130
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
@@ -2055,13 +2134,17 @@ class IfStmt(CodeBlockStmt, AstElseBodyNode, UniScopeNode):
2055
2134
  res = True
2056
2135
  if deep:
2057
2136
  res = self.condition.normalize(deep)
2058
- res = res and self.body.normalize(deep)
2137
+ for stmt in self.body:
2138
+ res = res and stmt.normalize(deep)
2059
2139
  res = res and self.else_body.normalize(deep) if self.else_body else res
2060
2140
  new_kid: list[UniNode] = [
2061
2141
  self.gen_token(Tok.KW_IF),
2062
2142
  self.condition,
2063
- self.body,
2143
+ self.gen_token(Tok.LBRACE),
2064
2144
  ]
2145
+ for stmt in self.body:
2146
+ new_kid.append(stmt)
2147
+ new_kid.append(self.gen_token(Tok.RBRACE))
2065
2148
  if self.else_body:
2066
2149
  new_kid.append(self.else_body)
2067
2150
  self.set_kids(nodes=new_kid)
@@ -2075,13 +2158,17 @@ class ElseIf(IfStmt):
2075
2158
  res = True
2076
2159
  if deep:
2077
2160
  res = self.condition.normalize(deep)
2078
- res = res and self.body.normalize(deep)
2161
+ for stmt in self.body:
2162
+ res = res and stmt.normalize(deep)
2079
2163
  res = res and self.else_body.normalize(deep) if self.else_body else res
2080
2164
  new_kid: list[UniNode] = [
2081
2165
  self.gen_token(Tok.KW_ELIF),
2082
2166
  self.condition,
2083
- self.body,
2167
+ self.gen_token(Tok.LBRACE),
2084
2168
  ]
2169
+ for stmt in self.body:
2170
+ new_kid.append(stmt)
2171
+ new_kid.append(self.gen_token(Tok.RBRACE))
2085
2172
  if self.else_body:
2086
2173
  new_kid.append(self.else_body)
2087
2174
  self.set_kids(nodes=new_kid)
@@ -2093,21 +2180,25 @@ class ElseStmt(UniScopeNode):
2093
2180
 
2094
2181
  def __init__(
2095
2182
  self,
2096
- body: SubNodeList[CodeBlockStmt],
2183
+ body: Sequence[CodeBlockStmt],
2097
2184
  kid: Sequence[UniNode],
2098
2185
  ) -> None:
2099
- self.body = body
2186
+ self.body: list[CodeBlockStmt] = list(body)
2100
2187
  UniNode.__init__(self, kid=kid)
2101
2188
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
2102
2189
 
2103
2190
  def normalize(self, deep: bool = False) -> bool:
2104
2191
  res = True
2105
2192
  if deep:
2106
- res = self.body.normalize(deep)
2193
+ for stmt in self.body:
2194
+ res = res and stmt.normalize(deep)
2107
2195
  new_kid: list[UniNode] = [
2108
2196
  self.gen_token(Tok.KW_ELSE),
2109
- self.body,
2197
+ self.gen_token(Tok.LBRACE),
2110
2198
  ]
2199
+ for stmt in self.body:
2200
+ new_kid.append(stmt)
2201
+ new_kid.append(self.gen_token(Tok.RBRACE))
2111
2202
  self.set_kids(nodes=new_kid)
2112
2203
  return res
2113
2204
 
@@ -2144,14 +2235,14 @@ class TryStmt(AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2144
2235
 
2145
2236
  def __init__(
2146
2237
  self,
2147
- body: SubNodeList[CodeBlockStmt],
2148
- excepts: Optional[SubNodeList[Except]],
2238
+ body: Sequence[CodeBlockStmt],
2239
+ excepts: Sequence[Except],
2149
2240
  else_body: Optional[ElseStmt],
2150
2241
  finally_body: Optional[FinallyStmt],
2151
2242
  kid: Sequence[UniNode],
2152
2243
  ) -> None:
2153
- self.body = body
2154
- self.excepts = excepts
2244
+ self.body: list[CodeBlockStmt] = list(body)
2245
+ self.excepts: list[Except] = list(excepts)
2155
2246
  self.finally_body = finally_body
2156
2247
  UniNode.__init__(self, kid=kid)
2157
2248
  AstElseBodyNode.__init__(self, else_body=else_body)
@@ -2161,18 +2252,23 @@ class TryStmt(AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2161
2252
  def normalize(self, deep: bool = False) -> bool:
2162
2253
  res = True
2163
2254
  if deep:
2164
- res = self.body.normalize(deep)
2165
- res = res and self.excepts.normalize(deep) if self.excepts else res
2255
+ for stmt in self.body:
2256
+ res = res and stmt.normalize(deep)
2257
+ for exc in self.excepts:
2258
+ res = res and exc.normalize(deep)
2166
2259
  res = res and self.else_body.normalize(deep) if self.else_body else res
2167
2260
  res = (
2168
2261
  res and self.finally_body.normalize(deep) if self.finally_body else res
2169
2262
  )
2170
2263
  new_kid: list[UniNode] = [
2171
2264
  self.gen_token(Tok.KW_TRY),
2265
+ self.gen_token(Tok.LBRACE),
2172
2266
  ]
2173
- new_kid.append(self.body)
2174
- if self.excepts:
2175
- new_kid.append(self.excepts)
2267
+ for stmt in self.body:
2268
+ new_kid.append(stmt)
2269
+ new_kid.append(self.gen_token(Tok.RBRACE))
2270
+ for exc in self.excepts:
2271
+ new_kid.append(exc)
2176
2272
  if self.else_body:
2177
2273
  new_kid.append(self.else_body)
2178
2274
  if self.finally_body:
@@ -2188,12 +2284,12 @@ class Except(CodeBlockStmt, UniScopeNode):
2188
2284
  self,
2189
2285
  ex_type: Expr,
2190
2286
  name: Optional[Name],
2191
- body: SubNodeList[CodeBlockStmt],
2287
+ body: Sequence[CodeBlockStmt],
2192
2288
  kid: Sequence[UniNode],
2193
2289
  ) -> None:
2194
2290
  self.ex_type = ex_type
2195
2291
  self.name = name
2196
- self.body = body
2292
+ self.body: list[CodeBlockStmt] = list(body)
2197
2293
  UniNode.__init__(self, kid=kid)
2198
2294
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
2199
2295
  CodeBlockStmt.__init__(self)
@@ -2203,7 +2299,8 @@ class Except(CodeBlockStmt, UniScopeNode):
2203
2299
  if deep:
2204
2300
  res = self.ex_type.normalize(deep)
2205
2301
  res = res and self.name.normalize(deep) if self.name else res
2206
- res = res and self.body.normalize(deep) if self.body else res
2302
+ for stmt in self.body:
2303
+ res = res and stmt.normalize(deep)
2207
2304
  new_kid: list[UniNode] = [
2208
2305
  self.gen_token(Tok.KW_EXCEPT),
2209
2306
  self.ex_type,
@@ -2211,7 +2308,10 @@ class Except(CodeBlockStmt, UniScopeNode):
2211
2308
  if self.name:
2212
2309
  new_kid.append(self.gen_token(Tok.KW_AS))
2213
2310
  new_kid.append(self.name)
2214
- new_kid.append(self.body)
2311
+ new_kid.append(self.gen_token(Tok.LBRACE))
2312
+ for stmt in self.body:
2313
+ new_kid.append(stmt)
2314
+ new_kid.append(self.gen_token(Tok.RBRACE))
2215
2315
  self.set_kids(nodes=new_kid)
2216
2316
  return res
2217
2317
 
@@ -2221,10 +2321,10 @@ class FinallyStmt(CodeBlockStmt, UniScopeNode):
2221
2321
 
2222
2322
  def __init__(
2223
2323
  self,
2224
- body: SubNodeList[CodeBlockStmt],
2324
+ body: Sequence[CodeBlockStmt],
2225
2325
  kid: Sequence[UniNode],
2226
2326
  ) -> None:
2227
- self.body = body
2327
+ self.body: list[CodeBlockStmt] = list(body)
2228
2328
  UniNode.__init__(self, kid=kid)
2229
2329
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
2230
2330
  CodeBlockStmt.__init__(self)
@@ -2232,11 +2332,15 @@ class FinallyStmt(CodeBlockStmt, UniScopeNode):
2232
2332
  def normalize(self, deep: bool = False) -> bool:
2233
2333
  res = True
2234
2334
  if deep:
2235
- res = self.body.normalize(deep)
2335
+ for stmt in self.body:
2336
+ res = res and stmt.normalize(deep)
2236
2337
  new_kid: list[UniNode] = [
2237
2338
  self.gen_token(Tok.KW_FINALLY),
2339
+ self.gen_token(Tok.LBRACE),
2238
2340
  ]
2239
- new_kid.append(self.body)
2341
+ for stmt in self.body:
2342
+ new_kid.append(stmt)
2343
+ new_kid.append(self.gen_token(Tok.RBRACE))
2240
2344
  self.set_kids(nodes=new_kid)
2241
2345
  return res
2242
2346
 
@@ -2250,14 +2354,14 @@ class IterForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2250
2354
  is_async: bool,
2251
2355
  condition: Expr,
2252
2356
  count_by: Assignment,
2253
- body: SubNodeList[CodeBlockStmt],
2357
+ body: Sequence[CodeBlockStmt],
2254
2358
  else_body: Optional[ElseStmt],
2255
2359
  kid: Sequence[UniNode],
2256
2360
  ) -> None:
2257
2361
  self.iter = iter
2258
2362
  self.condition = condition
2259
2363
  self.count_by = count_by
2260
- self.body = body
2364
+ self.body: list[CodeBlockStmt] = list(body)
2261
2365
  UniNode.__init__(self, kid=kid)
2262
2366
  AstAsyncNode.__init__(self, is_async=is_async)
2263
2367
  AstElseBodyNode.__init__(self, else_body=else_body)
@@ -2270,8 +2374,9 @@ class IterForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2270
2374
  res = self.iter.normalize(deep)
2271
2375
  res = self.condition.normalize(deep)
2272
2376
  res = self.count_by.normalize(deep)
2273
- res = self.body.normalize(deep)
2274
- res = self.else_body.normalize(deep) if self.else_body else res
2377
+ for stmt in self.body:
2378
+ res = res and stmt.normalize(deep)
2379
+ res = res and self.else_body.normalize(deep) if self.else_body else res
2275
2380
  new_kid: list[UniNode] = []
2276
2381
  if self.is_async:
2277
2382
  new_kid.append(self.gen_token(Tok.KW_ASYNC))
@@ -2281,7 +2386,10 @@ class IterForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2281
2386
  new_kid.append(self.condition)
2282
2387
  new_kid.append(self.gen_token(Tok.KW_BY))
2283
2388
  new_kid.append(self.count_by)
2284
- new_kid.append(self.body)
2389
+ new_kid.append(self.gen_token(Tok.LBRACE))
2390
+ for stmt in self.body:
2391
+ new_kid.append(stmt)
2392
+ new_kid.append(self.gen_token(Tok.RBRACE))
2285
2393
  if self.else_body:
2286
2394
  new_kid.append(self.else_body)
2287
2395
  self.set_kids(nodes=new_kid)
@@ -2296,13 +2404,13 @@ class InForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2296
2404
  target: Expr,
2297
2405
  is_async: bool,
2298
2406
  collection: Expr,
2299
- body: SubNodeList[CodeBlockStmt],
2407
+ body: Sequence[CodeBlockStmt],
2300
2408
  else_body: Optional[ElseStmt],
2301
2409
  kid: Sequence[UniNode],
2302
2410
  ) -> None:
2303
2411
  self.target = target
2304
2412
  self.collection = collection
2305
- self.body = body
2413
+ self.body: list[CodeBlockStmt] = list(body)
2306
2414
  UniNode.__init__(self, kid=kid)
2307
2415
  AstAsyncNode.__init__(self, is_async=is_async)
2308
2416
  AstElseBodyNode.__init__(self, else_body=else_body)
@@ -2312,9 +2420,10 @@ class InForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2312
2420
  def normalize(self, deep: bool = False) -> bool:
2313
2421
  res = True
2314
2422
  if deep:
2315
- res = self.target.normalize(deep)
2423
+ res = res and self.target.normalize(deep)
2316
2424
  res = res and self.collection.normalize(deep)
2317
- res = res and self.body.normalize(deep)
2425
+ for stmt in self.body:
2426
+ res = res and stmt.normalize(deep)
2318
2427
  res = res and self.else_body.normalize(deep) if self.else_body else res
2319
2428
  new_kid: list[UniNode] = []
2320
2429
  if self.is_async:
@@ -2324,8 +2433,10 @@ class InForStmt(AstAsyncNode, AstElseBodyNode, CodeBlockStmt, UniScopeNode):
2324
2433
  new_kid.append(self.gen_token(Tok.KW_IN))
2325
2434
  new_kid.append(self.collection)
2326
2435
 
2327
- if self.body:
2328
- new_kid.append(self.body)
2436
+ new_kid.append(self.gen_token(Tok.LBRACE))
2437
+ for stmt in self.body:
2438
+ new_kid.append(stmt)
2439
+ new_kid.append(self.gen_token(Tok.RBRACE))
2329
2440
  if self.else_body:
2330
2441
  new_kid.append(self.else_body)
2331
2442
  self.set_kids(nodes=new_kid)
@@ -2338,11 +2449,11 @@ class WhileStmt(CodeBlockStmt, UniScopeNode):
2338
2449
  def __init__(
2339
2450
  self,
2340
2451
  condition: Expr,
2341
- body: SubNodeList[CodeBlockStmt],
2452
+ body: Sequence[CodeBlockStmt],
2342
2453
  kid: Sequence[UniNode],
2343
2454
  ) -> None:
2344
2455
  self.condition = condition
2345
- self.body = body
2456
+ self.body: list[CodeBlockStmt] = list(body)
2346
2457
  UniNode.__init__(self, kid=kid)
2347
2458
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
2348
2459
  CodeBlockStmt.__init__(self)
@@ -2351,13 +2462,16 @@ class WhileStmt(CodeBlockStmt, UniScopeNode):
2351
2462
  res = True
2352
2463
  if deep:
2353
2464
  res = self.condition.normalize(deep)
2354
- res = res and self.body.normalize(deep)
2465
+ for stmt in self.body:
2466
+ res = res and stmt.normalize(deep)
2355
2467
  new_kid: list[UniNode] = [
2356
2468
  self.gen_token(Tok.KW_WHILE),
2357
2469
  self.condition,
2470
+ self.gen_token(Tok.LBRACE),
2358
2471
  ]
2359
- if self.body:
2360
- new_kid.append(self.body)
2472
+ for stmt in self.body:
2473
+ new_kid.append(stmt)
2474
+ new_kid.append(self.gen_token(Tok.RBRACE))
2361
2475
  self.set_kids(nodes=new_kid)
2362
2476
  return res
2363
2477
 
@@ -2368,12 +2482,12 @@ class WithStmt(AstAsyncNode, CodeBlockStmt, UniScopeNode):
2368
2482
  def __init__(
2369
2483
  self,
2370
2484
  is_async: bool,
2371
- exprs: SubNodeList[ExprAsItem],
2372
- body: SubNodeList[CodeBlockStmt],
2485
+ exprs: Sequence[ExprAsItem],
2486
+ body: Sequence[CodeBlockStmt],
2373
2487
  kid: Sequence[UniNode],
2374
2488
  ) -> None:
2375
2489
  self.exprs = exprs
2376
- self.body = body
2490
+ self.body: list[CodeBlockStmt] = list(body)
2377
2491
  UniNode.__init__(self, kid=kid)
2378
2492
  AstAsyncNode.__init__(self, is_async=is_async)
2379
2493
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
@@ -2382,14 +2496,22 @@ class WithStmt(AstAsyncNode, CodeBlockStmt, UniScopeNode):
2382
2496
  def normalize(self, deep: bool = False) -> bool:
2383
2497
  res = True
2384
2498
  if deep:
2385
- res = self.exprs.normalize(deep)
2386
- res = res and self.body.normalize(deep)
2499
+ for item in self.exprs:
2500
+ res = res and item.normalize(deep)
2501
+ for stmt in self.body:
2502
+ res = res and stmt.normalize(deep)
2387
2503
  new_kid: list[UniNode] = []
2388
2504
  if self.is_async:
2389
2505
  new_kid.append(self.gen_token(Tok.KW_ASYNC))
2390
2506
  new_kid.append(self.gen_token(Tok.KW_WITH))
2391
- new_kid.append(self.exprs)
2392
- new_kid.append(self.body)
2507
+ for idx, item in enumerate(self.exprs):
2508
+ new_kid.append(item)
2509
+ if idx < len(self.exprs) - 1:
2510
+ new_kid.append(self.gen_token(Tok.COMMA))
2511
+ new_kid.append(self.gen_token(Tok.LBRACE))
2512
+ for stmt in self.body:
2513
+ new_kid.append(stmt)
2514
+ new_kid.append(self.gen_token(Tok.RBRACE))
2393
2515
  self.set_kids(nodes=new_kid)
2394
2516
  return res
2395
2517
 
@@ -2543,7 +2665,7 @@ class DeleteStmt(CodeBlockStmt):
2543
2665
  def py_ast_targets(self) -> list[ast3.AST]:
2544
2666
  """Get Python AST targets (without setting ctx)."""
2545
2667
  return (
2546
- self.target.values.gen.py_ast
2668
+ [i.gen.py_ast[0] for i in self.target.values]
2547
2669
  if isinstance(self.target, TupleVal) and self.target.values
2548
2670
  else self.target.gen.py_ast
2549
2671
  )
@@ -2727,22 +2849,24 @@ class GlobalStmt(CodeBlockStmt):
2727
2849
 
2728
2850
  def __init__(
2729
2851
  self,
2730
- target: SubNodeList[NameAtom],
2852
+ target: Sequence[NameAtom],
2731
2853
  kid: Sequence[UniNode],
2732
2854
  ) -> None:
2733
- self.target = target
2855
+ self.target: list[NameAtom] = list(target)
2734
2856
  UniNode.__init__(self, kid=kid)
2735
2857
  CodeBlockStmt.__init__(self)
2736
2858
 
2737
2859
  def normalize(self, deep: bool = False) -> bool:
2738
2860
  res = True
2739
2861
  if deep:
2740
- res = self.target.normalize(deep)
2741
- new_kid: list[UniNode] = [
2742
- self.gen_token(Tok.GLOBAL_OP),
2743
- self.target,
2744
- self.gen_token(Tok.SEMI),
2745
- ]
2862
+ for item in self.target:
2863
+ res = res and item.normalize(deep)
2864
+ new_kid: list[UniNode] = [self.gen_token(Tok.GLOBAL_OP)]
2865
+ for idx, item in enumerate(self.target):
2866
+ new_kid.append(item)
2867
+ if idx < len(self.target) - 1:
2868
+ new_kid.append(self.gen_token(Tok.COMMA))
2869
+ new_kid.append(self.gen_token(Tok.SEMI))
2746
2870
  self.set_kids(nodes=new_kid)
2747
2871
  return res
2748
2872
 
@@ -2753,12 +2877,14 @@ class NonLocalStmt(GlobalStmt):
2753
2877
  def normalize(self, deep: bool = False) -> bool:
2754
2878
  res = True
2755
2879
  if deep:
2756
- res = self.target.normalize(deep)
2757
- new_kid: list[UniNode] = [
2758
- self.gen_token(Tok.NONLOCAL_OP),
2759
- self.target,
2760
- self.gen_token(Tok.SEMI),
2761
- ]
2880
+ for item in self.target:
2881
+ res = res and item.normalize(deep)
2882
+ new_kid: list[UniNode] = [self.gen_token(Tok.NONLOCAL_OP)]
2883
+ for idx, item in enumerate(self.target):
2884
+ new_kid.append(item)
2885
+ if idx < len(self.target) - 1:
2886
+ new_kid.append(self.gen_token(Tok.COMMA))
2887
+ new_kid.append(self.gen_token(Tok.SEMI))
2762
2888
  self.set_kids(nodes=new_kid)
2763
2889
  return res
2764
2890
 
@@ -2768,7 +2894,7 @@ class Assignment(AstTypedVarNode, EnumBlockStmt, CodeBlockStmt):
2768
2894
 
2769
2895
  def __init__(
2770
2896
  self,
2771
- target: SubNodeList[Expr],
2897
+ target: Sequence[Expr],
2772
2898
  value: Optional[Expr | YieldExpr],
2773
2899
  type_tag: Optional[SubTag[Expr]],
2774
2900
  kid: Sequence[UniNode],
@@ -2776,24 +2902,28 @@ class Assignment(AstTypedVarNode, EnumBlockStmt, CodeBlockStmt):
2776
2902
  aug_op: Optional[Token] = None,
2777
2903
  is_enum_stmt: bool = False,
2778
2904
  ) -> None:
2779
- self.target = target
2905
+ self.target: list[Expr] = list(target)
2780
2906
  self.value = value
2781
2907
  self.mutable = mutable
2782
2908
  self.aug_op = aug_op
2783
- self.is_enum_stmt = is_enum_stmt
2784
2909
  UniNode.__init__(self, kid=kid)
2785
2910
  AstTypedVarNode.__init__(self, type_tag=type_tag)
2786
2911
  CodeBlockStmt.__init__(self)
2912
+ EnumBlockStmt.__init__(self, is_enum_stmt=is_enum_stmt)
2787
2913
 
2788
2914
  def normalize(self, deep: bool = True) -> bool:
2789
2915
  res = True
2790
2916
  if deep:
2791
- res = self.target.normalize(deep)
2917
+ for t in self.target:
2918
+ res = res and t.normalize(deep)
2792
2919
  res = res and self.value.normalize(deep) if self.value else res
2793
2920
  res = res and self.type_tag.normalize(deep) if self.type_tag else res
2794
2921
  res = res and self.aug_op.normalize(deep) if self.aug_op else res
2795
2922
  new_kid: list[UniNode] = []
2796
- new_kid.append(self.target)
2923
+ for idx, targ in enumerate(self.target):
2924
+ new_kid.append(targ)
2925
+ if idx < len(self.target) - 1:
2926
+ new_kid.append(self.gen_token(Tok.EQ))
2797
2927
  if self.type_tag:
2798
2928
  new_kid.append(self.type_tag)
2799
2929
  if self.aug_op:
@@ -2802,12 +2932,13 @@ class Assignment(AstTypedVarNode, EnumBlockStmt, CodeBlockStmt):
2802
2932
  if not self.aug_op:
2803
2933
  new_kid.append(self.gen_token(Tok.EQ))
2804
2934
  new_kid.append(self.value)
2805
- if isinstance(self.parent, SubNodeList) and isinstance(
2806
- self.parent.parent, GlobalVars
2807
- ):
2808
- if self.parent.kid.index(self) == len(self.parent.kid) - 1:
2935
+ if isinstance(self.parent, GlobalVars):
2936
+ if self.parent.assignments.index(self) == len(self.parent.assignments) - 1:
2809
2937
  new_kid.append(self.gen_token(Tok.SEMI))
2810
- elif (not self.is_enum_stmt) and not isinstance(self.parent, IterForStmt):
2938
+ elif (not self.is_enum_stmt) and not (
2939
+ isinstance(self.parent, IterForStmt)
2940
+ and self in [self.parent.iter, self.parent.count_by]
2941
+ ):
2811
2942
  new_kid.append(self.gen_token(Tok.SEMI))
2812
2943
  self.set_kids(nodes=new_kid)
2813
2944
  return res
@@ -3045,10 +3176,10 @@ class FString(AtomExpr):
3045
3176
 
3046
3177
  def __init__(
3047
3178
  self,
3048
- parts: Optional[SubNodeList[String | ExprStmt]],
3179
+ parts: Sequence[String | ExprStmt],
3049
3180
  kid: Sequence[UniNode],
3050
3181
  ) -> None:
3051
- self.parts = parts
3182
+ self.parts: list[String | ExprStmt] = list(parts)
3052
3183
  UniNode.__init__(self, kid=kid)
3053
3184
  Expr.__init__(self)
3054
3185
  AstSymbolStubNode.__init__(self, sym_type=SymbolType.STRING)
@@ -3056,26 +3187,30 @@ class FString(AtomExpr):
3056
3187
  def normalize(self, deep: bool = False) -> bool:
3057
3188
  res = True
3058
3189
  if deep:
3059
- res = self.parts.normalize(deep) if self.parts else res
3190
+ for part in self.parts:
3191
+ res = res and part.normalize(deep)
3060
3192
  new_kid: list[UniNode] = []
3061
3193
  is_single_quote = (
3062
3194
  isinstance(self.kid[0], Token) and self.kid[0].name == Tok.FSTR_SQ_START
3063
3195
  )
3064
- if self.parts:
3065
- if is_single_quote:
3066
- new_kid.append(self.gen_token(Tok.FSTR_SQ_START))
3067
- else:
3068
- new_kid.append(self.gen_token(Tok.FSTR_START))
3069
- for i in self.parts.items:
3070
- if isinstance(i, String):
3071
- i.value = (
3072
- "{{" if i.value == "{" else "}}" if i.value == "}" else i.value
3073
- )
3074
- new_kid.append(self.parts)
3075
- if is_single_quote:
3076
- new_kid.append(self.gen_token(Tok.FSTR_SQ_END))
3196
+ if is_single_quote:
3197
+ new_kid.append(self.gen_token(Tok.FSTR_SQ_START))
3198
+ else:
3199
+ new_kid.append(self.gen_token(Tok.FSTR_START))
3200
+ for i in self.parts:
3201
+ if isinstance(i, String):
3202
+ i.value = (
3203
+ "{{" if i.value == "{" else "}}" if i.value == "}" else i.value
3204
+ )
3205
+ new_kid.append(i)
3077
3206
  else:
3078
- new_kid.append(self.gen_token(Tok.FSTR_END))
3207
+ new_kid.append(self.gen_token(Tok.LBRACE))
3208
+ new_kid.append(i)
3209
+ new_kid.append(self.gen_token(Tok.RBRACE))
3210
+ if is_single_quote:
3211
+ new_kid.append(self.gen_token(Tok.FSTR_SQ_END))
3212
+ else:
3213
+ new_kid.append(self.gen_token(Tok.FSTR_END))
3079
3214
  self.set_kids(nodes=new_kid)
3080
3215
  return res
3081
3216
 
@@ -3085,7 +3220,7 @@ class ListVal(AtomExpr):
3085
3220
 
3086
3221
  def __init__(
3087
3222
  self,
3088
- values: Optional[SubNodeList[Expr]],
3223
+ values: Sequence[Expr],
3089
3224
  kid: Sequence[UniNode],
3090
3225
  ) -> None:
3091
3226
  self.values = values
@@ -3096,12 +3231,13 @@ class ListVal(AtomExpr):
3096
3231
  def normalize(self, deep: bool = False) -> bool:
3097
3232
  res = True
3098
3233
  if deep:
3099
- res = self.values.normalize(deep) if self.values else res
3100
- new_kid: list[UniNode] = [
3101
- self.gen_token(Tok.LSQUARE),
3102
- ]
3103
- if self.values:
3104
- new_kid.append(self.values)
3234
+ for i in self.values:
3235
+ res = res and i.normalize(deep)
3236
+ new_kid: list[UniNode] = [self.gen_token(Tok.LSQUARE)]
3237
+ for idx, val in enumerate(self.values):
3238
+ new_kid.append(val)
3239
+ if idx < len(self.values) - 1:
3240
+ new_kid.append(self.gen_token(Tok.COMMA))
3105
3241
  new_kid.append(self.gen_token(Tok.RSQUARE))
3106
3242
  self.set_kids(nodes=new_kid)
3107
3243
  return res
@@ -3112,10 +3248,10 @@ class SetVal(AtomExpr):
3112
3248
 
3113
3249
  def __init__(
3114
3250
  self,
3115
- values: Optional[SubNodeList[Expr]],
3251
+ values: Sequence[Expr] | None,
3116
3252
  kid: Sequence[UniNode],
3117
3253
  ) -> None:
3118
- self.values = values
3254
+ self.values: list[Expr] = list(values) if values else []
3119
3255
  UniNode.__init__(self, kid=kid)
3120
3256
  Expr.__init__(self)
3121
3257
  AstSymbolStubNode.__init__(self, sym_type=SymbolType.SEQUENCE)
@@ -3123,12 +3259,13 @@ class SetVal(AtomExpr):
3123
3259
  def normalize(self, deep: bool = False) -> bool:
3124
3260
  res = True
3125
3261
  if deep:
3126
- res = self.values.normalize(deep) if self.values else res
3127
- new_kid: list[UniNode] = [
3128
- self.gen_token(Tok.LBRACE),
3129
- ]
3130
- if self.values:
3131
- new_kid.append(self.values)
3262
+ for i in self.values:
3263
+ res = res and i.normalize(deep)
3264
+ new_kid: list[UniNode] = [self.gen_token(Tok.LBRACE)]
3265
+ for idx, val in enumerate(self.values):
3266
+ new_kid.append(val)
3267
+ if idx < len(self.values) - 1:
3268
+ new_kid.append(self.gen_token(Tok.COMMA))
3132
3269
  new_kid.append(self.gen_token(Tok.RBRACE))
3133
3270
  self.set_kids(nodes=new_kid)
3134
3271
  return res
@@ -3139,10 +3276,10 @@ class TupleVal(AtomExpr):
3139
3276
 
3140
3277
  def __init__(
3141
3278
  self,
3142
- values: Optional[SubNodeList[Expr | KWPair]],
3279
+ values: Sequence[Expr | KWPair],
3143
3280
  kid: Sequence[UniNode],
3144
3281
  ) -> None:
3145
- self.values = values
3282
+ self.values = list(values)
3146
3283
  UniNode.__init__(self, kid=kid)
3147
3284
  Expr.__init__(self)
3148
3285
  AstSymbolStubNode.__init__(self, sym_type=SymbolType.SEQUENCE)
@@ -3150,7 +3287,8 @@ class TupleVal(AtomExpr):
3150
3287
  def normalize(self, deep: bool = False) -> bool:
3151
3288
  res = True
3152
3289
  if deep:
3153
- res = self.values.normalize(deep) if self.values else res
3290
+ for i in self.values:
3291
+ res = res and i.normalize(deep)
3154
3292
  in_ret_type = (
3155
3293
  self.parent
3156
3294
  and isinstance(self.parent, IndexSlice)
@@ -3166,10 +3304,12 @@ class TupleVal(AtomExpr):
3166
3304
  if not in_ret_type
3167
3305
  else []
3168
3306
  )
3169
- if self.values:
3170
- new_kid.append(self.values)
3171
- if len(self.values.items) < 2:
3307
+ for idx, i in enumerate(self.values):
3308
+ new_kid.append(i)
3309
+ if idx < len(self.values) - 1:
3172
3310
  new_kid.append(self.gen_token(Tok.COMMA))
3311
+ if len(self.values) == 1:
3312
+ new_kid.append(self.gen_token(Tok.COMMA))
3173
3313
  if not in_ret_type:
3174
3314
  new_kid.append(self.gen_token(Tok.RPAREN))
3175
3315
  self.set_kids(nodes=new_kid)
@@ -3516,23 +3656,27 @@ class FuncCall(Expr):
3516
3656
  def __init__(
3517
3657
  self,
3518
3658
  target: Expr,
3519
- params: Optional[SubNodeList[Expr | KWPair]],
3659
+ params: Sequence[Expr | KWPair] | None,
3520
3660
  genai_call: Optional[FuncCall],
3521
3661
  kid: Sequence[UniNode],
3522
3662
  ) -> None:
3523
3663
  self.target = target
3524
- self.params = params
3664
+ self.params = list(params) if params else []
3525
3665
  self.genai_call = genai_call
3526
3666
  UniNode.__init__(self, kid=kid)
3527
3667
  Expr.__init__(self)
3528
3668
 
3529
3669
  def normalize(self, deep: bool = True) -> bool:
3670
+ res = True
3530
3671
  if deep:
3531
3672
  res = self.target.normalize(deep)
3532
- res = res and (not self.params or self.params.normalize(deep))
3673
+ for prm in self.params:
3674
+ res = res and prm.normalize(deep)
3533
3675
  new_kids = [self.target, self.gen_token(Tok.LPAREN, "(")]
3534
- if self.params:
3535
- new_kids.append(self.params)
3676
+ for i, prm in enumerate(self.params):
3677
+ new_kids.append(prm)
3678
+ if i < len(self.params) - 1:
3679
+ new_kids.append(self.gen_token(Tok.COMMA))
3536
3680
  if self.genai_call:
3537
3681
  new_kids.append(self.gen_token(Tok.KW_BY))
3538
3682
  new_kids.append(self.genai_call)
@@ -3780,11 +3924,11 @@ class FilterCompr(AtomExpr):
3780
3924
  def __init__(
3781
3925
  self,
3782
3926
  f_type: Optional[Expr],
3783
- compares: Optional[SubNodeList[CompareExpr]],
3927
+ compares: Sequence[CompareExpr],
3784
3928
  kid: Sequence[UniNode],
3785
3929
  ) -> None:
3786
3930
  self.f_type = f_type
3787
- self.compares = compares
3931
+ self.compares = list(compares)
3788
3932
  UniNode.__init__(self, kid=kid)
3789
3933
  Expr.__init__(self)
3790
3934
  AstSymbolStubNode.__init__(self, sym_type=SymbolType.SEQUENCE)
@@ -3793,7 +3937,8 @@ class FilterCompr(AtomExpr):
3793
3937
  res = True
3794
3938
  if deep:
3795
3939
  res = self.f_type.normalize(deep) if self.f_type else res
3796
- res = res and self.compares.normalize(deep) if self.compares else res
3940
+ for comp in self.compares:
3941
+ res = res and comp.normalize(deep)
3797
3942
  new_kid: list[UniNode] = []
3798
3943
  if not isinstance(self.parent, EdgeOpRef):
3799
3944
  new_kid.append(self.gen_token(Tok.LPAREN))
@@ -3805,7 +3950,10 @@ class FilterCompr(AtomExpr):
3805
3950
  if self.compares:
3806
3951
  if self.f_type:
3807
3952
  new_kid.append(self.gen_token(Tok.COLON))
3808
- new_kid.append(self.compares)
3953
+ for i, comp in enumerate(self.compares):
3954
+ new_kid.append(comp)
3955
+ if i < len(self.compares) - 1:
3956
+ new_kid.append(self.gen_token(Tok.COMMA))
3809
3957
  if not isinstance(self.parent, EdgeOpRef):
3810
3958
  new_kid.append(self.gen_token(Tok.RPAREN))
3811
3959
  self.set_kids(nodes=new_kid)
@@ -3817,10 +3965,10 @@ class AssignCompr(AtomExpr):
3817
3965
 
3818
3966
  def __init__(
3819
3967
  self,
3820
- assigns: SubNodeList[KWPair],
3968
+ assigns: Sequence[KWPair],
3821
3969
  kid: Sequence[UniNode],
3822
3970
  ) -> None:
3823
- self.assigns = assigns
3971
+ self.assigns = list(assigns)
3824
3972
  UniNode.__init__(self, kid=kid)
3825
3973
  Expr.__init__(self)
3826
3974
  AstSymbolStubNode.__init__(self, sym_type=SymbolType.SEQUENCE)
@@ -3828,14 +3976,21 @@ class AssignCompr(AtomExpr):
3828
3976
  def normalize(self, deep: bool = False) -> bool:
3829
3977
  res = True
3830
3978
  if deep:
3831
- res = self.assigns.normalize(deep)
3979
+ for assign in self.assigns:
3980
+ res = res and assign.normalize(deep)
3832
3981
  new_kid: list[UniNode] = []
3833
3982
  if isinstance(self.parent, ConnectOp):
3834
- new_kid.append(self.assigns)
3983
+ for i, assign in enumerate(self.assigns):
3984
+ new_kid.append(assign)
3985
+ if i < len(self.assigns) - 1:
3986
+ new_kid.append(self.gen_token(Tok.COMMA))
3835
3987
  else:
3836
3988
  new_kid.append(self.gen_token(Tok.LPAREN))
3837
3989
  new_kid.append(self.gen_token(Tok.EQ))
3838
- new_kid.append(self.assigns)
3990
+ for i, assign in enumerate(self.assigns):
3991
+ new_kid.append(assign)
3992
+ if i < len(self.assigns) - 1:
3993
+ new_kid.append(self.gen_token(Tok.COMMA))
3839
3994
  new_kid.append(self.gen_token(Tok.RPAREN))
3840
3995
  self.set_kids(nodes=new_kid)
3841
3996
  return res
@@ -4133,30 +4288,37 @@ class MatchArch(MatchPattern):
4133
4288
  def __init__(
4134
4289
  self,
4135
4290
  name: AtomTrailer | NameAtom,
4136
- arg_patterns: Optional[SubNodeList[MatchPattern]],
4137
- kw_patterns: Optional[SubNodeList[MatchKVPair]],
4291
+ arg_patterns: Sequence[MatchPattern] | None,
4292
+ kw_patterns: Sequence[MatchKVPair] | None,
4138
4293
  kid: Sequence[UniNode],
4139
4294
  ) -> None:
4140
4295
  self.name = name
4141
- self.arg_patterns = arg_patterns
4142
- self.kw_patterns = kw_patterns
4296
+ self.arg_patterns = list(arg_patterns) if arg_patterns else None
4297
+ self.kw_patterns = list(kw_patterns) if kw_patterns else None
4143
4298
  UniNode.__init__(self, kid=kid)
4144
4299
 
4145
4300
  def normalize(self, deep: bool = False) -> bool:
4146
4301
  res = True
4147
4302
  if deep:
4148
4303
  res = self.name.normalize(deep)
4149
- res = res and (not self.arg_patterns or self.arg_patterns.normalize(deep))
4150
- res = res and (not self.kw_patterns or self.kw_patterns.normalize(deep))
4304
+ for arg in self.arg_patterns or []:
4305
+ res = res and arg.normalize(deep)
4306
+ for kw in self.kw_patterns or []:
4307
+ res = res and kw.normalize(deep)
4151
4308
  new_kid: list[UniNode] = [self.name]
4152
4309
  new_kid.append(self.gen_token(Tok.LPAREN))
4153
4310
  if self.arg_patterns:
4154
- new_kid.append(self.arg_patterns)
4155
- new_kid.append(self.gen_token(Tok.COMMA))
4311
+ for idx, arg in enumerate(self.arg_patterns):
4312
+ new_kid.append(arg)
4313
+ if idx < len(self.arg_patterns) - 1:
4314
+ new_kid.append(self.gen_token(Tok.COMMA))
4315
+ if self.kw_patterns:
4316
+ new_kid.append(self.gen_token(Tok.COMMA))
4156
4317
  if self.kw_patterns:
4157
- new_kid.append(self.kw_patterns)
4158
- else:
4159
- new_kid.pop()
4318
+ for idx, kw in enumerate(self.kw_patterns):
4319
+ new_kid.append(kw)
4320
+ if idx < len(self.kw_patterns) - 1:
4321
+ new_kid.append(self.gen_token(Tok.COMMA))
4160
4322
  new_kid.append(self.gen_token(Tok.RPAREN))
4161
4323
  self.set_kids(nodes=new_kid)
4162
4324
  return res
@@ -4214,10 +4376,9 @@ class Name(Token, NameAtom):
4214
4376
  col_end: int,
4215
4377
  pos_start: int,
4216
4378
  pos_end: int,
4217
- is_enum_singleton: bool = False,
4379
+ is_enum_stmt: bool = False,
4218
4380
  is_kwesc: bool = False,
4219
4381
  ) -> None:
4220
- self.is_enum_singleton = is_enum_singleton
4221
4382
  self.is_kwesc = is_kwesc
4222
4383
  Token.__init__(
4223
4384
  self,
@@ -4231,7 +4392,7 @@ class Name(Token, NameAtom):
4231
4392
  pos_start=pos_start,
4232
4393
  pos_end=pos_end,
4233
4394
  )
4234
- NameAtom.__init__(self)
4395
+ NameAtom.__init__(self, is_enum_stmt=is_enum_stmt)
4235
4396
  AstSymbolNode.__init__(
4236
4397
  self,
4237
4398
  sym_name=value,
@@ -4242,7 +4403,7 @@ class Name(Token, NameAtom):
4242
4403
  def unparse(self) -> str:
4243
4404
  super().unparse()
4244
4405
  return (f"<>{self.value}" if self.is_kwesc else self.value) + (
4245
- ",\n" if self.is_enum_singleton else ""
4406
+ ",\n" if self.is_enum_stmt else ""
4246
4407
  )
4247
4408
 
4248
4409
  @staticmethod
@@ -4272,6 +4433,7 @@ class SpecialVarRef(Name):
4272
4433
  def __init__(
4273
4434
  self,
4274
4435
  var: Name,
4436
+ is_enum_stmt: bool = False,
4275
4437
  ) -> None:
4276
4438
  self.orig = var
4277
4439
  Name.__init__(
@@ -4286,7 +4448,7 @@ class SpecialVarRef(Name):
4286
4448
  pos_start=var.pos_start,
4287
4449
  pos_end=var.pos_end,
4288
4450
  )
4289
- NameAtom.__init__(self)
4451
+ NameAtom.__init__(self, is_enum_stmt=is_enum_stmt)
4290
4452
  AstSymbolNode.__init__(
4291
4453
  self,
4292
4454
  sym_name=self.py_resolve_name(),
@@ -4423,12 +4585,7 @@ class String(Literal):
4423
4585
  ) and not self.find_parent_of_type(FString):
4424
4586
  return repr_str[3:-3]
4425
4587
  if (not self.find_parent_of_type(FString)) or (
4426
- not (
4427
- self.parent
4428
- and isinstance(self.parent, SubNodeList)
4429
- and self.parent.parent
4430
- and isinstance(self.parent.parent, FString)
4431
- )
4588
+ not (self.parent and isinstance(self.parent, FString))
4432
4589
  ):
4433
4590
  return repr_str[1:-1]
4434
4591
  return repr_str
@@ -4599,9 +4756,4 @@ class PythonModuleAst(EmptyToken):
4599
4756
  super().__init__()
4600
4757
  self.ast = ast
4601
4758
  self.orig_src = orig_src
4602
-
4603
- # This bellow attribute is un-necessary since it already exists in the orig_src
4604
- # however I'm keeping it here not to break existing code trying to access file_path.
4605
- # We can remove this in the future once we safley remove all references to it and
4606
- # use orig_src.
4607
4759
  self.file_path = orig_src.file_path