jaclang 0.5.6__py3-none-any.whl → 0.5.8__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 (51) hide show
  1. jaclang/__init__.py +6 -1
  2. jaclang/cli/cli.py +63 -20
  3. jaclang/cli/cmdreg.py +42 -12
  4. jaclang/compiler/__init__.py +6 -3
  5. jaclang/compiler/__jac_gen__/jac_parser.py +2 -2
  6. jaclang/compiler/absyntree.py +1740 -61
  7. jaclang/compiler/codeloc.py +7 -0
  8. jaclang/compiler/compile.py +4 -5
  9. jaclang/compiler/constant.py +52 -6
  10. jaclang/compiler/parser.py +220 -129
  11. jaclang/compiler/passes/main/def_impl_match_pass.py +19 -3
  12. jaclang/compiler/passes/main/def_use_pass.py +1 -1
  13. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +357 -0
  14. jaclang/compiler/passes/main/import_pass.py +7 -3
  15. jaclang/compiler/passes/main/pyast_gen_pass.py +333 -93
  16. jaclang/compiler/passes/main/pyast_load_pass.py +1779 -206
  17. jaclang/compiler/passes/main/pyout_pass.py +2 -2
  18. jaclang/compiler/passes/main/schedules.py +2 -1
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +20 -28
  20. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +4 -4
  21. jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +14 -5
  22. jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +8 -8
  23. jaclang/compiler/passes/main/tests/test_typeinfo_pass.py +7 -0
  24. jaclang/compiler/passes/main/type_check_pass.py +0 -1
  25. jaclang/compiler/passes/tool/jac_formatter_pass.py +8 -17
  26. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +43 -0
  27. jaclang/compiler/passes/utils/mypy_ast_build.py +28 -14
  28. jaclang/compiler/symtable.py +23 -2
  29. jaclang/compiler/tests/test_parser.py +53 -0
  30. jaclang/compiler/workspace.py +52 -26
  31. jaclang/core/aott.py +68 -0
  32. jaclang/core/construct.py +58 -6
  33. jaclang/core/importer.py +9 -10
  34. jaclang/core/utils.py +65 -3
  35. jaclang/plugin/builtin.py +42 -0
  36. jaclang/plugin/default.py +163 -18
  37. jaclang/plugin/feature.py +38 -10
  38. jaclang/plugin/spec.py +33 -6
  39. jaclang/utils/helpers.py +25 -0
  40. jaclang/utils/lang_tools.py +4 -1
  41. jaclang/utils/test.py +1 -0
  42. jaclang/utils/tests/test_lang_tools.py +12 -15
  43. jaclang/utils/treeprinter.py +10 -2
  44. {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/METADATA +1 -1
  45. {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/RECORD +48 -46
  46. {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/WHEEL +1 -1
  47. jaclang/compiler/tests/fixtures/__jac_gen__/__init__.py +0 -0
  48. jaclang/compiler/tests/fixtures/__jac_gen__/hello_world.py +0 -5
  49. jaclang/core/jacbuiltins.py +0 -10
  50. {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/entry_points.txt +0 -0
  51. {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/top_level.txt +0 -0
@@ -138,6 +138,16 @@ class PyastGenPass(Pass):
138
138
  jac_node=self.ir,
139
139
  )
140
140
  )
141
+ self.preamble.append(
142
+ self.sync(
143
+ ast3.ImportFrom(
144
+ module="jaclang.plugin.builtin",
145
+ names=[self.sync(ast3.alias(name="*", asname=None))],
146
+ level=0,
147
+ ),
148
+ jac_node=self.ir,
149
+ )
150
+ )
141
151
  self.already_added.append("jac_feature")
142
152
 
143
153
  def needs_dataclass(self) -> None:
@@ -200,9 +210,18 @@ class PyastGenPass(Pass):
200
210
  i.col_offset = jac_node.loc.col_start
201
211
  i.end_lineno = jac_node.loc.last_line
202
212
  i.end_col_offset = jac_node.loc.col_end
203
- i.jac_link = jac_node # type: ignore
213
+ i.jac_link: list[ast3.AST] = [jac_node] # type: ignore
204
214
  return py_node
205
215
 
216
+ def link_jac_py_nodes(
217
+ self, jac_node: ast.AstNode, py_nodes: list[ast3.AST]
218
+ ) -> None:
219
+ """Link jac name ast to py ast nodes."""
220
+ jac_node.gen.py_ast = py_nodes
221
+ for i in py_nodes:
222
+ if isinstance(i.jac_link, list): # type: ignore
223
+ i.jac_link.append(jac_node) # type: ignore
224
+
206
225
  def pyinline_sync(
207
226
  self,
208
227
  py_nodes: list[ast3.AST],
@@ -215,7 +234,7 @@ class PyastGenPass(Pass):
215
234
  i.lineno += self.cur_node.loc.first_line
216
235
  if hasattr(i, "end_lineno") and i.end_lineno is not None:
217
236
  i.end_lineno += self.cur_node.loc.first_line
218
- i.jac_link = self.cur_node # type: ignore
237
+ i.jac_link: ast3.AST = [self.cur_node] # type: ignore
219
238
  return py_nodes
220
239
 
221
240
  def resolve_stmt_block(
@@ -237,7 +256,7 @@ class PyastGenPass(Pass):
237
256
  [
238
257
  x.gen.py_ast
239
258
  for x in node.items
240
- # if not isinstance(x, ast.AstImplOnlyNode)
259
+ if not isinstance(x, ast.AstImplOnlyNode)
241
260
  ]
242
261
  )
243
262
  if node and isinstance(node.gen.py_ast, list)
@@ -295,7 +314,8 @@ class PyastGenPass(Pass):
295
314
  body: Sequence[ElementStmt],
296
315
  is_imported: bool,
297
316
  """
298
- pre_body = [*node.impl_mod.body, *node.body] if node.impl_mod else node.body
317
+ clean_body = [i for i in node.body if not isinstance(i, ast.AstImplOnlyNode)]
318
+ pre_body = [*node.impl_mod.body, *clean_body] if node.impl_mod else clean_body
299
319
  pre_body = [*pre_body, *node.test_mod.body] if node.test_mod else pre_body
300
320
  body = (
301
321
  [
@@ -557,6 +577,8 @@ class PyastGenPass(Pass):
557
577
  )
558
578
  )
559
579
  ]
580
+ if node.alias:
581
+ self.link_jac_py_nodes(jac_node=node.alias, py_nodes=node.gen.py_ast)
560
582
 
561
583
  def exit_module_item(self, node: ast.ModuleItem) -> None:
562
584
  """Sub objects.
@@ -681,6 +703,9 @@ class PyastGenPass(Pass):
681
703
  )
682
704
  )
683
705
  ]
706
+ self.link_jac_py_nodes(jac_node=node.name, py_nodes=node.gen.py_ast)
707
+ if isinstance(node.body, ast.ArchDef):
708
+ self.link_jac_py_nodes(jac_node=node.body, py_nodes=node.gen.py_ast)
684
709
 
685
710
  def collect_events(
686
711
  self, node: ast.Architype
@@ -733,6 +758,12 @@ class PyastGenPass(Pass):
733
758
  doc: Optional[String],
734
759
  decorators: Optional[SubNodeList[ExprType]],
735
760
  """
761
+ for i in node.target.archs:
762
+ if i.sym_link:
763
+ self.link_jac_py_nodes(jac_node=i, py_nodes=i.sym_link.decl.gen.py_ast)
764
+ self.link_jac_py_nodes(
765
+ jac_node=i.name_ref, py_nodes=i.sym_link.decl.gen.py_ast
766
+ )
736
767
 
737
768
  def exit_enum(self, node: ast.Enum) -> None:
738
769
  """Sub objects.
@@ -773,6 +804,8 @@ class PyastGenPass(Pass):
773
804
  )
774
805
  )
