jaclang 0.7.30__py3-none-any.whl → 0.7.32__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 (35) hide show
  1. jaclang/__init__.py +419 -3
  2. jaclang/compiler/absyntree.py +3 -3
  3. jaclang/compiler/constant.py +4 -4
  4. jaclang/compiler/jac.lark +226 -175
  5. jaclang/compiler/parser.py +1772 -2422
  6. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +2 -2
  7. jaclang/compiler/passes/main/import_pass.py +2 -1
  8. jaclang/compiler/passes/main/inheritance_pass.py +20 -1
  9. jaclang/compiler/passes/main/pyast_gen_pass.py +565 -723
  10. jaclang/compiler/passes/main/tests/test_type_check_pass.py +6 -3
  11. jaclang/compiler/tests/test_parser.py +13 -5
  12. jaclang/plugin/builtin.py +11 -0
  13. jaclang/plugin/default.py +64 -10
  14. jaclang/plugin/feature.py +14 -0
  15. jaclang/plugin/spec.py +16 -0
  16. jaclang/plugin/tests/fixtures/graph_purger.jac +2 -0
  17. jaclang/plugin/tests/fixtures/other_root_access.jac +1 -0
  18. jaclang/plugin/tests/fixtures/savable_object.jac +2 -0
  19. jaclang/plugin/tests/fixtures/traversing_save.jac +17 -0
  20. jaclang/plugin/tests/test_jaseci.py +34 -1
  21. jaclang/runtimelib/architype.py +9 -19
  22. jaclang/runtimelib/context.py +25 -9
  23. jaclang/settings.py +2 -0
  24. jaclang/tests/fixtures/base_class_complex_expr.jac +38 -0
  25. jaclang/tests/fixtures/create_dynamic_architype.jac +1 -1
  26. jaclang/tests/fixtures/nested_impls.jac +55 -0
  27. jaclang/tests/test_cli.py +21 -0
  28. jaclang/tests/test_language.py +27 -13
  29. jaclang/tests/test_reference.py +2 -2
  30. jaclang/utils/helpers.py +4 -3
  31. jaclang/utils/profiler.py +62 -0
  32. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/METADATA +1 -1
  33. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/RECORD +35 -31
  34. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/WHEEL +1 -1
  35. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/entry_points.txt +0 -0
@@ -7,11 +7,12 @@ in each node. Module nodes contain the entire module code.
7
7
  import ast as ast3
8
8
  import textwrap
9
9
  from dataclasses import dataclass
10
- from typing import Optional, Sequence, TypeVar
10
+ from typing import Optional, Sequence, TypeVar, cast
11
11
 
12
12
  import jaclang.compiler.absyntree as ast
13
13
  from jaclang.compiler.constant import Constants as Con, EdgeDir, Tokens as Tok
14
14
  from jaclang.compiler.passes import Pass
15
+ from jaclang.settings import settings
15
16
 
16
17
  T = TypeVar("T", bound=ast3.AST)
17
18
 
@@ -52,8 +53,47 @@ class PyastGenPass(Pass):
52
53
  ),
53
54
  jac_node=self.ir,
54
55
  ),
56
+ (
57
+ self.sync(
58
+ ast3.ImportFrom(
59
+ module="jaclang",
60
+ names=[self.sync(ast3.alias(name="*", asname=None))],
61
+ level=0,
62
+ ),
63
+ jac_node=self.ir,
64
+ )
65
+ if settings.pyout_jaclib_import_all
66
+ else self.sync(
67
+ ast3.Import(
68
+ names=[
69
+ self.sync(
70
+ ast3.alias(
71
+ name="jaclang", asname=settings.pyout_jaclib_alias
72
+ )
73
+ )
74
+ ]
75
+ ),
76
+ jac_node=self.ir,
77
+ )
78
+ ),
55
79
  ]
56
80
 
81
+ from jaclang.plugin.builtin import __all__ as jac_builtin_funcs
82
+
83
+ if not settings.pyout_jaclib_import_all:
84
+ self.preamble += [
85
+ self.sync(
86
+ ast3.ImportFrom(
87
+ module="jaclang",
88
+ names=[
89
+ self.sync(ast3.alias(name=func_name))
90
+ for func_name in jac_builtin_funcs
91
+ ],
92
+ level=0,
93
+ )
94
+ )
95
+ ]
96
+
57
97
  def enter_node(self, node: ast.AstNode) -> None:
58
98
  """Enter node."""
59
99
  if node.gen.py_ast:
@@ -71,25 +111,19 @@ class PyastGenPass(Pass):
71
111
  # if isinstance(i, ast3.AST):
72
112
  # i.jac_link = node
73
113
 
