jaclang 0.7.1__py3-none-any.whl → 0.7.5__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 (85) hide show
  1. jaclang/cli/cli.py +2 -2
  2. jaclang/compiler/absyntree.py +378 -277
  3. jaclang/compiler/codeloc.py +2 -2
  4. jaclang/compiler/constant.py +2 -0
  5. jaclang/compiler/jac.lark +25 -19
  6. jaclang/compiler/parser.py +115 -92
  7. jaclang/compiler/passes/main/access_modifier_pass.py +15 -9
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +29 -11
  9. jaclang/compiler/passes/main/def_use_pass.py +48 -17
  10. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +49 -30
  11. jaclang/compiler/passes/main/import_pass.py +12 -7
  12. jaclang/compiler/passes/main/pyast_gen_pass.py +110 -47
  13. jaclang/compiler/passes/main/pyast_load_pass.py +49 -13
  14. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +25 -11
  15. jaclang/compiler/passes/main/pyout_pass.py +3 -1
  16. jaclang/compiler/passes/main/registry_pass.py +6 -6
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +30 -72
  18. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
  19. jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
  20. jaclang/compiler/passes/main/tests/test_import_pass.py +8 -0
  21. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  22. jaclang/compiler/passes/main/type_check_pass.py +2 -1
  23. jaclang/compiler/passes/tool/jac_formatter_pass.py +44 -11
  24. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
  27. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
  28. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  29. jaclang/compiler/passes/transform.py +2 -4
  30. jaclang/{core/registry.py → compiler/semtable.py} +1 -3
  31. jaclang/compiler/symtable.py +39 -31
  32. jaclang/compiler/tests/test_parser.py +2 -2
  33. jaclang/core/aott.py +112 -16
  34. jaclang/core/{construct.py → architype.py} +44 -93
  35. jaclang/core/constructs.py +44 -0
  36. jaclang/core/context.py +157 -0
  37. jaclang/core/importer.py +18 -9
  38. jaclang/core/llms/anthropic.py +31 -2
  39. jaclang/core/llms/base.py +3 -3
  40. jaclang/core/llms/groq.py +4 -1
  41. jaclang/core/llms/huggingface.py +4 -1
  42. jaclang/core/llms/ollama.py +4 -1
  43. jaclang/core/llms/openai.py +6 -2
  44. jaclang/core/llms/togetherai.py +4 -1
  45. jaclang/core/memory.py +53 -2
  46. jaclang/core/test.py +90 -0
  47. jaclang/core/utils.py +2 -2
  48. jaclang/langserve/engine.py +119 -122
  49. jaclang/langserve/server.py +27 -5
  50. jaclang/langserve/tests/fixtures/circle.jac +16 -12
  51. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  52. jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
  53. jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
  54. jaclang/langserve/tests/test_server.py +114 -0
  55. jaclang/langserve/utils.py +104 -10
  56. jaclang/plugin/builtin.py +1 -1
  57. jaclang/plugin/default.py +46 -90
  58. jaclang/plugin/feature.py +32 -16
  59. jaclang/plugin/spec.py +17 -19
  60. jaclang/plugin/tests/test_features.py +0 -33
  61. jaclang/settings.py +4 -0
  62. jaclang/tests/fixtures/abc.jac +16 -12
  63. jaclang/tests/fixtures/byllmissue.jac +12 -0
  64. jaclang/tests/fixtures/edgetypetest.jac +16 -0
  65. jaclang/tests/fixtures/hash_init_check.jac +17 -0
  66. jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
  67. jaclang/tests/fixtures/impl_match_confused.jac +5 -0
  68. jaclang/tests/fixtures/math_question.jpg +0 -0
  69. jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
  70. jaclang/tests/fixtures/nosigself.jac +19 -0
  71. jaclang/tests/fixtures/run_test.jac +17 -5
  72. jaclang/tests/fixtures/walker_override.jac +21 -0
  73. jaclang/tests/fixtures/with_llm_vision.jac +25 -0
  74. jaclang/tests/test_bugs.py +19 -0
  75. jaclang/tests/test_cli.py +1 -1
  76. jaclang/tests/test_language.py +116 -11
  77. jaclang/tests/test_reference.py +1 -1
  78. jaclang/utils/lang_tools.py +5 -4
  79. jaclang/utils/test.py +2 -1
  80. jaclang/utils/treeprinter.py +35 -4
  81. {jaclang-0.7.1.dist-info → jaclang-0.7.5.dist-info}/METADATA +3 -2
  82. {jaclang-0.7.1.dist-info → jaclang-0.7.5.dist-info}/RECORD +84 -71
  83. jaclang/core/shelve_storage.py +0 -55
  84. {jaclang-0.7.1.dist-info → jaclang-0.7.5.dist-info}/WHEEL +0 -0
  85. {jaclang-0.7.1.dist-info → jaclang-0.7.5.dist-info}/entry_points.txt +0 -0