775
806
  ]
807
+ if isinstance(node.body, ast.EnumDef):
808
+ self.link_jac_py_nodes(jac_node=node.body, py_nodes=node.gen.py_ast)
776
809
 
777
810
  def exit_enum_def(self, node: ast.EnumDef) -> None:
778
811
  """Sub objects.
@@ -782,6 +815,12 @@ class PyastGenPass(Pass):
782
815
  doc: Optional[String],
783
816
  decorators: Optional[SubNodeList[ExprType]],
784
817
  """
818
+ for i in node.target.archs:
819
+ if i.sym_link:
820
+ self.link_jac_py_nodes(jac_node=i, py_nodes=i.sym_link.decl.gen.py_ast)
821
+ self.link_jac_py_nodes(
822
+ jac_node=i.name_ref, py_nodes=i.sym_link.decl.gen.py_ast
823
+ )
785
824
 
786
825
  def exit_ability(self, node: ast.Ability) -> None:
787
826
  """Sub objects.
@@ -793,27 +832,33 @@ class PyastGenPass(Pass):
793
832
  is_abstract: bool,
794
833
  access: Optional[SubTag[Token]],
795
834
  signature: Optional[FuncSignature | ExprType | EventSignature],
796
- body: Optional[SubNodeList[CodeBlockStmt]],
835
+ body: Optional[SubNodeList[CodeBlockStmt] | AbilityDef | FuncCall],
797
836
  doc: Optional[String],
798
837
  decorators: Optional[SubNodeList[ExprType]],
799
838
  """