74
- def needs_jac_import(self) -> None:
75
- """Check if import is needed."""
76
- if self.needs_jac_import.__name__ in self.already_added:
77
- return
78
- self.preamble.append(
79
- self.sync(
80
- ast3.ImportFrom(
81
- module="jaclang",
82
- names=[
83
- self.sync(
84
- ast3.alias(name="jac_import", asname="__jac_import__")
85
- )
86
- ],
87
- level=0,
114
+ def jaclib_obj(self, obj_name: str) -> ast3.Name | ast3.Attribute:
115
+ """Return the object from jaclib as ast node based on the import config."""
116
+ if settings.pyout_jaclib_import_all:
117
+ return self.sync(ast3.Name(id=obj_name, ctx=ast3.Load()))
118
+ return self.sync(
119
+ ast3.Attribute(
120
+ value=self.sync(
121
+ ast3.Name(id=settings.pyout_jaclib_alias, ctx=ast3.Load())
88
122
  ),
89
- jac_node=self.ir,
123
+ attr=obj_name,
124
+ ctx=ast3.Load(),
90
125
  )
91
126
  )
92
- self.already_added.append(self.needs_jac_import.__name__)
93
127
 
94
128
  def needs_typing(self) -> None:
95
129
  """Check if enum is needed."""
@@ -100,7 +134,7 @@ class PyastGenPass(Pass):
100
134
  ast3.Import(
101
135
  names=[
102
136
  self.sync(
103
- ast3.alias(name="typing", asname="_jac_typ"),
137
+ ast3.alias(name="typing"),
104
138
  jac_node=self.ir,
105
139
  ),
106
140
  ]
@@ -110,25 +144,6 @@ class PyastGenPass(Pass):
110
144
  )
111
145
  self.already_added.append(self.needs_typing.__name__)
112
146
 
113
- def needs_abc(self) -> None:
114
- """Check if enum is needed."""
115
- if self.needs_abc.__name__ in self.already_added:
116
- return
117
- self.preamble.append(
118
- self.sync(
119
- ast3.Import(
120
- names=[
121
- self.sync(
122
- ast3.alias(name="abc", asname="_jac_abc"),
123
- jac_node=self.ir,
124
- ),
125
- ]
126
- ),
127
- jac_node=self.ir,
128
- )
129
- )
130
- self.already_added.append(self.needs_abc.__name__)
131
-
132
147
  def needs_enum(self) -> None:
133
148
  """Check if enum is needed."""
134
149
  if self.needs_enum.__name__ in self.already_added:
@@ -138,8 +153,8 @@ class PyastGenPass(Pass):
138
153
  ast3.ImportFrom(
139
154
  module="enum",
140
155
  names=[
141
- self.sync(ast3.alias(name="Enum", asname="__jac_Enum__")),
142
- self.sync(ast3.alias(name="auto", asname="__jac_auto__")),
156
+ self.sync(ast3.alias(name="Enum", asname=None)),
157
+ self.sync(ast3.alias(name="auto", asname=None)),
143
158
  ],
144
159
  level=0,
145
160
  ),
@@ -148,74 +163,6 @@ class PyastGenPass(Pass):
148
163
  )
149
164
  self.already_added.append(self.needs_enum.__name__)
150
165
 
151
- def needs_jac_feature(self) -> None:
152
- """Check if enum is needed."""
153
- if self.needs_jac_feature.__name__ in self.already_added:
154
- return
155
- self.preamble.append(
156
- self.sync(
157
- ast3.ImportFrom(
158
- module="jaclang.plugin.feature",
159
- names=[
160
- self.sync(
161
- ast3.alias(name="JacFeature", asname=Con.JAC_FEATURE.value)
162
- ),
163
- ],
164
- level=0,
165
- ),
166
- jac_node=self.ir,
167
- )
168
- )
169
- self.preamble.append(
170
- self.sync(
171
- ast3.ImportFrom(
172
- module="jaclang.plugin.builtin",
173
- names=[self.sync(ast3.alias(name="*", asname=None))],
174
- level=0,
175
- ),
176
- jac_node=self.ir,
177
- )
178
- )
179
- self.already_added.append(self.needs_jac_feature.__name__)
180
-
181
- def needs_dataclass(self) -> None:
182
- """Check if enum is needed."""
183
- if self.needs_dataclass.__name__ in self.already_added:
184
- return
185
- self.preamble.append(
186
- self.sync(
187
- ast3.ImportFrom(
188
- module="dataclasses",
189
- names=[
190
- self.sync(
191
- ast3.alias(name="dataclass", asname="__jac_dataclass__")
192
- ),
193
- ],
194
- level=0,
195
- ),
196
- jac_node=self.ir,
197
- )
198
- )
199
- self.already_added.append(self.needs_dataclass.__name__)
200
-
201
- def needs_dataclass_field(self) -> None:
202
- """Check if enum is needed."""
203
- if self.needs_dataclass_field.__name__ in self.already_added:
204
- return
205
- self.preamble.append(
206
- self.sync(
207
- ast3.ImportFrom(
208
- module="dataclasses",
209
- names=[
210
- self.sync(ast3.alias(name="field", asname="__jac_field__")),
211
- ],
212
- level=0,
213
- ),
214
- jac_node=self.ir,
215
- )
216
- )
217
- self.already_added.append(self.needs_dataclass_field.__name__)
218
-
219
166
  def flatten(self, body: list[T | list[T] | None]) -> list[T]:
220
167
  """Flatten ast list."""
221
168
  new_body = []
@@ -404,7 +351,6 @@ class PyastGenPass(Pass):
404
351
  body: SubNodeList[CodeBlockStmt],
405
352
  doc: Optional[String],
406
353
  """
407
- self.needs_jac_feature()
408
354
  test_name = node.name.sym_name
409
355
  func = self.sync(
410
356
  ast3.FunctionDef(
@@ -412,7 +358,11 @@ class PyastGenPass(Pass):
412
358
  args=self.sync(
413
359
  ast3.arguments(
414
360
  posonlyargs=[],
415
- args=[self.sync(ast3.arg(arg="_jac_check", annotation=None))],
361
+ args=[
362
+ self.sync(
363
+ ast3.arg(arg=Con.JAC_CHECK.value, annotation=None)
364
+ )
365
+ ],
416
366
  kwonlyargs=[],
417
367
  vararg=None,
418
368
  kwargs=None,
@@ -421,17 +371,7 @@ class PyastGenPass(Pass):
421
371
  )
422
372
  ),
423
373
  body=self.resolve_stmt_block(node.body, doc=node.doc),
424
- decorator_list=[
425
- self.sync(
426
- ast3.Attribute(
427
- value=self.sync(
428
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
429
- ),
430
- attr="create_test",
431
- ctx=ast3.Load(),
432
- )
433
- )
434
- ],
374
+ decorator_list=[self.jaclib_obj("jac_test")],
435
375
  returns=self.sync(ast3.Constant(value=None)),
436
376
  type_comment=None,
437
377
  type_params=[],
@@ -443,9 +383,7 @@ class PyastGenPass(Pass):
443
383
  ast3.Call(
444
384
  func=self.sync(
445
385
  ast3.Attribute(
446
- value=self.sync(
447
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
448
- ),
386
+ value=self.jaclib_obj("Jac"),
449
387
  attr="impl_patch_filename",
450
388
  ctx=ast3.Load(),
451
389
  )
@@ -548,7 +486,6 @@ class PyastGenPass(Pass):
548
486
  for k, v in imp_from.items():
549
487
  item_keys.append(self.sync(ast3.Constant(value=k)))
550
488
  item_values.append(self.sync(ast3.Constant(value=v)))
551
- self.needs_jac_import()
552
489
  path_named_value: str
553
490
  py_nodes: list[ast3.AST] = []
554
491
  typecheck_nodes: list[ast3.AST] = []
@@ -607,68 +544,65 @@ class PyastGenPass(Pass):
607
544
  ),
608
545
  value=self.sync(
609
546
  ast3.Call(
610
- func=self.sync(
611
- ast3.Name(id="__jac_import__", ctx=ast3.Load())
612
- ),
613
- args=[],
614
- keywords=[
615
- self.sync(
616
- ast3.keyword(
617
- arg="target",
618
- value=self.sync(
619
- ast3.Constant(value=path),
620
- ),
621
- )
622
- ),
623
- self.sync(
624
- ast3.keyword(
625
- arg="base_path",
626
- value=self.sync(
627
- ast3.Name(
628
- id="__file__",
629
- ctx=ast3.Load(),
630
- )
631
- ),
547
+ func=self.jaclib_obj("jac_import"),
548
+ args=[
549
+ self.sync(ast3.Constant(value=path)),
550
+ ]
551
+ + (
552
+ [
553
+ self.sync(
554
+ ast3.Constant(value="py"),
555
+ node.hint,
632
556
  )
633
- ),
634
- self.sync(
635
- ast3.keyword(
636
- arg="lng",
637
- value=self.sync(
638
- ast3.Constant(
639
- value="py" if node.is_py else "jac"
557
+ ]
558
+ if node.is_py
559
+ else []
560
+ ),
561
+ keywords=(
562
+ [
563
+ self.sync(
564
+ ast3.keyword(
565
+ arg="absorb",
566
+ value=self.sync(
567
+ ast3.Constant(value=node.is_absorb),
640
568
  ),
641
- node.hint,
642
- ),
643
- )
644
- ),
645
- self.sync(
646
- ast3.keyword(
647
- arg="absorb",
648
- value=self.sync(
649
- ast3.Constant(value=node.is_absorb),
650
- ),
651
- )
652
- ),
653
- self.sync(
654
- ast3.keyword(
655
- arg="mdl_alias",
656
- value=self.sync(
657
- ast3.Constant(value=alias),
658
- ),
659
- )
660
- ),
661
- self.sync(
662
- ast3.keyword(
663
- arg="items",
664
- value=self.sync(
665
- ast3.Dict(
666
- keys=item_keys, values=item_values
569
+ )
570
+ ),
571
+ ]
572
+ if node.is_absorb
573
+ else []
574
+ )
575
+ + (
576
+ [
577
+ self.sync(
578
+ ast3.keyword(
579
+ arg="alias",
580
+ value=self.sync(
581
+ ast3.Constant(value=alias),
667
582
  ),
668
- ),
669
- )
670
- ),
671
- ],
583
+ )
584
+ ),
585
+ ]
586
+ if alias
587
+ else []
588
+ )
589
+ + (
590
+ [
591
+ self.sync(
592
+ ast3.keyword(
593
+ arg="items",
594
+ value=self.sync(
595
+ ast3.Dict(
596
+ keys=item_keys,
597
+ values=item_values,
598
+ ),
599
+ ),
600
+ )
601
+ ),
602
+ ]
603
+ if len(item_keys)
604
+ else []
605
+ ),
672
606
  )
673
607
  ),
674
608
  ),
@@ -857,7 +791,7 @@ class PyastGenPass(Pass):
857
791
  ast3.If(
858
792
  test=self.sync(
859
793
  ast3.Attribute(
860
- value=self.sync(ast3.Name(id="_jac_typ", ctx=ast3.Load())),
794
+ value=self.sync(ast3.Name(id="typing", ctx=ast3.Load())),
861
795
  attr="TYPE_CHECKING",
862
796
  ctx=ast3.Load(),
863
797
  )
@@ -935,88 +869,9 @@ class PyastGenPass(Pass):
935
869
  else []
936
870
  )
937
871
 
938
- ds_on_entry, ds_on_exit = self.collect_events(node)
939
- if node.arch_type.name != Tok.KW_CLASS:
940
- self.needs_jac_feature()
941
- self.needs_dataclass()
942
- decorators.append(
943
- self.sync(
944
- ast3.Call(
945
- func=self.sync(
946
- ast3.Attribute(
947
- value=self.sync(
948
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
949
- ),
950
- attr=f"make_{node.arch_type.value}",
951
- ctx=ast3.Load(),
952
- )
953
- ),
954
- args=[],
955
- keywords=[
956
- self.sync(
957
- ast3.keyword(
958
- arg="on_entry",
959
- value=self.sync(
960
- ast3.List(elts=ds_on_entry, ctx=ast3.Load())
961
- ),
962
- )
963
- ),
964
- self.sync(
965
- ast3.keyword(
966
- arg="on_exit",
967
- value=self.sync(
968
- ast3.List(elts=ds_on_exit, ctx=ast3.Load())
969
- ),
970
- )
971
- ),
972
- ],
973
- )
974
- )
975
- )
976
- decorators.append(
977
- self.sync(
978
- ast3.Call(
979
- func=self.sync(
980
- ast3.Name(id="__jac_dataclass__", ctx=ast3.Load())
981
- ),
982
- args=[],
983
- keywords=[
984
- self.sync(
985
- ast3.keyword(
986
- arg="eq",
987
- value=self.sync(
988
- ast3.Constant(value=False),
989
- ),
990
- )
991
- )
992
- ],
993
- )
994
- )
995
- )
996
872
  base_classes = node.base_classes.gen.py_ast if node.base_classes else []
997
873
  if node.arch_type.name != Tok.KW_CLASS:
998
- base_classes.append(
999
- self.sync(
1000
- ast3.Attribute(
1001
- value=self.sync(
1002
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
1003
- ),
1004
- attr=node.arch_type.value.capitalize(),
1005
- ctx=ast3.Load(),
1006
- )
1007
- )
1008
- )
1009
- if node.is_abstract:
1010
- self.needs_abc()
1011
- base_classes.append(
1012
- self.sync(
1013
- ast3.Attribute(
1014
- value=self.sync(ast3.Name(id="_jac_abc", ctx=ast3.Load())),
1015
- attr="ABC",
1016
- ctx=ast3.Load(),
1017
- )
1018
- )
1019
- )
874
+ base_classes.append(self.jaclib_obj(node.arch_type.value.capitalize()))
1020
875
  node.gen.py_ast = [
1021
876
  self.sync(
1022
877
  ast3.ClassDef(
@@ -1030,42 +885,6 @@ class PyastGenPass(Pass):
1030
885
  )
1031
886
  ]
1032
887
 
1033
- def collect_events(
1034
- self, node: ast.Architype
1035
- ) -> tuple[list[ast3.AST], list[ast3.AST]]:
1036
- """Collect events."""
1037
- ds_on_entry: list[ast3.AST] = []
1038
- ds_on_exit: list[ast3.AST] = []
1039
- for i in (
1040
- node.body.body.items
1041
- if isinstance(node.body, ast.ArchDef)
1042
- else node.body.items if node.body else []
1043
- ):
1044
- if isinstance(i, ast.Ability) and isinstance(
1045
- i.signature, ast.EventSignature
1046
- ):
1047
- func_spec = self.sync(
1048
- ast3.Call(
1049
- func=self.sync(
1050
- ast3.Attribute(
1051
- value=self.sync(
1052
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
1053
- ),
1054
- attr="DSFunc",
1055
- ctx=ast3.Load(),
1056
- )
1057
- ),
1058
- args=[self.sync(ast3.Constant(value=i.sym_name))],
1059
- keywords=[],
1060
- )
1061
- )
1062
- (
1063
- ds_on_entry.append(func_spec)
1064
- if i.signature.event.name == Tok.KW_ENTRY
1065
- else ds_on_exit.append(func_spec)
1066
- )
1067
- return ds_on_entry, ds_on_exit
1068
-
1069
888
  def exit_arch_def(self, node: ast.ArchDef) -> None:
1070
889
  """Sub objects.
1071
890
 
@@ -1110,9 +929,7 @@ class PyastGenPass(Pass):
1110
929
  )
1111
930
  base_classes = node.base_classes.gen.py_ast if node.base_classes else []
1112
931
  if isinstance(base_classes, list):
1113
- base_classes.append(
1114
- self.sync(ast3.Name(id="__jac_Enum__", ctx=ast3.Load()))
1115
- )
932
+ base_classes.append(self.sync(ast3.Name(id="Enum", ctx=ast3.Load())))
1116
933
  else:
1117
934
  raise self.ice()
1118
935
  node.gen.py_ast = [
@@ -1207,56 +1024,35 @@ class PyastGenPass(Pass):
1207
1024
  node,
1208
1025
  )
1209
1026
  decorator_list = node.decorators.gen.py_ast if node.decorators else []
1027
+ if isinstance(node.signature, ast.EventSignature):
1028
+ decorator_list.append(
1029
+ self.jaclib_obj(
1030
+ "with_entry"
1031
+ if node.signature.event.name == Tok.KW_ENTRY
1032
+ else "with_exit"
1033
+ )
1034
+ )
1035
+
1210
1036
  if isinstance(node.body, ast.AstImplOnlyNode):
1211
- self.needs_jac_feature()
1212
1037
  decorator_list.append(
1213
1038
  self.sync(
1214
1039
  ast3.Call(
1215
1040
  func=self.sync(
1216
1041
  ast3.Attribute(
1217
- value=self.sync(
1218
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
1219
- ),
1042
+ self.jaclib_obj("Jac"),
1220
1043
  attr="impl_patch_filename",
1221
1044
  ctx=ast3.Load(),
1222
- )
1223
- ),
1224
- args=[],
1225
- keywords=[
1226
- self.sync(
1227
- ast3.keyword(
1228
- arg="file_loc",
1229
- value=self.sync(
1230
- ast3.Constant(value=node.body.loc.mod_path)
1231
- ),
1232
- )
1233
1045
  ),
1234
- ],
1046
+ ),
1047
+ args=[self.sync(ast3.Constant(value=node.body.loc.mod_path))],
1048
+ keywords=[],
1235
1049
  )
1236
1050
  )
1237
1051
  )
