jaclang 0.8.7__py3-none-any.whl → 0.8.9__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 (99) hide show
  1. jaclang/cli/cli.py +77 -29
  2. jaclang/cli/cmdreg.py +44 -0
  3. jaclang/compiler/constant.py +6 -2
  4. jaclang/compiler/jac.lark +37 -47
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +356 -61
  7. jaclang/compiler/passes/main/__init__.py +2 -4
  8. jaclang/compiler/passes/main/def_use_pass.py +1 -4
  9. jaclang/compiler/passes/main/predynamo_pass.py +221 -0
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +221 -135
  11. jaclang/compiler/passes/main/pyast_load_pass.py +54 -20
  12. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  13. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
  14. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
  22. jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
  23. jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
  24. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
  25. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
  26. jaclang/compiler/passes/main/tests/test_checker_pass.py +190 -0
  27. jaclang/compiler/passes/main/tests/test_predynamo_pass.py +56 -0
  28. jaclang/compiler/passes/main/type_checker_pass.py +29 -73
  29. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +302 -58
  30. jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
  31. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  32. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
  33. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
  34. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +276 -10
  35. jaclang/compiler/passes/transform.py +12 -8
  36. jaclang/compiler/program.py +19 -7
  37. jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
  38. jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
  39. jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
  40. jaclang/compiler/tests/fixtures/python_module.py +1 -0
  41. jaclang/compiler/tests/test_importer.py +39 -0
  42. jaclang/compiler/tests/test_parser.py +49 -0
  43. jaclang/compiler/type_system/type_evaluator.jac +959 -0
  44. jaclang/compiler/type_system/type_utils.py +246 -0
  45. jaclang/compiler/type_system/types.py +58 -2
  46. jaclang/compiler/unitree.py +102 -107
  47. jaclang/langserve/engine.jac +138 -159
  48. jaclang/langserve/server.jac +25 -1
  49. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  50. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  51. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  52. jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
  53. jaclang/langserve/tests/server_test/circle_template.jac +80 -0
  54. jaclang/langserve/tests/server_test/glob_template.jac +4 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
  56. jaclang/langserve/tests/server_test/utils.py +153 -116
  57. jaclang/langserve/tests/test_server.py +21 -84
  58. jaclang/langserve/utils.jac +12 -15
  59. jaclang/lib.py +17 -0
  60. jaclang/runtimelib/archetype.py +25 -25
  61. jaclang/runtimelib/constructs.py +2 -2
  62. jaclang/runtimelib/machine.py +63 -46
  63. jaclang/runtimelib/meta_importer.py +27 -1
  64. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  65. jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
  66. jaclang/settings.py +19 -16
  67. jaclang/tests/fixtures/abc_check.jac +3 -3
  68. jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
  69. jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
  70. jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
  71. jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
  72. jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
  73. jaclang/tests/fixtures/funccall_genexpr.py +5 -0
  74. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  75. jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
  76. jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
  77. jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
  78. jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
  79. jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
  80. jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
  81. jaclang/tests/fixtures/py2jac_params.py +8 -0
  82. jaclang/tests/fixtures/run_test.jac +4 -4
  83. jaclang/tests/test_cli.py +159 -7
  84. jaclang/tests/test_language.py +213 -38
  85. jaclang/tests/test_reference.py +3 -1
  86. jaclang/utils/helpers.py +67 -6
  87. jaclang/utils/module_resolver.py +10 -0
  88. jaclang/utils/test.py +8 -0
  89. jaclang/utils/tests/test_lang_tools.py +4 -15
  90. jaclang/utils/treeprinter.py +0 -18
  91. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/METADATA +1 -2
  92. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/RECORD +95 -65
  93. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/WHEEL +1 -1
  94. jaclang/compiler/passes/main/inheritance_pass.py +0 -131
  95. jaclang/compiler/type_system/type_evaluator.py +0 -560
  96. jaclang/langserve/dev_engine.jac +0 -645
  97. jaclang/langserve/dev_server.jac +0 -201
  98. /jaclang/{langserve/tests/server_test/code_test.py → tests/fixtures/py2jac_empty.py} +0 -0
  99. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/entry_points.txt +0 -0
@@ -7,6 +7,7 @@ import builtins
7
7
  import os
8
8
  from copy import copy
9
9
  from dataclasses import dataclass
10
+ from enum import IntEnum
10
11
  from hashlib import md5
11
12
  from types import EllipsisType