800
839
  func_type = ast3.AsyncFunctionDef if node.is_async else ast3.FunctionDef
801
840
  body = (
802
- [
803
- self.sync(ast3.Expr(value=node.doc.gen.py_ast[0]), jac_node=node.doc),
804
- self.sync(ast3.Pass(), node.body),
805
- ]
806
- if node.doc and node.is_abstract
841
+ self.gen_llm_body(node)
842
+ if isinstance(node.body, ast.FuncCall)
807
843
  else (
808
- [self.sync(ast3.Pass(), node.body)]
809
- if node.is_abstract
810
- else self.resolve_stmt_block(
811
- (
812
- node.body.body
813
- if isinstance(node.body, ast.AbilityDef)
814
- else node.body
844
+ [
845
+ self.sync(
846
+ ast3.Expr(value=node.doc.gen.py_ast[0]), jac_node=node.doc
815
847
  ),
816
- doc=node.doc,
848
+ self.sync(ast3.Pass(), node.body),
849
+ ]
850
+ if node.doc and node.is_abstract
851
+ else (
852
+ [self.sync(ast3.Pass(), node.body)]
853
+ if node.is_abstract
854
+ else self.resolve_stmt_block(
855
+ (
856
+ node.body.body
857
+ if isinstance(node.body, ast.AbilityDef)
858
+ else node.body
859
+ ),
860
+ doc=node.doc,
861
+ )
817
862
  )
818
863
  )
819
864
  )
@@ -857,8 +902,10 @@ class PyastGenPass(Pass):
857
902
  decorator_list.insert(
858
903
  0, self.sync(ast3.Name(id="staticmethod", ctx=ast3.Load()))
859
904
  )
860
- if not body:
905
+ if not body and not isinstance(node.body, ast.FuncCall):
861
906
  self.error("Ability has no body. Perhaps an impl must be imported.", node)
907
+ body = [self.sync(ast3.Pass(), node)]
908
+
862
909
  node.gen.py_ast = [
863
910
  self.sync(
864
911
  func_type(
@@ -875,6 +922,184 @@ class PyastGenPass(Pass):
875
922
  )
876
923
  )
877
924
  ]
925
+ self.link_jac_py_nodes(jac_node=node.name_ref, py_nodes=node.gen.py_ast)
926
+ if isinstance(node.body, ast.AbilityDef):
927
+ self.link_jac_py_nodes(jac_node=node.body, py_nodes=node.gen.py_ast)
928
+
929
+ def gen_llm_body(self, node: ast.Ability) -> list[ast3.AST]:
930
+ """Generate llm body."""
931
+ if isinstance(node.body, ast.FuncCall):
932
+ model_params = (
933
+ {
934
+ param.key: param.value
935
+ for param in node.body.params.items
936
+ if isinstance(param, ast.KWPair)
937
+ }
938
+ if node.body.params
939
+ else {}
940
+ )
941
+ return [
942
+ self.sync(
943
+ ast3.Return(
944
+ value=self.sync(
945
+ ast3.Call(
946
+ func=self.sync(
947
+ ast3.Attribute(
948
+ value=self.sync(
949
+ ast3.Name(
950
+ id=Con.JAC_FEATURE.value,
951
+ ctx=ast3.Load(),
952
+ )
953
+ ),
954
+ attr="with_llm",
955
+ ctx=ast3.Load(),
956
+ )
957
+ ),
958
+ args=[],
959
+ keywords=[
960
+ self.sync(
961
+ ast3.keyword(
962
+ arg="model",
963
+ value=node.body.target.gen.py_ast[0],
964
+ )
965
+ ),
966
+ self.sync(
967
+ ast3.keyword(
968
+ arg="model_params",
969
+ value=self.sync(
970
+ ast3.Dict(
971
+ keys=[
972
+ self.sync(ast3.Constant(value=key.value)) # type: ignore
973
+ for key in model_params.keys()
974
+ ],
975
+ values=[
976
+ value.gen.py_ast[0]
977
+ for value in model_params.values()
978
+ ],
979
+ )
980
+ ),
981
+ )
982
+ ),
983
+ self.sync(
984
+ ast3.keyword(
985
+ arg="incl_info",
986
+ value=self.sync(
987
+ ast3.Constant(value=None)
988
+ ), # TODO: Add incl_info
989
+ )
990
+ ),
991
+ self.sync(
992
+ ast3.keyword(
993
+ arg="excl_info",
994
+ value=self.sync(
995
+ ast3.Constant(value=None)
996
+ ), # TODO: Add excl_info
997
+ )
998
+ ),
999
+ self.sync(
1000
+ ast3.keyword(
1001
+ arg="inputs",
1002
+ value=self.sync(
1003
+ ast3.List(
1004
+ elts=(
1005
+ [
1006
+ self.sync(
1007
+ ast3.Tuple(
1008
+ elts=[
1009
+ (
1010
+ param.semstr.gen.py_ast[
1011
+ 0
1012
+ ]
1013
+ if param.semstr
1014
+ else None
1015
+ ),
1016
+ (
1017
+ param.type_tag.tag.gen.py_ast[
1018
+ 0
1019
+ ]
1020
+ if param.type_tag
1021
+ else None
1022
+ ),
1023
+ self.sync(
1024
+ ast3.Constant(
1025
+ value=param.name.value
1026
+ )
1027
+ ),
1028
+ self.sync(
1029
+ ast3.Name(
1030
+ id=param.name.value,
1031
+ ctx=ast3.Load(),
1032
+ )
1033
+ ),
1034
+ ],
1035
+ ctx=ast3.Load(),
1036
+ )
1037
+ )
1038
+ for param in node.signature.params.items
1039
+ ]
1040
+ if isinstance(
1041
+ node.signature,
1042
+ ast.FuncSignature,
1043
+ )
1044
+ and node.signature.params
1045
+ else []
1046
+ ),
1047
+ ctx=ast3.Load(),
1048
+ )
1049
+ ),
1050
+ )
1051
+ ),
1052
+ self.sync(
1053
+ ast3.keyword(
1054
+ arg="outputs",
1055
+ value=self.sync(
1056
+ ast3.Tuple(
1057
+ elts=(
1058
+ [
1059
+ (
1060
+ node.signature.semstr.gen.py_ast[
1061
+ 0
1062
+ ]
1063
+ if node.signature.semstr
1064
+ else None
1065
+ ),
1066
+ (
1067
+ node.signature.return_type.gen.py_ast[
1068
+ 0
1069
+ ]
1070
+ if node.signature.return_type
1071
+ else None
1072
+ ),
1073
+ ]
1074
+ if isinstance(
1075
+ node.signature,
1076
+ ast.FuncSignature,
1077
+ )
1078
+ else []
1079
+ ),
1080
+ ctx=ast3.Load(),
1081
+ )
1082
+ ),
1083
+ )
1084
+ ), # TODO: Add Meaning Types of Outputs
1085
+ self.sync(
1086
+ ast3.keyword(
1087
+ arg="action",
1088
+ value=(
1089
+ node.semstr.gen.py_ast[0]
1090
+ if node.semstr
1091
+ else None
1092
+ ),
1093
+ )
1094
+ ),
1095
+ ],
1096
+ )
1097
+ )
1098
+ )
1099
+ )
1100
+ ]
1101
+ else:
1102
+ return []
878
1103
 
879
1104
  def exit_ability_def(self, node: ast.AbilityDef) -> None:
880
1105
  """Sub objects.
@@ -885,6 +1110,15 @@ class PyastGenPass(Pass):
885
1110
  doc: Optional[String],
886
1111
  decorators: Optional[SubNodeList[ExprType]],
887
1112
  """
1113
+ for i in node.target.archs:
1114
+ if i.sym_link:
1115
+ self.link_jac_py_nodes(jac_node=i, py_nodes=i.sym_link.decl.gen.py_ast)
1116
+ self.link_jac_py_nodes(
1117
+ jac_node=i.name_ref, py_nodes=i.sym_link.decl.gen.py_ast
1118
+ )
1119
+ if isinstance(node.parent, ast.Ability) and node.parent.signature:
1120
+ # TODO: Here we need to do a link for each subnode to the original parent signature
1121
+ pass
888
1122
 
889
1123
  def exit_func_signature(self, node: ast.FuncSignature) -> None:
890
1124
  """Sub objects.
@@ -973,7 +1207,7 @@ class PyastGenPass(Pass):
973
1207
  if node.arch.name == Tok.TYPE_OP:
974
1208
  if (
975
1209
  isinstance(node.name_ref, ast.SpecialVarRef)
976
- and node.name_ref.var.name == Tok.ROOT_OP
1210
+ and node.name_ref.var.name == Tok.KW_ROOT
977
1211
  ):
978
1212
  node.gen.py_ast = [
979
1213
  self.sync(
@@ -1041,6 +1275,7 @@ class PyastGenPass(Pass):
1041
1275
  )
1042
1276
  )
1043
1277
  ]
1278
+ self.link_jac_py_nodes(jac_node=node.name, py_nodes=node.gen.py_ast)
1044
1279
 
1045
1280
  def exit_arch_has(self, node: ast.ArchHas) -> None:
1046
1281
  """Sub objects.
@@ -1296,6 +1531,8 @@ class PyastGenPass(Pass):
1296
1531
  )
1297
1532
  )