1238
1052
  if node.is_abstract:
1239
- self.needs_abc()
1240
- decorator_list.append(
1241
- self.sync(
1242
- ast3.Attribute(
1243
- value=self.sync(ast3.Name(id="_jac_abc", ctx=ast3.Load())),
1244
- attr="abstractmethod",
1245
- ctx=ast3.Load(),
1246
- )
1247
- )
1248
- )
1053
+ decorator_list.append(self.jaclib_obj("abstract"))
1249
1054
  if node.is_override:
1250
- self.needs_typing()
1251
- decorator_list.append(
1252
- self.sync(
1253
- ast3.Attribute(
1254
- value=self.sync(ast3.Name(id="_jac_typ", ctx=ast3.Load())),
1255
- attr="override",
1256
- ctx=ast3.Load(),
1257
- )
1258
- )
1259
- )
1055
+ decorator_list.append(self.jaclib_obj("override"))
1260
1056
  if node.is_static:
1261
1057
  decorator_list.insert(
1262
1058
  0, self.sync(ast3.Name(id="staticmethod", ctx=ast3.Load()))
@@ -1381,23 +1177,13 @@ class PyastGenPass(Pass):
1381
1177
  isinstance(node.arch_name, ast.SpecialVarRef)
1382
1178
  and node.arch_name.orig.name == Tok.KW_ROOT
1383
1179
  ):