@@ -42,7 +42,6 @@ class PyastGenPass(Pass):
42
42
  """Initialize pass."""
43
43
  self.debuginfo: dict[str, list[str]] = {"jac_mods": []}
44
44
  self.already_added: list[str] = []
45
- self.method_sigs: list[ast.FuncSignature | ast.EventSignature] = []
46
45
  self.preamble: list[ast3.AST] = [
47
46
  self.sync(
48
47
  ast3.ImportFrom(
@@ -54,6 +53,13 @@ class PyastGenPass(Pass):
54
53
  )
55
54
  ]
56
55
 
56
+ def enter_node(self, node: ast.AstNode) -> None:
57
+ """Enter node."""
58
+ if node.gen.py_ast:
59
+ self.prune()
60
+ return
61
+ super().enter_node(node)
62
+
57
63
  def exit_node(self, node: ast.AstNode) -> None:
58
64
  """Exit node."""
59
65
  super().exit_node(node)
@@ -325,7 +331,8 @@ class PyastGenPass(Pass):
325
331
  for pbody in node.impl_mod:
326
332
  pre_body = [*pre_body, *pbody.body]
327
333
  pre_body = [*pre_body, *clean_body]
328
- pre_body = [*pre_body, *node.test_mod.body] if node.test_mod else pre_body
334
+ for pbody in node.test_mod:
335
+ pre_body = [*pre_body, *pbody.body]
329
336
  body = (
330
337
  [
331
338
  self.sync(ast3.Expr(value=node.doc.gen.py_ast[0]), jac_node=node.doc),
@@ -385,7 +392,7 @@ class PyastGenPass(Pass):
385
392
  args=self.sync(
386
393
  ast3.arguments(
387
394
  posonlyargs=[],
388
- args=[self.sync(ast3.arg(arg="check", annotation=None))],
395
+ args=[self.sync(ast3.arg(arg="_jac_check", annotation=None))],
389
396
  kwonlyargs=[],
390
397
  vararg=None,
391
398
  kwargs=None,
@@ -544,7 +551,7 @@ class PyastGenPass(Pass):
544
551
  arg="mod_bundle",
545
552
  value=self.sync(
546
553
  ast3.Name(
547
- id="__jac_mod_bundle__",
554
+ id="__name__",
548
555
  ctx=ast3.Load(),
549
556
  )
550
557
  ),
@@ -670,15 +677,7 @@ class PyastGenPass(Pass):
670
677
  doc: Optional[String],
671
678
  decorators: Optional[SubNodeList[ExprType]],
672
679
  """
673
- # Record all signatures that are part of methods
674
- for i in (
675
- node.body.body.items
676
- if isinstance(node.body, ast.ArchDef)
677
- else node.body.items if node.body else []
678
- ):
679
- if isinstance(i, ast.Ability) and i.signature:
680
- self.method_sigs.append(i.signature)
681
- if isinstance(node.body, ast.ArchDef):
680
+ if isinstance(node.body, ast.AstImplOnlyNode):
682
681
  self.traverse(node.body)
683
682
 
684
683
  def exit_architype(self, node: ast.Architype) -> None:
@@ -760,6 +759,18 @@ class PyastGenPass(Pass):
760
759
  )
761
760
  )
762
761
  base_classes = node.base_classes.gen.py_ast if node.base_classes else []
762
+ if node.arch_type.name != Tok.KW_CLASS:
763
+ base_classes.append(
764
+ self.sync(
765
+ ast3.Attribute(
766
+ value=self.sync(
767
+ ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
768
+ ),
769
+ attr=node.arch_type.value.capitalize(),
770
+ ctx=ast3.Load(),
771
+ )
772
+ )
773
+ )
763
774
  if node.is_abstract:
764
775
  self.needs_jac_feature()
765
776
  base_classes.append(
@@ -854,7 +865,7 @@ class PyastGenPass(Pass):
854
865
  doc: Optional[String],
855
866
  decorators: Optional[SubNodeList[ExprType]],
856
867
  """
857
- if isinstance(node.body, ast.EnumDef):
868
+ if isinstance(node.body, ast.AstImplOnlyNode):
858
869
  self.traverse(node.body)
859
870
 
860
871
  def exit_enum(self, node: ast.Enum) -> None:
@@ -920,7 +931,7 @@ class PyastGenPass(Pass):
920
931
  doc: Optional[String],
921
932
  decorators: Optional[SubNodeList[ExprType]],
922
933
  """
923
- if isinstance(node.body, ast.AbilityDef):
934
+ if isinstance(node.body, ast.AstImplOnlyNode):
924
935
  self.traverse(node.body)
925
936
 
926
937
  def exit_ability(self, node: ast.Ability) -> None:
@@ -1083,7 +1094,7 @@ class PyastGenPass(Pass):
1083
1094
  value=(
1084
1095
  node.signature.semstr.lit_value
1085
1096
  if node.signature.semstr
1086
- else None
1097
+ else ""
1087
1098
  )
1088
1099
  )
1089
1100
  )
@@ -1096,7 +1107,7 @@ class PyastGenPass(Pass):
1096
1107
  action = (
1097
1108
  node.semstr.gen.py_ast[0]
1098
1109
  if node.semstr
1099
- else self.sync(ast3.Constant(value=None))
1110
+ else self.sync(ast3.Constant(value=node.name_ref.sym_name))
1100
1111
  )
1101
1112
  return [
1102
1113
  self.sync(
@@ -1325,7 +1336,7 @@ class PyastGenPass(Pass):
1325
1336
  """
1326
1337
  params = (
1327
1338
  [self.sync(ast3.arg(arg="self", annotation=None))]
1328
- if node in self.method_sigs and not node.is_static
1339
+ if node.is_method and not node.is_static
1329
1340
  else []
1330
1341
  )
1331
1342
  vararg = None
@@ -1383,7 +1394,7 @@ class PyastGenPass(Pass):
1383
1394
  posonlyargs=[],
1384
1395
  args=(
1385
1396
  [self.sync(ast3.arg(arg="self", annotation=None)), here]
1386
- if node in self.method_sigs
1397
+ if node.is_method
1387
1398
  else [here]
1388
1399
  ),
1389
1400
  kwonlyargs=[],
@@ -1401,27 +1412,19 @@ class PyastGenPass(Pass):
1401
1412
  name_ref: NameType,
1402
1413
  arch: Token,
1403
1414
  """
1404
- if node.arch.name == Tok.TYPE_OP:
1415
+ if node.arch_type.name == Tok.TYPE_OP:
1405
1416
  if (
1406
- isinstance(node.name_ref, ast.SpecialVarRef)
1407
- and node.name_ref.var.name == Tok.KW_ROOT
1417
+ isinstance(node.arch_name, ast.SpecialVarRef)
1418
+ and node.arch_name.orig.name == Tok.KW_ROOT
1408
1419
  ):
1409
1420
  node.gen.py_ast = [
1410
1421
  self.sync(
1411
- ast3.Call(
1412
- func=self.sync(
1413
- ast3.Attribute(
1414
- value=self.sync(
1415
- ast3.Name(
1416
- id=Con.JAC_FEATURE.value, ctx=ast3.Load()
1417
- )
1418
- ),
1419
- attr="get_root_type",
1420
- ctx=ast3.Load(),
1421
- )
1422
+ ast3.Attribute(
1423
+ value=self.sync(
1424
+ ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
1422
1425
  ),
1423
- args=[],
1424
- keywords=[],
1426
+ attr="RootType",
1427
+ ctx=ast3.Load(),
1425
1428
  )
1426
1429
  )
1427
1430
  ]
@@ -1431,13 +1434,13 @@ class PyastGenPass(Pass):
1431
1434
  self.sync(
1432
1435
  ast3.Attribute(
1433
1436
  value=self.sync(ast3.Name(id="_jac_typ", ctx=ast3.Load())),
1434
- attr=node.name_ref.sym_name,
1437
+ attr=node.arch_name.sym_name,
1435
1438
  ctx=ast3.Load(),
1436
1439
  )
1437
1440
  )
1438
1441
  ]
1439
1442
  else:
1440
- node.gen.py_ast = node.name_ref.gen.py_ast
1443
+ node.gen.py_ast = node.arch_name.gen.py_ast
1441
1444
 
1442
1445
  def exit_arch_ref_chain(self, node: ast.ArchRefChain) -> None:
1443
1446
  """Sub objects.
@@ -1455,7 +1458,7 @@ class PyastGenPass(Pass):
1455
1458
  attr = self.sync(
1456
1459
  ast3.Attribute(
1457
1460
  value=make_attr_chain(arch[:-1]),
1458
- attr=cur.name_ref.sym_name,
1461
+ attr=cur.arch_name.sym_name,
1459
1462
  ctx=ast3.Load(),
1460
1463
  ),
1461
1464
  jac_node=cur,
@@ -1873,6 +1876,38 @@ class PyastGenPass(Pass):
1873
1876
  )
1874
1877
  ]
1875
1878
 
1879
+ def exit_check_stmt(self, node: ast.CheckStmt) -> None:
1880
+ """Sub objects.
1881
+
1882
+ target: ExprType,
1883
+ """
1884
+ if isinstance(node.target, ast.FuncCall) and isinstance(
1885
+ node.target.gen.py_ast[0], ast3.Call
1886
+ ):
1887
+ func = node.target.target.gen.py_ast[0]
1888
+ if isinstance(func, ast3.Name):
1889
+ new_func: ast3.expr = self.sync(
1890
+ ast3.Attribute(
1891
+ value=self.sync(ast3.Name(id="_jac_check", ctx=ast3.Load())),
1892
+ attr=func.id,
1893
+ ctx=ast3.Load(),
1894
+ )
1895
+ )
1896
+ node.target.gen.py_ast[0].func = new_func
1897
+ node.gen.py_ast = [
1898
+ self.sync(
1899
+ ast3.Expr(
1900
+ value=node.target.gen.py_ast[0],
1901
+ )
1902
+ )
1903
+ ]
1904
+ return
1905
+ self.error(
1906
+ "For now, check statements must be function calls "
1907
+ "in the style of assertTrue(), assertEqual(), etc.",
1908
+ node,
1909
+ )
1910
+
1876
1911
  def exit_ctrl_stmt(self, node: ast.CtrlStmt) -> None:
1877
1912
  """Sub objects.
1878
1913
 
@@ -3082,14 +3117,42 @@ class PyastGenPass(Pass):
3082
3117
 
3083
3118
  var: Token,
3084
3119
  """
3085
- try:
3086
- var_ast_expr = ast3.parse(node.sym_name).body[0]
3087
- if not isinstance(var_ast_expr, ast3.Expr):
3088
- raise self.ice("Invalid special var ref for pyast generation")
3089
- var_ast = var_ast_expr.value
3090
- except Exception:
3091
- raise self.ice("Invalid special var ref for pyast generation")
3092
- node.gen.py_ast = [self.sync(var_ast, deep=True)]
3120
+ if node.name == Tok.KW_SUPER:
3121
+ node.gen.py_ast = [
3122
+ self.sync(
3123
+ ast3.Call(
3124
+ func=self.sync(ast3.Name(id="super", ctx=node.py_ctx_func())),
3125
+ args=[],
3126
+ keywords=[],
3127
+ )
3128
+ )
3129
+ ]
3130
+ elif node.name == Tok.KW_ROOT:
3131
+ node.gen.py_ast = [
3132
+ self.sync(
3133
+ ast3.Call(
3134
+ func=self.sync(
3135
+ ast3.Attribute(
3136
+ value=self.sync(
3137
+ ast3.Name(
3138
+ id=Con.JAC_FEATURE.value,
3139
+ ctx=ast3.Load(),
3140
+ )
3141
+ ),
3142
+ attr="get_root",
3143
+ ctx=ast3.Load(),
3144
+ )
3145
+ ),
3146
+ args=[],
3147
+ keywords=[],
3148
+ )
3149
+ )
3150
+ ]
3151
+
3152
+ else:
3153
+ node.gen.py_ast = [
3154
+ self.sync(ast3.Name(id=node.sym_name, ctx=node.py_ctx_func()))
3155
+ ]
3093
3156
 
3094
3157
  def exit_edge_ref_trailer(self, node: ast.EdgeRefTrailer) -> None:
3095
3158
  """Sub objects.
@@ -3569,7 +3632,7 @@ class PyastGenPass(Pass):
3569
3632
  [
3570
3633
  x.key.sym_name
3571
3634
  for x in node.kw_patterns.items
3572
- if isinstance(x.key, ast.NameSpec)
3635
+ if isinstance(x.key, ast.NameAtom)
3573
3636
  ]
3574
3637
  if node.kw_patterns
3575
3638
  else []
@@ -127,7 +127,6 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
127
127
  is_imported=False,
128
128
  kid=valid,
129
129
  )
130
- ret.gen.py_ast = [node]
131
130
  return self.nu(ret)
132
131
 
133
132
  def proc_function_def(
@@ -151,6 +150,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
151
150
  node.name if node.name != "root" else "root_"
152
151
  ), # root is a reserved keyword
153
152
  line=node.lineno,
153
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
154
154
  col_start=node.col_offset,
155
155
  col_end=node.col_offset + len(node.name),
156
156
  pos_start=0,
@@ -209,6 +209,8 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
209
209
  kid = ([doc] if doc else []) + (
210
210
  [name, sig, valid_body] if sig else [name, valid_body]
211
211
  )
212
+ if not sig:
213
+ raise self.ice("Function signature not found")
212
214
  ret = ast.Ability(
213
215
  name_ref=name,
214
216
  is_async=False,
@@ -261,6 +263,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
261
263
  name=Tok.NAME,
262
264
  value=node.name,
263
265
  line=node.lineno,
266
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
264
267
  col_start=node.col_offset,
265
268
  col_end=node.col_offset + len(node.name),
266
269
  pos_start=0,
@@ -271,6 +274,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
271
274
  name=Tok.KW_CLASS,
272
275
  value="class",
273
276
  line=node.lineno,
277
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
274
278
  col_start=0,
275
279
  col_end=0,
276
280
  pos_start=0,
@@ -283,17 +287,18 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
283
287
  and isinstance(body_stmt.name_ref, ast.Name)
284
288
  and body_stmt.name_ref.value == "__init__"
285
289
  ):
286
- tok = ast.Token(
290
+ tok = ast.Name(
287
291
  file_path=self.mod_path,
288
292
  name=Tok.KW_INIT,
289
293
  value="init",
290
294
  line=node.lineno,
295
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
291
296
  col_start=node.col_offset,
292
297
  col_end=node.col_offset + len("init"),
293
298
  pos_start=0,
294
299
  pos_end=0,
295
300
  )
296
- body_stmt.name_ref = ast.SpecialVarRef(var=tok, kid=[tok])
301
+ body_stmt.name_ref = ast.SpecialVarRef(var=tok)
297
302
  if (
298
303
  isinstance(body_stmt, ast.Ability)
299
304
  and body_stmt.signature
@@ -372,17 +377,18 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
372
377
  converted_stmt.expr, ast.String
373
378
  ):
374
379
  continue
375
- tok = ast.Token(
380
+ pintok = ast.Token(
376
381
  file_path=self.mod_path,
377
382
  name=Tok.PYNLINE,
378
383
  value=py_ast.unparse(class_body_stmt),
379
384
  line=node.lineno,
385
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
380
386
  col_start=node.col_offset,
381
387
  col_end=node.col_offset + len(py_ast.unparse(class_body_stmt)),
382
388
  pos_start=0,
383
389
  pos_end=0,
384
390
  )
385
- valid_enum_body.append(ast.PyInlineCode(code=tok, kid=[tok]))
391
+ valid_enum_body.append(ast.PyInlineCode(code=pintok, kid=[pintok]))
386
392
 
387
393
  valid_enum_body2: list[ast.EnumBlockStmt] = [
388
394
  i for i in valid_enum_body if isinstance(i, ast.EnumBlockStmt)
@@ -902,17 +908,18 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
902
908
  and isinstance(value.target, ast.Name)
903
909
  and value.target.value == "super"
904
910
  ):
905
- tok = ast.Token(
911
+ tok = ast.Name(
906
912
  file_path=self.mod_path,
907
913
  name=Tok.KW_SUPER,
908
914
  value="super",
909
915
  line=node.lineno,
916
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
910
917
  col_start=node.col_offset,
911
918
  col_end=node.col_offset + len("super"),
912
919
  pos_start=0,
913
920
  pos_end=0,
914
921
  )
915
- value = ast.SpecialVarRef(var=tok, kid=[tok])
922
+ value = ast.SpecialVarRef(var=tok)
916
923
  # exit()
917
924
  attribute = ast.Name(
918
925
  file_path=self.mod_path,
@@ -923,6 +930,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
923
930
  else "init" if node.attr == "__init__" else node.attr
924
931
  ),
925
932
  line=node.lineno,
933
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
926
934
  col_start=node.col_offset,
927
935
  col_end=node.col_offset + len(node.attr),
928
936
  pos_start=0,
@@ -1029,6 +1037,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1029
1037
  name=Tok.KW_BREAK,
1030
1038
  value="break",
1031
1039
  line=0,
1040
+ end_line=0,
1032
1041
  col_start=0,
1033
1042
  col_end=0,
1034
1043
  pos_start=0,
@@ -1143,6 +1152,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1143
1152
  else str(node.value)
1144
1153
  ),
1145
1154
  line=node.lineno,
1155
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1146
1156
  col_start=node.col_offset,
1147
1157
  col_end=node.col_offset + len(str(node.value)),
1148
1158
  pos_start=0,
@@ -1154,6 +1164,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1154
1164
  name=Tok.ELLIPSIS,
1155
1165
  value="...",
1156
1166
  line=node.lineno,
1167
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1157
1168
  col_start=node.col_offset,
1158
1169
  col_end=node.col_offset + 3,
1159
1170
  pos_start=0,
@@ -1169,6 +1180,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1169
1180
  name=Tok.KW_CONTINUE,
1170
1181
  value="continue",
1171
1182
  line=0,
1183
+ end_line=0,
1172
1184
  col_start=0,
1173
1185
  col_end=0,
1174
1186
  pos_start=0,
@@ -1245,6 +1257,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1245
1257
  name=Tok.NAME,
1246
1258
  value="Exception",
1247
1259
  line=node.lineno,
1260
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1248
1261
  col_start=node.col_offset,
1249
1262
  col_end=node.col_offset + 9,
1250
1263
  pos_start=0,
@@ -1255,6 +1268,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1255
1268
  name=Tok.NAME,
1256
1269
  value="e",
1257
1270
  line=node.lineno,
1271
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1258
1272
  col_start=node.col_offset,
1259
1273
  col_end=node.col_offset + 1,
1260
1274
  pos_start=0,
@@ -1266,6 +1280,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1266
1280
  # name=Tok.NAME,
1267
1281
  # value=no,
1268
1282
  # line=node.lineno,
1283
+ # end_line = (node.end_lineno if node.end_lineno else node.lineno,)
1269
1284
  # col_start=node.col_offset,
1270
1285
  # col_end=node.col_offset + 9,
1271
1286
  # pos_start=0,
@@ -1277,6 +1292,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1277
1292
  name=Tok.NAME,
1278
1293
  value=node.name,
1279
1294
  line=node.lineno,
1295
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1280
1296
  col_start=node.col_offset,
1281
1297
  col_end=node.col_offset + len(node.name),
1282
1298
  pos_start=0,
@@ -1368,7 +1384,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1368
1384
  class Global(stmt):
1369
1385
  names: list[_Identifier]
1370
1386
  """
1371
- names: list[ast.NameSpec] = []
1387
+ names: list[ast.NameAtom] = []
1372
1388
  for id in node.names:
1373
1389
  names.append(
1374
1390
  ast.Name(
@@ -1376,13 +1392,14 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1376
1392
  name=Tok.NAME,
1377
1393
  value=id,
1378
1394
  line=node.lineno,
1395
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1379
1396
  col_start=node.col_offset,
1380
1397
  col_end=node.col_offset + len(id),
1381
1398
  pos_start=0,
1382
1399
  pos_end=0,
1383
1400
  )
1384
1401
  )
1385
- target = ast.SubNodeList[ast.NameSpec](items=names, delim=Tok.COMMA, kid=names)
1402
+ target = ast.SubNodeList[ast.NameAtom](items=names, delim=Tok.COMMA, kid=names)
1386
1403
  return ast.GlobalStmt(target=target, kid=[target])
1387
1404
 
1388
1405
  def proc_if_exp(self, node: py_ast.IfExp) -> ast.IfElseExpr:
@@ -1438,6 +1455,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1438
1455
  name=Tok.NAME,
1439
1456
  value="py",
1440
1457
  line=node.lineno,
1458
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1441
1459
  col_start=node.col_offset,
1442
1460
  col_end=0,
1443
1461
  pos_start=0,
@@ -1467,6 +1485,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1467
1485
  name=Tok.NAME,
1468
1486
  value="py",
1469
1487
  line=node.lineno,
1488
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1470
1489
  col_start=node.col_offset,
1471
1490
  col_end=0,
1472
1491
  pos_start=0,
@@ -1481,6 +1500,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1481
1500
  name=Tok.NAME,
1482
1501
  value=i,
1483
1502
  line=node.lineno,
1503
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1484
1504
  col_start=0,
1485
1505
  col_end=0,
1486
1506
  pos_start=0,
@@ -1642,6 +1662,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1642
1662
  name=Tok.NAME,
1643
1663
  value=node.name if node.name else "_",
1644
1664
  line=node.lineno,
1665
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1645
1666
  col_start=node.col_offset,
1646
1667
  col_end=(
1647
1668
  (node.col_offset + len(node.name))
@@ -1695,6 +1716,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1695
1716
  name=Tok.NAME,
1696
1717
  value=kwd_attrs,
1697
1718
  line=node.lineno,
1719
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1698
1720
  col_start=node.col_offset,
1699
1721
  col_end=node.col_offset + len(kwd_attrs),
1700
1722
  pos_start=0,
@@ -1719,7 +1741,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1719
1741
  kid.append(kw_patterns)
1720
1742
  else:
1721
1743
  kw_patterns = None
1722
- if isinstance(cls, (ast.NameSpec, ast.AtomTrailer)):
1744
+ if isinstance(cls, (ast.NameAtom, ast.AtomTrailer)):
1723
1745
  return ast.MatchArch(
1724
1746
  name=cls, arg_patterns=patterns_sub, kw_patterns=kw_patterns, kid=kid
1725
1747
  )
@@ -1737,7 +1759,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1737
1759
  values: list[ast.MatchKVPair | ast.MatchStar] = []
1738
1760
  keys = [self.convert(i) for i in node.keys]
1739
1761
  valid_keys = [
1740
- i for i in keys if isinstance(i, (ast.MatchPattern, ast.NameSpec))
1762
+ i for i in keys if isinstance(i, (ast.MatchPattern, ast.NameAtom))
1741
1763
  ]
1742
1764
  patterns = [self.convert(i) for i in node.patterns]
1743
1765
  valid_patterns = [i for i in patterns if isinstance(i, ast.MatchPattern)]
@@ -1754,6 +1776,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1754
1776
  name=Tok.NAME,
1755
1777
  value=node.rest,
1756
1778
  line=node.lineno,
1779
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1757
1780
  col_start=node.col_offset,
1758
1781
  col_end=node.col_offset + len(node.rest),
1759
1782
  pos_start=0,
@@ -1798,6 +1821,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1798
1821
  name=type,
1799
1822
  value=str(node.value),
1800
1823
  line=node.lineno,
1824
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1801
1825
  col_start=node.col_offset,
1802
1826
  col_end=node.col_offset + len(str(node.value)),
1803
1827
  pos_start=0,
@@ -1819,6 +1843,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1819
1843
  name=Tok.NAME,
1820
1844
  value=node.name if node.name else "_",
1821
1845
  line=node.lineno,
1846
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1822
1847
  col_start=node.col_offset,
1823
1848
  col_end=node.col_offset + len(node.name if node.name else "_"),
1824
1849
  pos_start=0,
@@ -1852,6 +1877,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1852
1877
  name=Tok.NAME,
1853
1878
  value=node.id if node.id != "root" else "root_", # reserved word
1854
1879
  line=node.lineno,
1880
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1855
1881
  col_start=node.col_offset,
1856
1882
  col_end=node.col_offset + len(node.id),
1857
1883
  pos_start=0,
@@ -1884,7 +1910,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1884
1910
  class Nonlocal(stmt):
1885
1911
  names: list[_Identifier]
1886
1912
  """
1887
- names: list[ast.NameSpec] = []
1913
+ names: list[ast.NameAtom] = []
1888
1914
  for name in node.names:
1889
1915
  names.append(
1890
1916
  ast.Name(
@@ -1892,13 +1918,14 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1892
1918
  name=Tok.NAME,
1893
1919
  value=name if name != "root" else "root_",
1894
1920
  line=node.lineno,
1921
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
1895
1922
  col_start=node.col_offset,
1896
1923
  col_end=node.col_offset + len(name),
1897
1924
  pos_start=0,
1898
1925
  pos_end=0,
1899
1926
  )
1900
1927
  )
1901
- target = ast.SubNodeList[ast.NameSpec](items=names, delim=Tok.COMMA, kid=names)
1928
+ target = ast.SubNodeList[ast.NameAtom](items=names, delim=Tok.COMMA, kid=names)
1902
1929
  return ast.NonLocalStmt(target=target, kid=names)
1903
1930
 
1904
1931
  def proc_pass(self, node: py_ast.Pass) -> ast.Semi:
@@ -1908,6 +1935,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
1908
1935
  name=Tok.SEMI,
1909
1936
  value=";",
1910
1937
  line=0,
1938
+ end_line=0,
1911
1939
  col_start=0,
1912
1940
  col_end=0,
1913
1941
  pos_start=0,
@@ -2175,6 +2203,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2175
2203
  name=Tok.NAME,
2176
2204
  value=node.name,
2177
2205
  line=node.lineno,
2206
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
2178
2207
  col_start=node.col_offset,
2179
2208
  col_end=node.col_offset + len(node.name),
2180
2209
  pos_start=0,
@@ -2186,6 +2215,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2186
2215
  name=Tok.NAME,
2187
2216
  value=node.asname,
2188
2217
  line=node.lineno,
2218
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
2189
2219
  col_start=node.col_offset,
2190
2220
  col_end=node.col_offset + len(node.asname),
2191
2221
  pos_start=0,
@@ -2210,6 +2240,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2210
2240
  name=Tok.NAME,
2211
2241
  value=node.arg if node.arg != "root" else "root_", # reserved word
2212
2242
  line=node.lineno,
2243
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
2213
2244
  col_start=node.col_offset,
2214
2245
  col_end=node.col_offset + len(node.arg),
2215
2246
  pos_start=0,
@@ -2223,6 +2254,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2223
2254
  name=Tok.NAME,
2224
2255
  value="Any",
2225
2256
  line=node.lineno,
2257
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
2226
2258
  col_start=node.col_offset,
2227
2259
  col_end=node.col_offset + 3,
2228
2260
  pos_start=0,
@@ -2256,6 +2288,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2256
2288
  name=Tok.STAR_MUL,
2257
2289
  value="*",
2258
2290
  line=vararg.loc.first_line,
2291
+ end_line=vararg.loc.last_line,
2259
2292
  col_start=vararg.loc.col_start,
2260
2293
  col_end=vararg.loc.col_end,
2261
2294
  pos_start=0,
@@ -2281,6 +2314,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2281
2314
  name=Tok.STAR_POW,
2282
2315
  value="**",
2283
2316
  line=kwarg.loc.first_line,
2317
+ end_line=kwarg.loc.last_line,
2284
2318
  col_start=kwarg.loc.col_start,
2285
2319
  col_end=kwarg.loc.col_end,
2286
2320
  pos_start=0,
@@ -2326,6 +2360,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2326
2360
  name=tok,
2327
2361
  value=value,
2328
2362
  line=0,
2363
+ end_line=0,
2329
2364
  col_start=0,
2330
2365
  col_end=0,
2331
2366
  pos_start=0,
@@ -2490,6 +2525,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2490
2525
  name=Tok.NAME,
2491
2526
  value=node.arg if node.arg else "_",
2492
2527
  line=node.lineno,
2528
+ end_line=node.end_lineno if node.end_lineno else node.lineno,
2493
2529
  col_start=node.col_offset,
2494
2530
  col_end=node.col_offset + len(node.arg if node.arg else "_"),
2495
2531
  pos_start=0,