1298
1533
  ]
1534
+ if node.name:
1535
+ self.link_jac_py_nodes(jac_node=node.name, py_nodes=node.gen.py_ast)
1299
1536
 
1300
1537
  def exit_finally_stmt(self, node: ast.FinallyStmt) -> None:
1301
1538
  """Sub objects.
@@ -1403,6 +1640,9 @@ class PyastGenPass(Pass):
1403
1640
  )
1404
1641
  )
1405
1642
  ]
1643
+ self.link_jac_py_nodes(jac_node=node.expr, py_nodes=node.gen.py_ast)
1644
+ if node.alias:
1645
+ self.link_jac_py_nodes(jac_node=node.alias, py_nodes=node.gen.py_ast)
1406
1646
 
1407
1647
  def exit_raise_stmt(self, node: ast.RaiseStmt) -> None:
1408
1648
  """Sub objects.
@@ -1660,6 +1900,7 @@ class PyastGenPass(Pass):
1660
1900
  jac_node=x,
1661
1901
  )
1662
1902
  )
1903
+ self.link_jac_py_nodes(jac_node=x, py_nodes=[py_nodes[-1]])
1663
1904
  node.gen.py_ast = [*py_nodes]
1664
1905
 
1665
1906
  def exit_non_local_stmt(self, node: ast.NonLocalStmt) -> None:
@@ -1675,6 +1916,7 @@ class PyastGenPass(Pass):
1675
1916
  jac_node=x,
1676
1917
  )
1677
1918
  )
1919
+ self.link_jac_py_nodes(jac_node=x, py_nodes=[py_nodes[-1]])
1678
1920
  node.gen.py_ast = [*py_nodes]
1679
1921
 
1680
1922
  def exit_assignment(self, node: ast.Assignment) -> None:
@@ -1685,6 +1927,21 @@ class PyastGenPass(Pass):
1685
1927
  type_tag: Optional[SubTag[ExprType]],
1686
1928
  mutable: bool =True,
1687
1929
  """
1930
+ value = (
1931
+ node.value.gen.py_ast[0]
1932
+ if node.value
1933
+ else (
1934
+ self.sync(
1935
+ ast3.Call(
1936
+ func=self.sync(ast3.Name(id="__jac_auto__", ctx=ast3.Load())),
1937
+ args=[],
1938
+ keywords=[],
1939
+ )
1940
+ )
1941
+ if node.is_enum_stmt
1942
+ else self.ice()
1943
+ )
1944
+ )
1688
1945
  if node.type_tag:
1689
1946
  node.gen.py_ast = [
1690
1947
  self.sync(
@@ -1696,25 +1953,19 @@ class PyastGenPass(Pass):
1696
1953
  )
1697
1954
  )
1698
1955
  ]
1699
- elif not node.value:
1700
- self.ice()
1701
1956
  elif node.aug_op:
1702
1957
  node.gen.py_ast = [
1703
1958
  self.sync(
1704
1959
  ast3.AugAssign(
1705
1960
  target=node.target.items[0].gen.py_ast[0],
1706
1961
  op=node.aug_op.gen.py_ast[0],
1707
- value=node.value.gen.py_ast[0],
1962
+ value=value,
1708
1963
  )
1709
1964
  )
1710
1965
  ]
1711
1966
  else:
1712
1967
  node.gen.py_ast = [
1713
- self.sync(
1714
- ast3.Assign(
1715
- targets=node.target.gen.py_ast, value=node.value.gen.py_ast[0]
1716
- )
1717
- )
1968
+ self.sync(ast3.Assign(targets=node.target.gen.py_ast, value=value))
1718
1969
  ]
1719
1970
 
1720
1971
  def exit_binary_expr(self, node: ast.BinaryExpr) -> None:
@@ -1845,7 +2096,9 @@ class PyastGenPass(Pass):
1845
2096
  params=(
1846
2097
  node.left.values
1847
2098
  if isinstance(node.left, ast.TupleVal)
1848
- else ast.SubNodeList(items=[node.left], kid=[node.left])
2099
+ else ast.SubNodeList(
2100
+ items=[node.left], delim=Tok.COMMA, kid=[node.left]
2101
+ )
1849
2102
  ),
1850
2103
  kid=node.kid,
1851
2104
  )
@@ -1879,7 +2132,9 @@ class PyastGenPass(Pass):
1879
2132
  params=(
1880
2133
  node.right.values
1881
2134
  if isinstance(node.right, ast.TupleVal)
1882
- else ast.SubNodeList(items=[node.right], kid=[node.right])
2135
+ else ast.SubNodeList(
2136
+ items=[node.right], delim=Tok.COMMA, kid=[node.right]
2137
+ )
1883
2138
  ),
1884
2139
  kid=node.kid,
1885
2140
  )
@@ -2101,13 +2356,6 @@ class PyastGenPass(Pass):
2101
2356
  else [self.sync(ast3.Constant(value=""))]
2102
2357
  )
2103
2358
 
2104
- def exit_expr_list(self, node: ast.ExprList) -> None:
2105
- """Sub objects.
2106
-
2107
- values: Optional[SubNodeList[ExprType]],
2108
- """
2109
- node.gen.py_ast = node.values.gen.py_ast if node.values else []
2110
-
2111
2359
  def exit_list_val(self, node: ast.ListVal) -> None:
2112
2360
  """Sub objects.