1384
- node.gen.py_ast = [
1385
- self.sync(
1386
- ast3.Attribute(
1387
- value=self.sync(
1388
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
1389
- ),
1390
- attr="RootType",
1391
- ctx=ast3.Load(),
1392
- )
1393
- )
1394
- ]
1180
+ node.gen.py_ast = [self.jaclib_obj("Root")]
1395
1181
  else:
1396
1182
  self.needs_typing()
1397
1183
  node.gen.py_ast = [
1398
1184
  self.sync(
1399
1185
  ast3.Attribute(
1400
- value=self.sync(ast3.Name(id="_jac_typ", ctx=ast3.Load())),
1186
+ value=self.sync(ast3.Name(id="typing", ctx=ast3.Load())),
1401
1187
  attr=node.arch_name.sym_name,
1402
1188
  ctx=ast3.Load(),
1403
1189
  )
@@ -1498,25 +1284,15 @@ class PyastGenPass(Pass):
1498
1284
  )
1499
1285
  )
1500
1286
  if is_static_var:
1501
- self.needs_typing()
1502
1287
  annotation = self.sync(
1503
1288
  ast3.Subscript(
1504
- value=self.sync(
1505
- ast3.Attribute(
1506
- value=self.sync(ast3.Name(id="_jac_typ", ctx=ast3.Load())),
1507
- attr="ClassVar",
1508
- ctx=ast3.Load(),
1509
- )
1510
- ),
1289
+ value=self.jaclib_obj("static"),
1511
1290
  slice=annotation,
1512
1291
  ctx=ast3.Load(),
1513
1292
  )
1514
1293
  )