12
13
  from typing import (
@@ -306,7 +307,6 @@ class UniScopeNode(UniNode):
306
307
  self.parent_scope = parent_scope
307
308
  self.kid_scope: list[UniScopeNode] = []
308
309
  self.names_in_scope: dict[str, Symbol] = {}
309
- self.inherited_scope: list[InheritedSymbolTable] = []
310
310
 
311
311
  def get_type(self) -> SymbolType:
312
312
  """Get type."""
@@ -322,10 +322,6 @@ class UniScopeNode(UniNode):
322
322
  """Lookup a variable in the symbol table."""
323
323
  if name in self.names_in_scope:
324
324
  return self.names_in_scope[name]
325
- for i in self.inherited_scope:
326
- found = i.lookup(name, deep=False)
327
- if found:
328
- return found
329
325
  if deep and self.parent_scope:
330
326
  return self.parent_scope.lookup(name, deep)
331
327
  return None
@@ -369,9 +365,6 @@ class UniScopeNode(UniNode):
369
365
  for k in self.kid_scope:
370
366
  if k.scope_name == name:
371
367
  return k
372
- for k2 in self.inherited_scope:
373
- if k2.base_symbol_table.scope_name == name:
374
- return k2.base_symbol_table
375
368
  return None
376
369
 
377
370
  def link_kid_scope(self, key_node: UniScopeNode) -> UniScopeNode:
@@ -489,22 +482,6 @@ class UniScopeNode(UniNode):
489
482
 
490
483
  fix(node)
491
484
 
492
- def inherit_baseclasses_sym(self, node: Archetype | Enum) -> None:
493
- """Inherit base classes symbol tables."""
494
- if node.base_classes:
495
- for base_cls in node.base_classes:
496
- if (
497
- isinstance(base_cls, AstSymbolNode)
498
- and (found := self.use_lookup(base_cls))
499
- and found
500
- ):
501
- found_tab = found.decl.sym_tab
502
- inher_sym_tab = InheritedSymbolTable(
503
- base_symbol_table=found_tab, load_all_symbols=True, symbols=[]
504
- )
505
- self.inherited_scope.append(inher_sym_tab)
506
- base_cls.name_spec.name_of = found.decl.name_of
507
-
508
485
  def sym_pp(self, depth: Optional[int] = None) -> str:
509
486
  """Pretty print."""
510
487
  return print_symtab_tree(root=self, depth=depth)
@@ -521,31 +498,6 @@ class UniScopeNode(UniNode):
521
498
  return out
522
499
 
523
500
 
524
- class InheritedSymbolTable:
525
- """Inherited symbol table."""
526
-
527
- def __init__(
528
- self,
529
- base_symbol_table: UniScopeNode,
530
- load_all_symbols: bool = False, # This is needed for python imports
531
- symbols: Optional[list[str]] = None,
532
- ) -> None:
533
- """Initialize."""
534
- self.base_symbol_table: UniScopeNode = base_symbol_table
535
- self.load_all_symbols: bool = load_all_symbols
536
- self.symbols: list[str] = symbols if symbols else []
537
-
538
- def lookup(self, name: str, deep: bool = False) -> Optional[Symbol]:
539
- """Lookup a variable in the symbol table."""
540
- if self.load_all_symbols:
541
- return self.base_symbol_table.lookup(name, deep)
542
- else:
543
- if name in self.symbols:
544
- return self.base_symbol_table.lookup(name, deep)
545
- else:
546
- return None
547
-
548
-
549
501
  class AstSymbolNode(UniNode):
550
502
  """Nodes that have link to a symbol in symbol table."""
551
503
 
@@ -922,6 +874,12 @@ class Module(AstDocNode, UniScopeNode):
922
874
  self.src_terminals: list[Token] = terminals
923
875
  self.is_raised_from_py: bool = False
924
876
 
877
+ # We continue to parse a module even if there are syntax errors
878
+ # so that we can report more errors in a single pass and support
879
+ # features like code completion, lsp, format etc. This flag
880
+ # indicates if there were syntax errors during parsing.
881
+ self.has_syntax_errors: bool = False
882
+
925
883
  UniNode.__init__(self, kid=kid)
926
884
  AstDocNode.__init__(self, doc=doc)
927
885
  UniScopeNode.__init__(self, name=self.name)
@@ -1441,23 +1399,12 @@ class Archetype(
1441
1399
  self,
1442
1400
  sym_name=name.value,
1443
1401
  name_spec=name,
1444
- sym_category=(
1445
- SymbolType.OBJECT_ARCH
1446
- if arch_type.name == Tok.KW_OBJECT
1447
- else (
1448
- SymbolType.NODE_ARCH
1449
- if arch_type.name == Tok.KW_NODE
1450
- else (
1451
- SymbolType.EDGE_ARCH
1452
- if arch_type.name == Tok.KW_EDGE
1453
- else (
1454
- SymbolType.WALKER_ARCH
1455
- if arch_type.name == Tok.KW_WALKER
1456
- else SymbolType.TYPE
1457
- )
1458
- )
1459
- )
1460
- ),
1402
+ sym_category={
1403
+ Tok.KW_OBJECT.value: SymbolType.OBJECT_ARCH,
1404
+ Tok.KW_NODE.value: SymbolType.NODE_ARCH,
1405
+ Tok.KW_EDGE.value: SymbolType.EDGE_ARCH,
1406
+ Tok.KW_WALKER.value: SymbolType.WALKER_ARCH,
1407
+ }.get(arch_type.name, SymbolType.TYPE),
1461
1408
  )
1462
1409
  AstImplNeedingNode.__init__(self, body=body)
1463
1410
  AstAccessNode.__init__(self, access=access)
@@ -1941,11 +1888,19 @@ class FuncSignature(UniNode):
1941
1888
 
1942
1889
  def __init__(
1943
1890
  self,
1891
+ posonly_params: Sequence[ParamVar],
1944
1892
  params: Sequence[ParamVar] | None,
1893
+ varargs: Optional[ParamVar],
1894
+ kwonlyargs: Sequence[ParamVar],
1895
+ kwargs: Optional[ParamVar],
1945
1896
  return_type: Optional[Expr],
1946
1897
  kid: Sequence[UniNode],
1947
1898
  ) -> None:
1899
+ self.posonly_params: list[ParamVar] = list(posonly_params)
1948
1900
  self.params: list[ParamVar] = list(params) if params else []
1901
+ self.varargs = varargs
1902
+ self.kwonlyargs: list[ParamVar] = list(kwonlyargs)
1903
+ self.kwargs = kwargs
1949
1904
  self.return_type = return_type
1950
1905
  UniNode.__init__(self, kid=kid)
1951
1906
 
@@ -1953,14 +1908,36 @@ class FuncSignature(UniNode):
1953
1908
  res = True
1954
1909
  is_lambda = self.parent and isinstance(self.parent, LambdaExpr)
1955
1910
  if deep:
1911
+ for prm in self.posonly_params:
1912
+ res = res and prm.normalize(deep)
1956
1913
  for prm in self.params:
1957
1914
  res = res and prm.normalize(deep)
1958
1915
  res = res and self.return_type.normalize(deep) if self.return_type else res
1959
1916
  new_kid: list[UniNode] = [self.gen_token(Tok.LPAREN)] if not is_lambda else []
1960
- for idx, prm in enumerate(self.params):
1961
- new_kid.append(prm)
1962
- if idx < len(self.params) - 1:
1917
+ if self.posonly_params:
1918
+ for prm in self.posonly_params:
1919
+ new_kid.append(prm)
1920
+ new_kid.append(self.gen_token(Tok.COMMA))
1921
+ new_kid.append(self.gen_token(Tok.DIV))
1922
+ new_kid.append(self.gen_token(Tok.COMMA))
1923
+ if self.params:
1924
+ for prm in self.params:
1925
+ new_kid.append(prm)
1963
1926
  new_kid.append(self.gen_token(Tok.COMMA))
1927
+ if self.varargs:
1928
+ new_kid.append(self.varargs)
1929
+ new_kid.append(self.gen_token(Tok.COMMA))
1930
+ elif self.kwonlyargs:
1931
+ new_kid.append(self.gen_token(Tok.STAR_MUL))
1932
+ new_kid.append(self.gen_token(Tok.COMMA))
1933
+ for prm in self.kwonlyargs:
1934
+ new_kid.append(prm)
1935
+ new_kid.append(self.gen_token(Tok.COMMA))
1936
+ if self.kwargs:
1937
+ new_kid.append(self.kwargs)
1938
+ new_kid.append(self.gen_token(Tok.COMMA))
1939
+ if new_kid and isinstance(new_kid[-1], Token) and new_kid[-1].name == Tok.COMMA:
1940
+ new_kid = new_kid[:-1]
1964
1941
  if not is_lambda:
1965
1942
  new_kid.append(self.gen_token(Tok.RPAREN))
1966
1943
  if self.return_type:
@@ -1969,6 +1946,16 @@ class FuncSignature(UniNode):
1969
1946
  self.set_kids(nodes=new_kid)
1970
1947
  return res
1971
1948
 
1949
+ def get_parameters(self) -> list[ParamVar]:
1950
+ """Return all parameters in the declared order."""
1951
+ params = self.posonly_params + self.params
1952
+ if self.varargs:
1953
+ params.append(self.varargs)
1954
+ params += self.kwonlyargs
1955
+ if self.kwargs:
1956
+ params.append(self.kwargs)
1957
+ return params
1958
+
1972
1959
  @property
1973
1960
  def is_static(self) -> bool:
1974
1961
  return (isinstance(self.parent, Ability) and self.parent.is_static) or (
@@ -2025,6 +2012,16 @@ class EventSignature(WalkerStmtOnlyNode):
2025
2012
  return res
2026
2013
 
2027
2014
 
2015
+ class ParamKind(IntEnum):
2016
+ """Parameter kinds."""
2017
+
2018
+ POSONLY = 0
2019
+ NORMAL = 1
2020
+ VARARG = 2
2021
+ KWONLY = 3
2022
+ KWARG = 4
2023
+
2024
+
2028
2025
  class ParamVar(AstSymbolNode, AstTypedVarNode):
2029
2026
  """ParamVar node type for Jac Ast."""
2030
2027
 
@@ -2038,6 +2035,7 @@ class ParamVar(AstSymbolNode, AstTypedVarNode):
2038
2035
  ) -> None:
2039
2036
  self.name = name
2040
2037
  self.unpack = unpack
2038
+ self.param_kind = ParamKind.NORMAL
2041
2039
  self.value = value
2042
2040
  UniNode.__init__(self, kid=kid)
2043
2041
  AstSymbolNode.__init__(
@@ -2048,6 +2046,14 @@ class ParamVar(AstSymbolNode, AstTypedVarNode):
2048
2046
  )
2049
2047
  AstTypedVarNode.__init__(self, type_tag=type_tag)
2050
2048
 
2049
+ @property
2050
+ def is_vararg(self) -> bool:
2051
+ return bool((self.unpack) and (self.unpack.name == Tok.STAR_MUL.name))
2052
+
2053
+ @property
2054
+ def is_kwargs(self) -> bool:
2055
+ return bool((self.unpack) and (self.unpack.name == Tok.STAR_POW.name))
2056
+
2051
2057
  def normalize(self, deep: bool = True) -> bool:
2052
2058
  res = True
2053
2059
  if deep:
@@ -2161,7 +2167,7 @@ class HasVar(AstSymbolNode, AstTypedVarNode):
2161
2167
  return res
2162
2168
 
2163
2169
 
2164
- class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
2170
+ class TypedCtxBlock(CodeBlockStmt, WalkerStmtOnlyNode, UniScopeNode):
2165
2171
  """TypedCtxBlock node type for Jac Ast."""
2166
2172
 
2167
2173
  def __init__(
@@ -2175,6 +2181,7 @@ class TypedCtxBlock(CodeBlockStmt, UniScopeNode):
2175
2181
  UniNode.__init__(self, kid=kid)
2176
2182
  UniScopeNode.__init__(self, name=f"{self.__class__.__name__}")
2177
2183
  CodeBlockStmt.__init__(self)
2184
+ WalkerStmtOnlyNode.__init__(self)
2178
2185
 
2179
2186
  def normalize(self, deep: bool = False) -> bool:
2180
2187
  res = True
@@ -2687,31 +2694,6 @@ class AssertStmt(CodeBlockStmt):
2687
2694
  return res
2688
2695
 
2689
2696
 
2690
- class CheckStmt(CodeBlockStmt):
2691
- """CheckStmt node type for Jac Ast."""
2692
-
2693
- def __init__(
2694
- self,
2695
- target: Expr,
2696
- kid: Sequence[UniNode],
2697
- ) -> None:
2698
- self.target = target
2699
- UniNode.__init__(self, kid=kid)
2700
- CodeBlockStmt.__init__(self)
2701
-
2702
- def normalize(self, deep: bool = False) -> bool:
2703
- res = True
2704
- if deep:
2705
- res = self.target.normalize(deep)
2706
- new_kid: list[UniNode] = [
2707
- self.gen_token(Tok.KW_CHECK),
2708
- self.target,
2709
- self.gen_token(Tok.SEMI),
2710
- ]
2711
- self.set_kids(nodes=new_kid)
2712
- return res
2713
-
2714
-
2715
2697
  class CtrlStmt(CodeBlockStmt):
2716
2698
  """CtrlStmt node type for Jac Ast."""
2717
2699
 
@@ -3248,13 +3230,21 @@ class FString(AtomExpr):
3248
3230
  for part in self.parts:
3249
3231
  res = res and part.normalize(deep)
3250
3232
  new_kid: list[UniNode] = []
3251
- is_single_quote = (
3252
- isinstance(self.kid[0], Token) and self.kid[0].name == Tok.FSTR_SQ_START
3253
- )
3254
- if is_single_quote:
3255
- new_kid.append(self.gen_token(Tok.FSTR_SQ_START))
3233
+ # Determine quote type from first token
3234
+ start_token = self.kid[0] if isinstance(self.kid[0], Token) else None
3235
+ if start_token:
3236
+ if start_token.name == Tok.FSTR_SQ_TRIPLE_START:
3237
+ start_tok, end_tok = Tok.FSTR_SQ_TRIPLE_START, Tok.FSTR_SQ_TRIPLE_END
3238
+ elif start_token.name == Tok.FSTR_TRIPLE_START:
3239
+ start_tok, end_tok = Tok.FSTR_TRIPLE_START, Tok.FSTR_TRIPLE_END
3240
+ elif start_token.name == Tok.FSTR_SQ_START:
3241
+ start_tok, end_tok = Tok.FSTR_SQ_START, Tok.FSTR_SQ_END
3242
+ else:
3243
+ start_tok, end_tok = Tok.FSTR_START, Tok.FSTR_END
3256
3244
  else:
3257
- new_kid.append(self.gen_token(Tok.FSTR_START))
3245
+ start_tok, end_tok = Tok.FSTR_START, Tok.FSTR_END
3246
+
3247
+ new_kid.append(self.gen_token(start_tok))
3258
3248
  for i in self.parts:
3259
3249
  if isinstance(i, String):
3260
3250
  i.value = (
@@ -3265,10 +3255,7 @@ class FString(AtomExpr):
3265
3255
  new_kid.append(self.gen_token(Tok.LBRACE))
3266
3256
  new_kid.append(i)
3267
3257
  new_kid.append(self.gen_token(Tok.RBRACE))
3268
- if is_single_quote:
3269
- new_kid.append(self.gen_token(Tok.FSTR_SQ_END))
3270
- else:
3271
- new_kid.append(self.gen_token(Tok.FSTR_END))
3258
+ new_kid.append(self.gen_token(end_tok))
3272
3259
  self.set_kids(nodes=new_kid)
3273
3260
  return res
3274
3261
 
@@ -3731,7 +3718,10 @@ class FuncCall(Expr):
3731
3718
  res = self.target.normalize(deep)
3732
3719
  for prm in self.params:
3733
3720
  res = res and prm.normalize(deep)
3734
- new_kids = [self.target, self.gen_token(Tok.LPAREN, "(")]
3721
+ new_kids: list[UniNode] = [self.target]
3722
+ is_gencompr = len(self.params) == 1 and isinstance(self.params[0], GenCompr)
3723
+ if not is_gencompr:
3724
+ new_kids.append(self.gen_token(Tok.LPAREN))
3735
3725
  for i, prm in enumerate(self.params):
3736
3726
  new_kids.append(prm)
3737
3727
  if i < len(self.params) - 1:
@@ -3739,7 +3729,8 @@ class FuncCall(Expr):
3739
3729
  if self.genai_call:
3740
3730
  new_kids.append(self.gen_token(Tok.KW_BY))
3741
3731
  new_kids.append(self.genai_call)
3742
- new_kids.append(self.gen_token(Tok.RPAREN, ")"))
3732
+ if not is_gencompr:
3733
+ new_kids.append(self.gen_token(Tok.RPAREN, ")"))
3743
3734
  self.set_kids(nodes=new_kids)
3744
3735
  return res
3745
3736
 
@@ -3831,10 +3822,12 @@ class EdgeRefTrailer(Expr):
3831
3822
  self,
3832
3823
  chain: list[Expr | FilterCompr],
3833
3824
  edges_only: bool,
3825
+ is_async: bool,
3834
3826
  kid: Sequence[UniNode],
3835
3827
  ) -> None:
3836
3828
  self.chain = chain
3837
3829
  self.edges_only = edges_only
3830
+ self.is_async = is_async
3838
3831
  UniNode.__init__(self, kid=kid)
3839
3832
  Expr.__init__(self)
3840
3833
 
@@ -3844,6 +3837,8 @@ class EdgeRefTrailer(Expr):
3844
3837
  res = res and expr.normalize(deep)
3845
3838
  new_kid: list[UniNode] = []
3846
3839
  new_kid.append(self.gen_token(Tok.LSQUARE))
3840
+ if self.is_async:
3841
+ new_kid.append(self.gen_token(Tok.KW_ASYNC))
3847
3842
  if self.edges_only:
3848
3843
  new_kid.append(self.gen_token(Tok.KW_EDGE))
3849
3844
  new_kid.extend(self.chain)