2113
2361
 
@@ -2188,6 +2436,8 @@ class PyastGenPass(Pass):
2188
2436
  )
2189
2437
  )
2190
2438
  ]
2439
+ if node.key:
2440
+ self.link_jac_py_nodes(jac_node=node.key, py_nodes=node.gen.py_ast)
2191
2441
 
2192
2442
  def exit_inner_compr(self, node: ast.InnerCompr) -> None:
2193
2443
  """Sub objects.
@@ -2202,7 +2452,11 @@ class PyastGenPass(Pass):
2202
2452
  ast3.comprehension(
2203
2453
  target=node.target.gen.py_ast[0],
2204
2454
  iter=node.collection.gen.py_ast[0],
2205
- ifs=node.conditional.gen.py_ast if node.conditional else [],
2455
+ ifs=(
2456
+ [x.gen.py_ast[0] for x in node.conditional]
2457
+ if node.conditional
2458
+ else []
2459
+ ),
2206
2460
  is_async=0,
2207
2461
  )
2208
2462
  )
@@ -2212,7 +2466,7 @@ class PyastGenPass(Pass):
2212
2466
  """Sub objects.
2213
2467
 
2214
2468
  out_expr: ExprType,
2215
- compr: InnerCompr,
2469
+ compr: list[InnerCompr]
2216
2470
  """
2217
2471
  node.gen.py_ast = [
2218
2472
  self.sync(
@@ -2227,7 +2481,7 @@ class PyastGenPass(Pass):
2227
2481
  """Sub objects.