1515
- (
1516
- self.needs_dataclass_field()
1517
- if node.defer and not (is_static_var or is_in_class)
1518
- else None
1519
- )
1294
+
1295
+ default_field_fn_name = "field"
1520
1296
  node.gen.py_ast = [
1521
1297
  (
1522
1298
  self.sync(
@@ -1526,42 +1302,45 @@ class PyastGenPass(Pass):
1526
1302
  value=(
1527
1303
  self.sync(
1528
1304
  ast3.Call(
1529
- func=self.sync(
1530
- ast3.Attribute(
1531
- value=self.sync(
1532
- ast3.Name(
1533
- id=Con.JAC_FEATURE.value,
1534
- ctx=ast3.Load(),
1535
- )
1536
- ),
1537
- attr="has_instance_default",
1538
- ctx=ast3.Load(),
1305
+ func=self.jaclib_obj(default_field_fn_name),
1306
+ args=(
1307
+ [node.value.gen.py_ast[0]]
1308
+ if isinstance(
1309
+ node.value.gen.py_ast[0], ast3.Constant
1539
1310
  )
1311
+ else []
1540
1312
  ),
1541
- args=[],
1542
- keywords=[
1543
- self.sync(
1544
- ast3.keyword(
1545
- arg="gen_func",
1546
- value=self.sync(
1547
- ast3.Lambda(
1548
- args=self.sync(
1549
- ast3.arguments(
1550
- posonlyargs=[],
1551
- args=[],
1552
- kwonlyargs=[],
1553
- vararg=None,
1554
- kwargs=None,
1555
- kw_defaults=[],
1556
- defaults=[],
1557
- )
1558
- ),
1559
- body=node.value.gen.py_ast[0],
1560
- )
1561
- ),
1313
+ keywords=(
1314
+ [
1315
+ self.sync(
1316
+ ast3.keyword(
1317
+ arg="gen",
1318
+ value=self.sync(
1319
+ ast3.Lambda(
1320
+ args=self.sync(
1321
+ ast3.arguments(
1322
+ posonlyargs=[],
1323
+ args=[],
1324
+ kwonlyargs=[],
1325
+ vararg=None,
1326
+ kwargs=None,
1327
+ kw_defaults=[],
1328
+ defaults=[],
1329
+ )
1330
+ ),
1331
+ body=node.value.gen.py_ast[
1332
+ 0
1333
+ ],
1334
+ )
1335
+ ),
1336
+ )
1562
1337
  )
1338
+ ]
1339
+ if not isinstance(
1340
+ node.value.gen.py_ast[0], ast3.Constant
1563
1341
  )
1564
- ],
1342
+ else []
1343
+ ),
1565
1344
  )
1566
1345
  )
1567
1346
  if node.value
@@ -1569,19 +1348,14 @@ class PyastGenPass(Pass):
1569
1348
  else (
1570
1349
  self.sync(
1571
1350
  ast3.Call(
1572
- func=self.sync(
1573
- ast3.Name(
1574
- id="__jac_field__",
1575
- ctx=ast3.Load(),
1576
- )
1577
- ),
1351
+ func=self.jaclib_obj(default_field_fn_name),
1578
1352
  args=[],
1579
1353
  keywords=[
1580
1354
  self.sync(
1581
1355
  ast3.keyword(
1582
- arg="init",
1356
+ arg="postinit",
1583
1357
  value=self.sync(
1584
- ast3.Constant(value=False)
1358
+ ast3.Constant(value=True)
1585
1359
  ),
1586
1360
  )
1587
1361
  )
@@ -1983,16 +1757,16 @@ class PyastGenPass(Pass):
1983
1757
  for param in node.target.params.items:
1984
1758
  assert_args_list.append(param.gen.py_ast[0])
1985
1759
 
1986
- # assert_func_expr = "_jac_check.assertXXX"
1760
+ # assert_func_expr = "Con.JAC_CHECK.value.assertXXX"
1987
1761
  assert_func_expr: ast3.Attribute = self.sync(
1988
1762
  ast3.Attribute(
1989
- value=self.sync(ast3.Name(id="_jac_check", ctx=ast3.Load())),
1763
+ value=self.sync(ast3.Name(id=Con.JAC_CHECK.value, ctx=ast3.Load())),
1990
1764
  attr=assert_func_name,
1991
1765
  ctx=ast3.Load(),
1992
1766
  )
1993
1767
  )
1994
1768
 
1995
- # assert_call_expr = "(_jac_check.assertXXX)(args)"
1769
+ # assert_call_expr = "(Con.JAC_CHECK.value.assertXXX)(args)"
1996
1770
  assert_call_expr: ast3.Call = self.sync(
1997
1771
  ast3.Call(func=assert_func_expr, args=assert_args_list, keywords=[])
1998
1772
  )
@@ -2041,12 +1815,7 @@ class PyastGenPass(Pass):
2041
1815
  ast3.Call(
2042
1816
  func=self.sync(
2043
1817
  ast3.Attribute(
2044
- value=self.sync(
2045
- ast3.Name(
2046
- id=Con.JAC_FEATURE.value,
2047
- ctx=ast3.Load(),
2048
- )
2049
- ),
1818
+ value=self.jaclib_obj(Con.JAC_FEATURE.value),
2050
1819
  attr="report",
2051
1820
  ctx=ast3.Load(),
2052
1821
  )
@@ -2092,11 +1861,12 @@ class PyastGenPass(Pass):
2092
1861
 
2093
1862
  target: ExprType,
2094
1863
  """
2095
- loc = self.sync(
1864
+ walker = self.sync(
2096
1865
  ast3.Name(id="self", ctx=ast3.Load())
2097
1866
  if node.from_walker
2098
1867
  else ast3.Name(id=Con.HERE.value, ctx=ast3.Load())
2099
1868
  )
1869
+
2100
1870
  node.gen.py_ast = [
2101
1871
  self.sync(
2102
1872
  ast3.Expr(
@@ -2104,16 +1874,12 @@ class PyastGenPass(Pass):
2104
1874
  ast3.Call(
2105
1875
  func=self.sync(
2106
1876
  ast3.Attribute(
2107
- value=self.sync(
2108
- ast3.Name(
2109
- id=Con.JAC_FEATURE.value, ctx=ast3.Load()
2110
- )
2111
- ),
1877
+ value=walker,
2112
1878
  attr="ignore",
2113
1879
  ctx=ast3.Load(),
2114
1880
  )
2115
1881
  ),
2116
- args=[loc, node.target.gen.py_ast[0]],
1882
+ args=[node.target.gen.py_ast[0]],
2117
1883
  keywords=[],
2118
1884
  )
2119
1885
  )
@@ -2133,29 +1899,37 @@ class PyastGenPass(Pass):
2133
1899
  if node.from_walker
2134
1900
  else ast3.Name(id=Con.HERE.value, ctx=ast3.Load())
2135
1901
  )
1902
+
1903
+ visit_call = self.sync(
1904
+ ast3.Call(
1905
+ func=self.sync(
1906
+ ast3.Attribute(
1907
+ value=loc,
1908
+ attr="visit",
1909
+ ctx=ast3.Load(),
1910
+ )
1911
+ ),
1912
+ args=[node.target.gen.py_ast[0]],
1913
+ keywords=[],
1914
+ )
1915
+ )
1916
+
2136
1917
  node.gen.py_ast = [
2137
- self.sync(
2138
- ast3.If(
2139
- test=self.sync(
2140
- ast3.Call(
2141
- func=self.sync(
2142
- ast3.Attribute(
2143
- value=self.sync(
2144
- ast3.Name(
2145
- id=Con.JAC_FEATURE.value, ctx=ast3.Load()
2146
- )
2147
- ),
2148
- attr="visit_node",
2149
- ctx=ast3.Load(),
2150
- )
2151
- ),
2152
- args=[loc, node.target.gen.py_ast[0]],
2153
- keywords=[],
2154
- )
2155
- ),
2156
- body=[self.sync(ast3.Pass())],
2157
- orelse=node.else_body.gen.py_ast if node.else_body else [],
1918
+ (
1919
+ self.sync(
1920
+ ast3.If(
1921
+ test=self.sync(
1922
+ ast3.UnaryOp(
1923
+ op=self.sync(ast3.Not()),
1924
+ operand=visit_call,
1925
+ )
1926
+ ),
1927
+ body=node.else_body.gen.py_ast,
1928
+ orelse=[],
1929
+ )
2158
1930
  )
1931
+ if node.else_body
1932
+ else self.sync(ast3.Expr(value=visit_call))
2159
1933
  )
2160
1934
  ]
2161
1935
 
@@ -2179,30 +1953,24 @@ class PyastGenPass(Pass):
2179
1953
  )
2180
1954
  node.gen.py_ast = [
2181
1955
  self.sync(
2182
- ast3.Expr(
2183
- value=self.sync(
1956
+ ast3.Return(
1957
+ self.sync(
2184
1958
  self.sync(
2185
1959
  ast3.Call(
2186
1960
  func=self.sync(
2187
1961
  ast3.Attribute(
2188
- value=self.sync(
2189
- ast3.Name(
2190
- id=Con.JAC_FEATURE.value,
2191
- ctx=ast3.Load(),
2192
- )
2193
- ),
1962
+ value=loc,
2194
1963
  attr="disengage",
2195
1964
  ctx=ast3.Load(),
2196
1965
  )
2197
1966
  ),
2198
- args=[loc],
1967
+ args=[],
2199
1968
  keywords=[],
2200
1969
  )
2201
1970
  )
2202
1971
  )
2203
1972
  )
2204
1973
  ),
2205
- self.sync(ast3.Return()),
2206
1974
  ]
2207
1975
 
2208
1976
  def exit_await_expr(self, node: ast.AwaitExpr) -> None:
@@ -2256,7 +2024,7 @@ class PyastGenPass(Pass):
2256
2024
  else (
2257
2025
  self.sync(
2258
2026
  ast3.Call(
2259
- func=self.sync(ast3.Name(id="__jac_auto__", ctx=ast3.Load())),
2027
+ func=self.sync(ast3.Name(id="auto", ctx=ast3.Load())),
2260
2028
  args=[],
2261
2029
  keywords=[],
2262
2030
  )
@@ -2299,91 +2067,120 @@ class PyastGenPass(Pass):
2299
2067
  op: Token | DisconnectOp | ConnectOp,
2300
2068
  """
2301
2069
  if isinstance(node.op, ast.ConnectOp):
2070
+
2071
+ left = (
2072
+ node.right.gen.py_ast[0]
2073
+ if node.op.edge_dir == EdgeDir.IN
2074
+ else node.left.gen.py_ast[0]
2075
+ )
2076
+ right = (
2077
+ node.left.gen.py_ast[0]
2078
+ if node.op.edge_dir == EdgeDir.IN
2079
+ else node.right.gen.py_ast[0]
2080
+ )
2081
+ conn_type = (
2082
+ node.op.conn_type.gen.py_ast[0]
2083
+ if node.op.conn_type
2084
+ else self.sync(ast3.Constant(value=None))
2085
+ )
2086
+ undir = self.sync(ast3.Constant(value=node.op.edge_dir == EdgeDir.ANY))
2087
+ conn_assign = (
2088
+ node.op.conn_assign.gen.py_ast[0]
2089
+ if node.op.conn_assign
2090
+ else self.sync(ast3.Constant(value=None))
2091
+ )
2092
+
2093
+ keywords = []
2094
+ if not isinstance(conn_type, ast3.Constant) or conn_type.value is not None:
2095
+ keywords.append(
2096
+ self.sync(
2097
+ ast3.keyword(
2098
+ arg="edge",
2099
+ value=conn_type,
2100
+ )
2101
+ )
2102
+ )
2103
+ if undir.value: # default is Fault.
2104
+ keywords.append(
2105
+ self.sync(
2106
+ ast3.keyword(
2107
+ arg="undir",
2108
+ value=undir,
2109
+ )
2110
+ )
2111
+ )
2112
+ if (
2113
+ not isinstance(conn_assign, ast3.Constant)
2114
+ or conn_assign.value is not None
2115
+ ):
2116
+ keywords.append(
2117
+ self.sync(
2118
+ ast3.keyword(
2119
+ arg="conn_assign",
2120
+ value=conn_assign,
2121
+ )
2122
+ )
2123
+ )
2124
+
2302
2125
  node.gen.py_ast = [
2303
2126
  self.sync(
2304
2127
  ast3.Call(
2305
2128
  func=self.sync(
2306
2129
  ast3.Attribute(
2307
- value=self.sync(
2308
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2309
- ),
2130
+ value=left,
2310
2131
  attr="connect",
2311
2132
  ctx=ast3.Load(),
2312
- )
2313
- ),
2314
- args=[],
2315
- keywords=[
2316
- self.sync(
2317
- ast3.keyword(
2318
- arg="left",
2319
- value=(
2320
- node.right.gen.py_ast[0]
2321
- if node.op.edge_dir == EdgeDir.IN
2322
- else node.left.gen.py_ast[0]
2323
- ),
2324
- )
2325
2133
  ),
2326
- self.sync(
2327
- ast3.keyword(
2328
- arg="right",
2329
- value=(
2330
- node.left.gen.py_ast[0]
2331
- if node.op.edge_dir == EdgeDir.IN
2332
- else node.right.gen.py_ast[0]
2333
- ),
2334
- )
2134
+ ),
2135
+ args=[right],
2136
+ keywords=keywords,
2137
+ )
2138
+ )
2139
+ ]
2140
+
2141
+ elif isinstance(node.op, ast.DisconnectOp):
2142
+ keywords = []
2143
+
2144
+ if node.op.edge_spec.filter_cond and node.op.edge_spec.filter_cond.f_type:
2145
+ keywords.append(
2146
+ self.sync(
2147
+ ast3.keyword(
2148
+ arg="edge",
2149
+ value=self.sync(
2150
+ node.op.edge_spec.filter_cond.f_type.gen.py_ast[0]
2335
2151
  ),
2336
- self.sync(
2337
- ast3.keyword(
2338
- arg="edge_spec",
2339
- value=node.op.gen.py_ast[0],
2152
+ )
2153
+ )
2154
+ )
2155
+
2156
+ if node.op.edge_spec.edge_dir != EdgeDir.OUT:
2157
+ keywords.append(
2158
+ self.sync(
2159
+ ast3.keyword(
2160
+ arg="dir",
2161
+ value=self.sync(
2162
+ ast3.Attribute(
2163
+ value=self.jaclib_obj("EdgeDir"),
2164
+ attr=node.op.edge_spec.edge_dir.name,
2165
+ ctx=ast3.Load(),
2340
2166
  )
2341
2167
  ),
2342
- ],
2168
+ )
2343
2169
  )
2344
2170
  )
2345
- ]
2346
- elif isinstance(node.op, ast.DisconnectOp):
2171
+
2347
2172
  node.gen.py_ast = [
2348
2173
  self.sync(
2349
2174
  ast3.Call(
2350
2175
  func=self.sync(
2351
2176
  ast3.Attribute(
2352
- value=self.sync(
2353
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2354
- ),
2177
+ value=node.left.gen.py_ast[0],
2355
2178
  attr="disconnect",
2356
2179
  ctx=ast3.Load(),
2357
2180
  )
2358
2181
  ),
2359
- args=[
2360
- node.left.gen.py_ast[0],
2361
- node.right.gen.py_ast[0],
2362
- self.sync(
2363
- ast3.Attribute(
2364
- value=self.sync(
2365
- ast3.Attribute(
2366
- value=self.sync(
2367
- ast3.Name(
2368
- id=Con.JAC_FEATURE.value,
2369
- ctx=ast3.Load(),
2370
- )
2371
- ),
2372
- attr="EdgeDir",
2373
- ctx=ast3.Load(),
2374
- )
2375
- ),
2376
- attr=node.op.edge_spec.edge_dir.name,
2377
- ctx=ast3.Load(),
2378
- )
2379
- ),
2380
- (
2381
- node.op.edge_spec.filter_cond.gen.py_ast[0]
2382
- if node.op.edge_spec.filter_cond is not None
2383
- else self.sync(ast3.Constant(value=None))
2384
- ),
2385
- ],
2386
- keywords=[],
2182
+ args=[node.right.gen.py_ast[0]],
2183
+ keywords=keywords,
2387
2184
  )
2388
2185
  )
2389
2186
  ]
@@ -2444,20 +2241,17 @@ class PyastGenPass(Pass):
2444
2241
  self.exit_func_call(func_node)
2445
2242
  return func_node.gen.py_ast
2446
2243
  elif node.op.name in [Tok.KW_SPAWN]:
2447
- self.needs_jac_feature()
2448
2244
  return [
2449
2245
  self.sync(
2450
2246
  ast3.Call(
2451
2247
  func=self.sync(
2452
2248
  ast3.Attribute(
2453
- value=self.sync(
2454
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2455
- ),
2456
- attr="spawn_call",
2249
+ value=node.left.gen.py_ast[0],
2250
+ attr="spawn",
2457
2251
  ctx=ast3.Load(),
2458
2252
  )
2459
2253
  ),
2460
- args=[node.left.gen.py_ast[0], node.right.gen.py_ast[0]],
2254
+ args=[node.right.gen.py_ast[0]],
2461
2255
  keywords=[],
2462
2256
  )
2463
2257
  )
@@ -2619,15 +2413,7 @@ class PyastGenPass(Pass):
2619
2413
  node.gen.py_ast = [
2620
2414
  self.sync(
2621
2415
  ast3.Call(
2622
- func=self.sync(
2623
- ast3.Attribute(
2624
- value=self.sync(
2625
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2626
- ),
2627
- attr="get_object",
2628
- ctx=ast3.Load(),
2629
- )
2630
- ),
2416
+ func=self.jaclib_obj("jobj"),
2631
2417
  args=[],
2632
2418
  keywords=[
2633
2419
  self.sync(
@@ -2727,14 +2513,32 @@ class PyastGenPass(Pass):
2727
2513
 
2728
2514
  values: Optional[SubNodeList[ExprType]],
2729
2515
  """
2730
- node.gen.py_ast = [
2731
- self.sync(
2732
- ast3.List(
2733
- elts=node.values.gen.py_ast if node.values else [],
2734
- ctx=node.py_ctx_func(),
2516
+ if isinstance(node.py_ctx_func(), ast3.Load):
2517
+ node.gen.py_ast = [
2518
+ self.sync(
2519
+ ast3.Call(
2520
+ func=self.jaclib_obj("JacList"),
2521
+ args=[
2522
+ self.sync(
2523
+ ast3.List(
2524
+ elts=node.values.gen.py_ast if node.values else [],
2525
+ ctx=ast3.Load(),
2526
+ )
2527
+ )
2528
+ ],
2529
+ keywords=[],
2530
+ )
2735
2531
  )
2736
- )
2737
- ]
2532
+ ]
2533
+ else:
2534
+ node.gen.py_ast = [
2535
+ self.sync(
2536
+ ast3.List(
2537
+ elts=node.values.gen.py_ast if node.values else [],
2538
+ ctx=node.py_ctx_func(),
2539
+ )
2540
+ )
2541
+ ]
2738
2542
 
2739
2543
  def exit_set_val(self, node: ast.SetVal) -> None:
2740
2544
  """Sub objects.
@@ -2834,9 +2638,17 @@ class PyastGenPass(Pass):
2834
2638
  """
2835
2639
  node.gen.py_ast = [
2836
2640
  self.sync(
2837
- ast3.ListComp(
2838
- elt=node.out_expr.gen.py_ast[0],
2839
- generators=[i.gen.py_ast[0] for i in node.compr],
2641
+ ast3.Call(
2642
+ func=self.jaclib_obj("JacList"),
2643
+ args=[
2644
+ self.sync(
2645
+ ast3.ListComp(
2646
+ elt=node.out_expr.gen.py_ast[0],
2647
+ generators=[i.gen.py_ast[0] for i in node.compr],
2648
+ )
2649
+ )
2650
+ ],
2651
+ keywords=[],
2840
2652
  )
2841
2653
  )
2842
2654
  ]
@@ -2917,8 +2729,14 @@ class PyastGenPass(Pass):
2917
2729
  node.gen.py_ast = [
2918
2730
  self.sync(
2919
2731
  ast3.Call(
2920
- func=node.right.gen.py_ast[0],
2921
- args=[node.target.gen.py_ast[0]],
2732
+ func=self.sync(
2733
+ ast3.Attribute(
2734
+ value=node.target.gen.py_ast[0],
2735
+ attr="filter",
2736
+ ctx=ast3.Load(),
2737
+ )
2738
+ ),
2739
+ args=cast(ast3.Tuple, node.right.gen.py_ast[0]).elts,
2922
2740
  keywords=[],
2923
2741
  )
2924
2742
  )
@@ -2929,14 +2747,12 @@ class PyastGenPass(Pass):
2929
2747
  ast3.Call(
2930
2748
  func=self.sync(
2931
2749
  ast3.Attribute(
2932
- value=self.sync(
2933
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2934
- ),
2935
- attr="assign_compr",
2750
+ value=node.target.gen.py_ast[0],
2751
+ attr="assign",
2936
2752
  ctx=ast3.Load(),
2937
2753
  )
2938
2754
  ),
2939
- args=[node.target.gen.py_ast[0], node.right.gen.py_ast[0]],
2755
+ args=cast(ast3.Tuple, node.right.gen.py_ast[0]).elts,
2940
2756
  keywords=[],
2941
2757
  )
2942
2758
  )
@@ -3044,7 +2860,6 @@ class PyastGenPass(Pass):
3044
2860
  else:
3045
2861
  self.ice("Invalid Parameter")
3046
2862
  if node.genai_call:
3047
- self.needs_jac_feature()
3048
2863
  by_llm_call_args = self.get_by_llm_call_args(node)
3049
2864
  node.gen.py_ast = [self.sync(self.by_llm_call(**by_llm_call_args))]
3050
2865
  else:
@@ -3122,26 +2937,7 @@ class PyastGenPass(Pass):
3122
2937
  )
3123
2938
  ]
3124
2939
  elif node.name == Tok.KW_ROOT:
3125
- node.gen.py_ast = [
3126
- self.sync(
3127
- ast3.Call(
3128
- func=self.sync(
3129
- ast3.Attribute(
3130
- value=self.sync(
3131
- ast3.Name(
3132
- id=Con.JAC_FEATURE.value,
3133
- ctx=ast3.Load(),
3134
- )
3135
- ),
3136
- attr="get_root",
3137
- ctx=ast3.Load(),
3138
- )
3139
- ),
3140
- args=[],
3141
- keywords=[],
3142
- )
3143
- )
3144
- ]
2940
+ node.gen.py_ast = [self.jaclib_obj("root")]
3145
2941
 
3146
2942
  else:
3147
2943
  node.gen.py_ast = [
@@ -3183,8 +2979,14 @@ class PyastGenPass(Pass):
3183
2979
  if next_i and isinstance(next_i, ast.FilterCompr):
3184
2980
  pynode = self.sync(
3185
2981
  ast3.Call(
3186
- func=next_i.gen.py_ast[0],
3187
- args=[pynode],
2982
+ func=self.sync(
2983
+ ast3.Attribute(
2984
+ value=pynode,
2985
+ attr="filter",
2986
+ ctx=ast3.Load(),
2987
+ )
2988
+ ),
2989
+ args=cast(ast3.Tuple, next_i.gen.py_ast[0]).elts,
3188
2990
  keywords=[],
3189
2991
  )
3190
2992
  )
@@ -3219,71 +3021,145 @@ class PyastGenPass(Pass):
3219
3021
  self,
3220
3022
  loc: ast3.AST,
3221
3023
  node: ast.EdgeOpRef,
3222
- targ: Optional[ast3.AST],
3024
+ targ: ast3.AST | None,
3223
3025
  edges_only: bool,
3224
3026
  ) -> ast3.AST:
3225
3027
  """Generate ast for edge op ref call."""
3226
- return self.sync(
3227
- ast3.Call(
3228
- func=self.sync(
3229
- ast3.Attribute(
3230
- value=self.sync(
3231
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
3232
- ),
3233
- attr="edge_ref",
3234
- ctx=ast3.Load(),
3235
- )
3236
- ),
3237
- args=[loc],
3238
- keywords=[
3239
- self.sync(
3240
- ast3.keyword(
3241
- arg="target_obj",
3242
- value=(
3243
- targ if targ else self.sync(ast3.Constant(value=None))
3244
- ),
3245
- )
3246
- ),
3247
- self.sync(
3248
- ast3.keyword(
3249
- arg="dir",
3250
- value=self.sync(
3028
+ args = []
3029
+ keywords = []
3030
+
3031
+ if node.filter_cond and node.filter_cond.f_type:
3032
+ args.append(self.sync(node.filter_cond.f_type.gen.py_ast[0]))
3033
+
3034
+ edge_iter_name = "edge"
3035
+ if node.filter_cond.compares:
3036
+
3037
+ expr: ast3.expr | None = None
3038
+ comp = node.filter_cond.compares.items[0]
3039
+ if (
3040
+ len(node.filter_cond.compares.items) == 1
3041
+ and isinstance(comp.gen.py_ast[0], ast3.Compare)
3042
+ and isinstance(comp.gen.py_ast[0].left, ast3.Name)
3043
+ ):
3044
+ expr = self.sync(
3045
+ ast3.Compare(
3046
+ left=self.sync(
3251
3047
  ast3.Attribute(
3252
3048
  value=self.sync(
3253
- ast3.Attribute(
3254
- value=self.sync(
3255
- ast3.Name(
3256
- id=Con.JAC_FEATURE.value,
3257
- ctx=ast3.Load(),
3258
- )
3259
- ),
3260
- attr="EdgeDir",
3049
+ ast3.Name(
3050
+ id=edge_iter_name,
3261
3051
  ctx=ast3.Load(),
3262
- )
3052
+ ),
3053
+ jac_node=comp,
3263
3054
  ),
3264
- attr=node.edge_dir.name,
3055
+ attr=comp.gen.py_ast[0].left.id,
3265
3056
  ctx=ast3.Load(),
3266
- )
3057
+ ),
3058
+ jac_node=comp,
3267
3059
  ),
3268
- )
3269
- ),
3060
+ ops=comp.gen.py_ast[0].ops,
3061
+ comparators=comp.gen.py_ast[0].comparators,
3062
+ ),
3063
+ jac_node=comp,
3064
+ )
3065
+ else:
3066
+ expr = self.sync(
3067
+ ast3.BoolOp(
3068
+ op=self.sync(ast3.And()),
3069
+ values=[
3070
+ self.sync(
3071
+ ast3.Compare(
3072
+ left=self.sync(
3073
+ ast3.Attribute(
3074
+ value=self.sync(
3075
+ ast3.Name(
3076
+ id=edge_iter_name,
3077
+ ctx=ast3.Load(),
3078
+ ),
3079
+ jac_node=comp,
3080
+ ),
3081
+ attr=comp.gen.py_ast[0].left.id,
3082
+ ctx=ast3.Load(),
3083
+ ),
3084
+ jac_node=comp,
3085
+ ),
3086
+ ops=comp.gen.py_ast[0].ops,
3087
+ comparators=comp.gen.py_ast[0].comparators,
3088
+ ),
3089
+ jac_node=comp,
3090
+ )
3091
+ for comp in node.filter_cond.compares.items
3092
+ if isinstance(comp.gen.py_ast[0], ast3.Compare)
3093
+ and isinstance(comp.gen.py_ast[0].left, ast3.Name)
3094
+ ],
3095
+ ),
3096
+ )
3097
+ assert expr is not None
3098
+
3099
+ args.append(
3270
3100
  self.sync(
3271
- ast3.keyword(
3272
- arg="filter_func",
3273
- value=self.sync(
3274
- node.filter_cond.gen.py_ast[0]
3275
- if node.filter_cond
3276
- else self.sync(ast3.Constant(value=None))
3101
+ ast3.Lambda(
3102
+ args=self.sync(
3103
+ ast3.arguments(
3104
+ posonlyargs=[],
3105
+ args=[self.sync(ast3.arg(arg=edge_iter_name))],
3106
+ kwonlyargs=[],
3107
+ kw_defaults=[],
3108
+ defaults=[],
3109
+ )
3277
3110
  ),
3111
+ body=expr,
3278
3112
  )
3279
- ),
3280
- self.sync(
3281
- ast3.keyword(
3282
- arg="edges_only",
3283
- value=self.sync(ast3.Constant(value=edges_only)),
3284
- )
3285
- ),
3286
- ],
3113
+ )
3114
+ )
3115
+
3116
+ if targ is not None:
3117
+ keywords.append(
3118
+ self.sync(
3119
+ ast3.keyword(
3120
+ arg="target",
3121
+ value=self.sync(ast3.Constant(value=None)),
3122
+ )
3123
+ )
3124
+ )
3125
+
3126
+ if node.edge_dir != EdgeDir.OUT:
3127
+ keywords.append(
3128
+ self.sync(
3129
+ ast3.keyword(
3130
+ arg="dir",
3131
+ value=self.sync(
3132
+ ast3.Attribute(
3133
+ value=self.jaclib_obj("EdgeDir"),
3134
+ attr=node.edge_dir.name,
3135
+ ctx=ast3.Load(),
3136
+ )
3137
+ ),
3138
+ )
3139
+ )
3140
+ )
3141
+
3142
+ if edges_only:
3143
+ keywords.append(
3144
+ self.sync(
3145
+ ast3.keyword(
3146
+ arg="edges_only",
3147
+ value=self.sync(ast3.Constant(value=edges_only)),
3148
+ )
3149
+ )
3150
+ )
3151
+
3152
+ return self.sync(
3153
+ ast3.Call(
3154
+ func=self.sync(
3155
+ ast3.Attribute(
3156
+ value=loc,
3157
+ attr="refs",
3158
+ ctx=ast3.Load(),
3159
+ )
3160
+ ),
3161
+ args=args,
3162
+ keywords=keywords,
3287
3163
  )
3288
3164
  )
3289
3165
 
@@ -3306,9 +3182,7 @@ class PyastGenPass(Pass):
3306
3182
  ast3.Call(
3307
3183
  func=self.sync(
3308
3184
  ast3.Attribute(
3309
- value=self.sync(
3310
- ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
3311
- ),
3185
+ value=self.jaclib_obj(Con.JAC_FEATURE.value),
3312
3186
  attr="build_edge",
3313
3187
  ctx=ast3.Load(),
3314
3188
  )
@@ -3353,106 +3227,74 @@ class PyastGenPass(Pass):
3353
3227
 
3354
3228
  compares: SubNodeList[BinaryExpr],
3355
3229
  """
3356
- node.gen.py_ast = [
3230
+ iter_name = "item"
3231
+ comprs = [
3357
3232
  self.sync(
3358
- ast3.Lambda(
3359
- args=self.sync(
3360
- ast3.arguments(
3361
- posonlyargs=[],
3362
- args=[self.sync(ast3.arg(arg="x"))],
3363
- kwonlyargs=[],
3364
- kw_defaults=[],
3365
- defaults=[],
3366
- )
3233
+ ast3.Compare(
3234
+ left=self.sync(
3235
+ ast3.Attribute(
3236
+ value=self.sync(
3237
+ ast3.Name(
3238
+ id=iter_name,
3239
+ ctx=ast3.Load(),
3240
+ ),
3241
+ jac_node=x,
3242
+ ),
3243
+ attr=x.gen.py_ast[0].left.id,
3244
+ ctx=ast3.Load(),
3245
+ ),
3246
+ jac_node=x,
3367
3247
  ),
3368
- body=self.sync(
3369
- ast3.ListComp(
3370
- elt=self.sync(ast3.Name(id="i", ctx=ast3.Load())),
3371
- generators=[
3372
- self.sync(
3373
- ast3.comprehension(
3374
- target=self.sync(
3375
- ast3.Name(id="i", ctx=ast3.Store())
3376
- ),
3377
- iter=self.sync(
3378
- ast3.Name(id="x", ctx=ast3.Load())
3379
- ),
3380
- ifs=(
3381
- (
3382
- [
3383
- self.sync(
3384
- ast3.Call(
3385
- func=self.sync(
3386
- ast3.Name(
3387
- id="isinstance",
3388
- ctx=ast3.Load(),
3389
- )
3390
- ),
3391
- args=[
3392
- self.sync(
3393
- ast3.Name(
3394
- id="i",
3395
- ctx=ast3.Load(),
3396
- )
3397
- ),
3398
- self.sync(
3399
- node.f_type.gen.py_ast[
3400
- 0
3401
- ]
3402
- ),
3403
- ],
3404
- keywords=[],
3405
- )
3406
- )
3407
- ]
3408
- if node.f_type
3409
- else []
3410
- )
3411
- + [
3412
- self.sync(
3413
- ast3.Compare(
3414
- left=self.sync(
3415
- ast3.Attribute(
3416
- value=self.sync(
3417
- ast3.Name(
3418
- id="i",
3419
- ctx=ast3.Load(),
3420
- ),
3421
- jac_node=x,
3422
- ),
3423
- attr=x.gen.py_ast[
3424
- 0
3425
- ].left.id,
3426
- ctx=ast3.Load(),
3427
- ),
3428
- jac_node=x,
3429
- ),
3430
- ops=x.gen.py_ast[0].ops,
3431
- comparators=x.gen.py_ast[
3432
- 0
3433
- ].comparators,
3434
- ),
3435
- jac_node=x,
3436
- )
3437
- for x in (
3438
- node.compares.items
3439
- if node.compares
3440
- else []
3441
- )
3442
- if isinstance(
3443
- x.gen.py_ast[0], ast3.Compare
3444
- )
3445
- and isinstance(
3446
- x.gen.py_ast[0].left, ast3.Name
3447
- )
3448
- ]
3449
- ),
3450
- is_async=0,
3451
- )
3248
+ ops=x.gen.py_ast[0].ops,
3249
+ comparators=x.gen.py_ast[0].comparators,
3250
+ ),
3251
+ jac_node=x,
3252
+ )
3253
+ for x in (node.compares.items if node.compares else [])
3254
+ if isinstance(x.gen.py_ast[0], ast3.Compare)
3255
+ and isinstance(x.gen.py_ast[0].left, ast3.Name)
3256
+ ]
3257
+
3258
+ body = (
3259
+ self.sync(
3260
+ ast3.BoolOp(
3261
+ op=self.sync(ast3.And()),
3262
+ values=comprs,
3263
+ )
3264
+ )
3265
+ if len(comprs) > 1
3266
+ else (comprs[0] if comprs else None)
3267
+ )
3268
+
3269
+ node.gen.py_ast = [
3270
+ self.sync(
3271
+ ast3.Tuple(
3272
+ elts=[
3273
+ (
3274
+ self.sync(node.f_type.gen.py_ast[0])
3275
+ if node.f_type
3276
+ else self.sync(ast3.Constant(value=None))
3277
+ ),
3278
+ (
3279
+ self.sync(
3280
+ ast3.Lambda(
3281
+ args=self.sync(
3282
+ ast3.arguments(
3283
+ posonlyargs=[],
3284
+ args=[self.sync(ast3.arg(arg=iter_name))],
3285
+ kwonlyargs=[],
3286
+ kw_defaults=[],
3287
+ defaults=[],
3288
+ )
3289
+ ),
3290
+ body=body,
3452
3291
  )
3453
- ],
3454
- )
3455
- ),
3292
+ )
3293
+ if body
3294
+ else self.sync(ast3.Constant(value=None))
3295
+ ),
3296
+ ],
3297
+ ctx=ast3.Load(),
3456
3298
  )
3457
3299
  )
3458
3300
  ]