2228
2482
 
2229
2483
  out_expr: ExprType,
2230
- compr: InnerCompr,
2484
+ compr: list[InnerCompr]
2231
2485
  """
2232
2486
  node.gen.py_ast = [
2233
2487
  self.sync(
@@ -2242,7 +2496,7 @@ class PyastGenPass(Pass):
2242
2496
  """Sub objects.
2243
2497
 
2244
2498
  out_expr: ExprType,
2245
- compr: InnerCompr,
2499
+ compr: list[InnerCompr]
2246
2500
  """
2247
2501
  node.gen.py_ast = [
2248
2502
  self.sync(
@@ -2276,27 +2530,25 @@ class PyastGenPass(Pass):
2276
2530
 
2277
2531
  target: Expr,
2278
2532
  right: AtomExpr | Expr,
2279
- is_attr: Optional[Token],
2533
+ is_attr: bool,
2280
2534
  is_null_ok: bool,
2281
2535
  """
2282
2536
  if node.is_attr:
2283
- node.gen.py_ast = [
2284
- self.sync(
2285
- ast3.Attribute(
2286
- value=node.target.gen.py_ast[0],
2287
- attr=(
2288
- node.right.sym_name
2289
- if isinstance(node.right, ast.AstSymbolNode)
2290
- else ""
2291
- ),
2292
- ctx=(
2293
- node.right.py_ctx_func()
2294
- if isinstance(node.right, ast.AstSymbolNode)
2295
- else ast3.Load()
2296
- ),
2537
+ if isinstance(node.right, ast.AstSymbolNode):
2538
+ node.gen.py_ast = [
2539
+ self.sync(
2540
+ ast3.Attribute(
2541
+ value=node.target.gen.py_ast[0],
2542
+ attr=(node.right.sym_name),
2543
+ ctx=(node.right.py_ctx_func()),
2544
+ )
2297
2545
  )
2546
+ ]
2547
+ self.link_jac_py_nodes(
2548
+ jac_node=node.right.sym_name_node, py_nodes=node.gen.py_ast
2298
2549
  )
2299
- ]
2550
+ else:
2551
+ self.error("Invalid attribute access")
2300
2552
  elif isinstance(node.right, ast.FilterCompr):
2301
2553
  node.gen.py_ast = [
2302
2554
  self.sync(
@@ -2376,19 +2628,11 @@ class PyastGenPass(Pass):
2376
2628
  target: Expr,
2377
2629
  params: Optional[SubNodeList[Expr | KWPair]],
2378
2630
  """
2379
- node.gen.py_ast = [self.sync(self.gen_func_call(node.target, node.params))]
2380
-
2381
- def gen_func_call(
2382
- self,
2383
- target: ast.Expr,
2384
- params: Optional[ast.SubNodeList[ast.Expr | ast.KWPair]],
2385
- ) -> ast3.Call:
2386
- """Generate a function call."""
2387
- func = target.gen.py_ast[0]
2631
+ func = node.target.gen.py_ast[0]
2388
2632
  args = []
2389
2633
  keywords = []
2390
- if params and len(params.items) > 0:
2391
- for x in params.items:
2634
+ if node.params and len(node.params.items) > 0:
2635
+ for x in node.params.items:
2392
2636
  if isinstance(x, ast.UnaryExpr) and x.op.name == Tok.STAR_POW:
2393
2637
  keywords.append(
2394
2638
  self.sync(ast3.keyword(value=x.operand.gen.py_ast[0]), x)
@@ -2401,7 +2645,9 @@ class PyastGenPass(Pass):
2401
2645
  keywords.append(x.gen.py_ast[0])
2402
2646
  else:
2403
2647
  self.ice("Invalid Parameter")
2404
- return ast3.Call(func=func, args=args, keywords=keywords)
2648
+ node.gen.py_ast = [
2649
+ self.sync(ast3.Call(func=func, args=args, keywords=keywords))
2650
+ ]
2405
2651
 
2406
2652
  def exit_index_slice(self, node: ast.IndexSlice) -> None:
2407
2653
  """Sub objects.
@@ -2441,7 +2687,7 @@ class PyastGenPass(Pass):
2441
2687
  def exit_edge_ref_trailer(self, node: ast.EdgeRefTrailer) -> None:
2442
2688
  """Sub objects.
2443
2689
 
2444
- chain: list[Expr],
2690
+ chain: list[Expr|FilterCompr],
2445
2691
  edges_only: bool,
2446
2692
  """
2447
2693
  pynode = node.chain[0].gen.py_ast[0]
@@ -2461,11 +2707,23 @@ class PyastGenPass(Pass):
2461
2707
  not next_i or not isinstance(next_i, ast.EdgeOpRef)
2462
2708
  ):
2463
2709
  pynode = self.translate_edge_op_ref(
2464
- pynode,
2465
- cur,
2466
- targ=next_i.gen.py_ast[0] if next_i else None,
2710
+ loc=pynode,
2711
+ node=cur,
2712
+ targ=(
2713
+ next_i.gen.py_ast[0]
2714
+ if next_i and not isinstance(next_i, ast.FilterCompr)
2715
+ else None
2716
+ ),
2467
2717
  edges_only=node.edges_only and cur == last_edge,
2468
2718
  )
2719
+ if next_i and isinstance(next_i, ast.FilterCompr):
2720
+ pynode = self.sync(
2721
+ ast3.Call(
2722
+ func=next_i.gen.py_ast[0],
2723
+ args=[pynode],
2724
+ keywords=[],
2725
+ )
2726
+ )
2469
2727
  chomp = chomp[1:] if next_i else chomp
2470
2728
  elif isinstance(cur, ast.EdgeOpRef) and isinstance(next_i, ast.EdgeOpRef):
2471
2729
  pynode = self.translate_edge_op_ref(
@@ -2772,14 +3030,14 @@ class PyastGenPass(Pass):
2772
3030
 
2773
3031
  pattern: MatchPattern,
2774
3032
  guard: Optional[ExprType],
2775
- body: SubNodeList[CodeBlockStmt],
3033
+ body: list[CodeBlockStmt],
2776
3034
  """
2777
3035
  node.gen.py_ast = [
2778
3036
  self.sync(
2779
3037
  ast3.match_case(
2780
3038
  pattern=node.pattern.gen.py_ast[0],
2781
3039
  guard=node.guard.gen.py_ast[0] if node.guard else None,
2782
- body=self.resolve_stmt_block(node.body),
3040
+ body=[x.gen.py_ast[0] for x in node.body],
2783
3041
  )
2784
3042
  )
2785
3043
  ]
@@ -3000,24 +3258,6 @@ class PyastGenPass(Pass):
3000
3258
  node.gen.py_ast = [
3001
3259
  self.sync(ast3.Name(id=node.sym_name, ctx=node.py_ctx_func()))
3002
3260
  ]
3003
- if node.is_enum_singleton and isinstance(node.gen.py_ast[0], ast3.Name):
3004
- node.gen.py_ast[0].ctx = ast3.Store()
3005
- node.gen.py_ast = [
3006
- self.sync(
3007
- ast3.Assign(
3008
- targets=node.gen.py_ast,
3009
- value=self.sync(
3010
- ast3.Call(
3011
- func=self.sync(
3012
- ast3.Name(id="__jac_auto__", ctx=ast3.Load())
3013
- ),
3014
- args=[],
3015
- keywords=[],
3016
- )
3017
- ),
3018
- )
3019
- )
3020
- ]
3021
3261
 
3022
3262
  def exit_float(self, node: ast.Float) -> None:
3023
3263
  """Sub objects.