jaclang 0.4.7__py3-none-any.whl → 0.5.0__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 (152) hide show
  1. jaclang/__init__.py +5 -2
  2. jaclang/cli/cli.py +56 -8
  3. jaclang/cli/cmdreg.py +16 -9
  4. jaclang/compiler/__jac_gen__/jac_parser.py +11 -15
  5. jaclang/compiler/absyntree.py +53 -19
  6. jaclang/compiler/codeloc.py +3 -1
  7. jaclang/compiler/{transpiler.py → compile.py} +3 -2
  8. jaclang/compiler/constant.py +4 -0
  9. jaclang/compiler/parser.py +156 -108
  10. jaclang/compiler/passes/ir_pass.py +1 -0
  11. jaclang/compiler/passes/main/__init__.py +2 -1
  12. jaclang/compiler/passes/main/def_impl_match_pass.py +1 -0
  13. jaclang/compiler/passes/main/def_use_pass.py +1 -0
  14. jaclang/compiler/passes/main/import_pass.py +18 -18
  15. jaclang/compiler/passes/main/pyast_gen_pass.py +1228 -853
  16. jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
  17. jaclang/compiler/passes/main/pybc_gen_pass.py +46 -0
  18. jaclang/compiler/passes/main/pyout_pass.py +6 -7
  19. jaclang/compiler/passes/main/schedules.py +5 -9
  20. jaclang/compiler/passes/main/sub_node_tab_pass.py +1 -0
  21. jaclang/compiler/passes/main/sym_tab_build_pass.py +21 -9
  22. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +2 -1
  23. jaclang/compiler/passes/main/tests/test_def_use_pass.py +2 -1
  24. jaclang/compiler/passes/main/tests/test_import_pass.py +2 -1
  25. jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +1 -0
  26. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +15 -38
  27. jaclang/compiler/passes/main/tests/test_pybc_gen_pass.py +25 -0
  28. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -1
  29. jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +2 -1
  30. jaclang/compiler/passes/main/tests/test_type_check_pass.py +17 -1
  31. jaclang/compiler/passes/main/type_check_pass.py +9 -6
  32. jaclang/compiler/passes/tool/__init__.py +1 -0
  33. jaclang/compiler/passes/tool/ast_printer_pass.py +1 -0
  34. jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -1
  35. jaclang/compiler/passes/tool/jac_formatter_pass.py +69 -32
  36. jaclang/compiler/passes/tool/schedules.py +1 -0
  37. jaclang/compiler/passes/tool/sym_tab_printer_pass.py +1 -0
  38. jaclang/compiler/passes/tool/tests/test_ast_print_pass.py +2 -1
  39. jaclang/compiler/passes/tool/tests/test_fuse_comments_pass.py +1 -0
  40. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -3
  41. jaclang/compiler/passes/tool/tests/test_symtab_print_pass.py +2 -1
  42. jaclang/compiler/passes/transform.py +1 -0
  43. jaclang/compiler/passes/utils/mypy_ast_build.py +203 -17
  44. jaclang/compiler/symtable.py +1 -0
  45. jaclang/compiler/tests/test_importer.py +3 -2
  46. jaclang/compiler/tests/test_parser.py +1 -0
  47. jaclang/compiler/tests/test_workspace.py +1 -0
  48. jaclang/compiler/workspace.py +18 -5
  49. jaclang/core/construct.py +9 -32
  50. jaclang/{compiler → core}/importer.py +95 -85
  51. jaclang/core/utils.py +17 -12
  52. jaclang/plugin/__init__.py +1 -0
  53. jaclang/plugin/default.py +145 -43
  54. jaclang/plugin/feature.py +65 -19
  55. jaclang/plugin/spec.py +56 -34
  56. jaclang/plugin/tests/test_features.py +9 -0
  57. jaclang/utils/helpers.py +1 -0
  58. jaclang/utils/lang_tools.py +13 -19
  59. jaclang/utils/tests/test_lang_tools.py +2 -1
  60. jaclang/utils/treeprinter.py +2 -1
  61. jaclang/vendor/lark/common.py +3 -1
  62. jaclang/vendor/lark/lexer.py +6 -12
  63. jaclang/vendor/lark/parsers/lalr_parser.py +1 -0
  64. jaclang/vendor/mypy/applytype.py +2 -1
  65. jaclang/vendor/mypy/binder.py +1 -1
  66. jaclang/vendor/mypy/build.py +7 -9
  67. jaclang/vendor/mypy/checker.py +57 -33
  68. jaclang/vendor/mypy/checkexpr.py +42 -29
  69. jaclang/vendor/mypy/checkmember.py +13 -1
  70. jaclang/vendor/mypy/checkpattern.py +1 -1
  71. jaclang/vendor/mypy/checkstrformat.py +2 -4
  72. jaclang/vendor/mypy/constraints.py +10 -5
  73. jaclang/vendor/mypy/dmypy_server.py +3 -3
  74. jaclang/vendor/mypy/dmypy_util.py +62 -3
  75. jaclang/vendor/mypy/errors.py +1 -1
  76. jaclang/vendor/mypy/evalexpr.py +1 -0
  77. jaclang/vendor/mypy/expandtype.py +29 -29
  78. jaclang/vendor/mypy/fastparse.py +51 -31
  79. jaclang/vendor/mypy/inspections.py +5 -3
  80. jaclang/vendor/mypy/join.py +4 -4
  81. jaclang/vendor/mypy/main.py +6 -6
  82. jaclang/vendor/mypy/message_registry.py +1 -2
  83. jaclang/vendor/mypy/messages.py +31 -23
  84. jaclang/vendor/mypy/metastore.py +1 -2
  85. jaclang/vendor/mypy/modulefinder.py +2 -22
  86. jaclang/vendor/mypy/nodes.py +22 -20
  87. jaclang/vendor/mypy/options.py +4 -0
  88. jaclang/vendor/mypy/parse.py +6 -2
  89. jaclang/vendor/mypy/patterns.py +6 -6
  90. jaclang/vendor/mypy/plugin.py +3 -1
  91. jaclang/vendor/mypy/plugins/attrs.py +52 -10
  92. jaclang/vendor/mypy/plugins/common.py +2 -1
  93. jaclang/vendor/mypy/plugins/enums.py +3 -2
  94. jaclang/vendor/mypy/plugins/functools.py +1 -0
  95. jaclang/vendor/mypy/renaming.py +1 -1
  96. jaclang/vendor/mypy/report.py +15 -15
  97. jaclang/vendor/mypy/semanal.py +22 -13
  98. jaclang/vendor/mypy/semanal_enum.py +1 -1
  99. jaclang/vendor/mypy/semanal_namedtuple.py +1 -2
  100. jaclang/vendor/mypy/semanal_shared.py +3 -6
  101. jaclang/vendor/mypy/semanal_typeddict.py +16 -5
  102. jaclang/vendor/mypy/server/astdiff.py +15 -9
  103. jaclang/vendor/mypy/server/astmerge.py +5 -5
  104. jaclang/vendor/mypy/stats.py +0 -5
  105. jaclang/vendor/mypy/stubdoc.py +1 -1
  106. jaclang/vendor/mypy/stubgen.py +12 -21
  107. jaclang/vendor/mypy/stubgenc.py +16 -8
  108. jaclang/vendor/mypy/stubtest.py +57 -48
  109. jaclang/vendor/mypy/stubutil.py +28 -15
  110. jaclang/vendor/mypy/subtypes.py +4 -4
  111. jaclang/vendor/mypy/test/helpers.py +2 -2
  112. jaclang/vendor/mypy/test/meta/test_parse_data.py +1 -0
  113. jaclang/vendor/mypy/test/meta/test_update_data.py +1 -0
  114. jaclang/vendor/mypy/test/testargs.py +1 -0
  115. jaclang/vendor/mypy/test/testcheck.py +4 -1
  116. jaclang/vendor/mypy/test/testconstraints.py +25 -7
  117. jaclang/vendor/mypy/test/testerrorstream.py +1 -0
  118. jaclang/vendor/mypy/test/testformatter.py +2 -2
  119. jaclang/vendor/mypy/test/testparse.py +6 -4
  120. jaclang/vendor/mypy/test/testpythoneval.py +1 -0
  121. jaclang/vendor/mypy/test/testreports.py +1 -0
  122. jaclang/vendor/mypy/test/teststubgen.py +1 -2
  123. jaclang/vendor/mypy/test/teststubtest.py +98 -4
  124. jaclang/vendor/mypy/test/testtypes.py +1 -1
  125. jaclang/vendor/mypy/test/testutil.py +22 -0
  126. jaclang/vendor/mypy/typeanal.py +302 -158
  127. jaclang/vendor/mypy/typeops.py +22 -13
  128. jaclang/vendor/mypy/types.py +33 -34
  129. jaclang/vendor/mypy/typestate.py +2 -2
  130. jaclang/vendor/mypy/util.py +7 -6
  131. jaclang/vendor/mypy/version.py +1 -1
  132. jaclang/vendor/mypyc/analysis/ircheck.py +1 -0
  133. jaclang/vendor/mypyc/codegen/emitfunc.py +5 -3
  134. jaclang/vendor/mypyc/codegen/emitmodule.py +12 -12
  135. jaclang/vendor/mypyc/codegen/emitwrapper.py +2 -2
  136. jaclang/vendor/mypyc/ir/class_ir.py +10 -6
  137. jaclang/vendor/mypyc/irbuild/builder.py +3 -4
  138. jaclang/vendor/mypyc/irbuild/function.py +5 -3
  139. jaclang/vendor/mypyc/irbuild/nonlocalcontrol.py +1 -2
  140. jaclang/vendor/mypyc/irbuild/prepare.py +6 -6
  141. jaclang/vendor/mypyc/primitives/registry.py +15 -5
  142. jaclang/vendor/mypyc/test/test_run.py +1 -2
  143. jaclang/vendor/mypyc/transform/uninit.py +3 -3
  144. jaclang/vendor/pluggy/_callers.py +1 -0
  145. jaclang/vendor/pluggy/_hooks.py +6 -10
  146. jaclang/vendor/pluggy/_result.py +1 -0
  147. jaclang/vendor/pluggy/_tracing.py +1 -0
  148. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/METADATA +1 -1
  149. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/RECORD +152 -150
  150. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/WHEEL +0 -0
  151. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/entry_points.txt +0 -0
  152. {jaclang-0.4.7.dist-info → jaclang-0.5.0.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  This is a pass for formatting Jac code.
4
4
  """
5
+
5
6
  import re
6
7
 
7
8
  import jaclang.compiler.absyntree as ast
@@ -196,28 +197,35 @@ class JacFormatPass(Pass):
196
197
  ):
197
198
  self.emit_ln(node, "")
198
199
  self.indent_level += 1
199
- if stmt.name == "LBRACE":
200
- if (
201
- isinstance(node.kid[i + 1], ast.CommentToken)
202
- and node.kid[i + 1].is_inline
203
- ):
200
+ if stmt.name == Tok.LBRACE:
201
+ next_kid = node.kid[i + 1]
202
+ if isinstance(next_kid, ast.CommentToken) and next_kid.is_inline:
204
203
  self.emit(node, f" {stmt.value}")
205
204
  else:
206
205
  self.emit(node, f" {stmt.value}")
207
- elif stmt.name == "RBRACE":
206
+ elif stmt.name == Tok.RBRACE:
208
207
  if self.indent_level > 0:
209
208
  self.indent_level -= 1
210
- if stmt.parent.gen.jac.strip() == "{":
209
+ if stmt.parent and stmt.parent.gen.jac.strip() == "{":
211
210
  self.emit_ln(node, stmt.gen.jac.strip())
212
- elif isinstance(
213
- stmt.parent.parent,
214
- (ast.ElseIf, ast.IfStmt, ast.IterForStmt, ast.TryStmt),
211
+ elif (
212
+ stmt.parent
213
+ and stmt.parent.parent
214
+ and isinstance(
215
+ stmt.parent.parent,
216
+ (ast.ElseIf, ast.IfStmt, ast.IterForStmt, ast.TryStmt),
217
+ )
215
218
  ):
216
219
  self.emit(node, f"{stmt.value}")
217
220
  else:
218
- if i < (len(node.kid) - 1) and (
219
- isinstance(node.kid[i + 1], ast.CommentToken)
220
- and node.kid[i + 1].is_inline
221
+ next_kid = (
222
+ node.kid[i + 1]
223
+ if i < (len(node.kid) - 1)
224
+ else ast.EmptyToken()
225
+ )
226
+ if (
227
+ isinstance(next_kid, ast.CommentToken)
228
+ and next_kid.is_inline
221
229
  ):
222
230
  self.emit(node, f" {stmt.value}")
223
231
  elif not (node.gen.jac).endswith("\n"):
@@ -229,10 +237,14 @@ class JacFormatPass(Pass):
229
237
  self.emit(node, f"{stmt.value}")
230
238
  elif isinstance(stmt, ast.CommentToken):
231
239
  if stmt.is_inline:
232
- if isinstance(prev_token, ast.Semi) or prev_token.name in [
233
- "LBRACE",
234
- "RBRACE",
235
- ]:
240
+ if isinstance(prev_token, ast.Semi) or (
241
+ isinstance(prev_token, ast.Token)
242
+ and prev_token.name
243
+ in [
244
+ Tok.LBRACE,
245
+ Tok.RBRACE,
246
+ ]
247
+ ):
236
248
  self.indent_level -= 1
237
249
  self.emit(node, f" {stmt.gen.jac}")
238
250
  self.emit_ln(node, "")
@@ -883,9 +895,11 @@ class JacFormatPass(Pass):
883
895
  for i in node.kid:
884
896
  if isinstance(i, ast.SubTag):
885
897
  for j in i.kid:
886
- self.emit(node, j.gen.jac) if not j.gen.jac.startswith(
887
- ":"
888
- ) else self.emit(node, f"{j.gen.jac} ")
898
+ (
899
+ self.emit(node, j.gen.jac)
900
+ if not j.gen.jac.startswith(":")
901
+ else self.emit(node, f"{j.gen.jac} ")
902
+ )
889
903
  else:
890
904
  self.emit(node, f" {i.gen.jac}")
891
905
  if isinstance(node.kid[-1], ast.CommentToken) and not node.gen.jac.endswith(
@@ -1006,7 +1020,11 @@ class JacFormatPass(Pass):
1006
1020
  count_by: ExprType,
1007
1021
  body: CodeBlock,
1008
1022
  """
1009
- if isinstance(node.parent.parent, (ast.Ability)):
1023
+ if (
1024
+ node.parent
1025
+ and node.parent.parent
1026
+ and isinstance(node.parent.parent, (ast.Ability))
1027
+ ):
1010
1028
  self.emit_ln(node, "")
1011
1029
 
1012
1030
  start = True
@@ -1036,7 +1054,11 @@ class JacFormatPass(Pass):
1036
1054
  excepts: Optional[ExceptList],
1037
1055
  finally_body: Optional[FinallyStmt],
1038
1056
  """
1039
- if isinstance(node.parent.parent, (ast.Ability)):
1057
+ if (
1058
+ node.parent
1059
+ and node.parent.parent
1060
+ and isinstance(node.parent.parent, (ast.Ability))
1061
+ ):
1040
1062
  self.emit_ln(node, "")
1041
1063
  start = True
1042
1064
  for i in node.kid:
@@ -1068,7 +1090,11 @@ class JacFormatPass(Pass):
1068
1090
  name: Optional[Token],
1069
1091
  body: CodeBlock,
1070
1092
  """
1071
- if isinstance(node.parent.parent, (ast.Ability)):
1093
+ if (
1094
+ node.parent
1095
+ and node.parent.parent
1096
+ and isinstance(node.parent.parent, (ast.Ability))
1097
+ ):
1072
1098
  self.emit_ln(node, "")
1073
1099
  start = True
1074
1100
  for i in node.kid:
@@ -1108,7 +1134,11 @@ class JacFormatPass(Pass):
1108
1134
  condition: ExprType,
1109
1135
  body: CodeBlock,
1110
1136
  """
1111
- if isinstance(node.parent.parent, (ast.Ability)):
1137
+ if (
1138
+ node.parent
1139
+ and node.parent.parent
1140
+ and isinstance(node.parent.parent, (ast.Ability))
1141
+ ):
1112
1142
  self.emit_ln(node, "")
1113
1143
  start = True
1114
1144
  for i in node.kid:
@@ -1314,7 +1344,7 @@ class JacFormatPass(Pass):
1314
1344
  self.comma_sep_node_list(node.signature.params)
1315
1345
  out += node.signature.params.gen.jac
1316
1346
  if node.signature.return_type:
1317
- out += f" -> {node.signature.return_type.tag.gen.jac}"
1347
+ out += f" -> {node.signature.return_type.gen.jac}"
1318
1348
  self.emit(node, f"with {out} can {node.body.gen.jac}")
1319
1349
 
1320
1350
  def exit_unary_expr(self, node: ast.UnaryExpr) -> None:
@@ -1417,7 +1447,7 @@ class JacFormatPass(Pass):
1417
1447
  self.emit(node, f" {i.gen.jac}")
1418
1448
  else:
1419
1449
  self.emit_ln(node, i.gen.jac)
1420
- elif isinstance(prev_token, ast.Token) and prev_token.name == "LBRACE":
1450
+ elif isinstance(prev_token, ast.Token) and prev_token.name == Tok.LBRACE:
1421
1451
  self.emit(node, f"{i.gen.jac}")
1422
1452
  elif isinstance(i, ast.Semi) or i.gen.jac == ",":
1423
1453
  self.emit(node, i.gen.jac)
@@ -1504,7 +1534,10 @@ class JacFormatPass(Pass):
1504
1534
  key: ExprType,
1505
1535
  value: ExprType,
1506
1536
  """
1507
- self.emit(node, f"{node.key.gen.jac}={node.value.gen.jac}")
1537
+ if node.key:
1538
+ self.emit(node, f"{node.key.gen.jac}={node.value.gen.jac}")
1539
+ else:
1540
+ self.emit(node, f"**{node.value.gen.jac}")
1508
1541
 
1509
1542
  def exit_disconnect_op(self, node: ast.DisconnectOp) -> None:
1510
1543
  """Sub objects.
@@ -1566,7 +1599,7 @@ class JacFormatPass(Pass):
1566
1599
  from_walker: bool = False,
1567
1600
  """
1568
1601
  for i in node.kid:
1569
- if isinstance(i, (ast.EdgeOpRef, ast.ElseStmt)):
1602
+ if isinstance(i, (ast.EdgeOpRef, ast.ElseStmt, ast.SpecialVarRef)):
1570
1603
  self.emit(node, f" {i.gen.jac}")
1571
1604
  else:
1572
1605
  self.emit(node, i.gen.jac)
@@ -1712,7 +1745,7 @@ class JacFormatPass(Pass):
1712
1745
  alias: Optional[Token],
1713
1746
  """
1714
1747
  if node.alias:
1715
- self.emit(node, node.expr.gen.jac + " as " + node.alias.value)
1748
+ self.emit(node, node.expr.gen.jac + " as " + node.alias.gen.jac)
1716
1749
  else:
1717
1750
  self.emit(node, node.expr.gen.jac)
1718
1751
 
@@ -1723,7 +1756,11 @@ class JacFormatPass(Pass):
1723
1756
  collection: ExprType,
1724
1757
  body: SubNodeList[CodeBlockStmt],
1725
1758
  """
1726
- if isinstance(node.parent.parent, (ast.Ability)):
1759
+ if (
1760
+ node.parent
1761
+ and node.parent.parent
1762
+ and isinstance(node.parent.parent, (ast.Ability))
1763
+ ):
1727
1764
  self.indent_level -= 1
1728
1765
  self.emit_ln(node, "")
1729
1766
  self.indent_level += 1
@@ -1831,10 +1868,10 @@ class JacFormatPass(Pass):
1831
1868
  elif isinstance(i, ast.Semi):
1832
1869
  self.emit(node, i.gen.jac)
1833
1870
  elif isinstance(i, ast.Token):
1834
- if i.name == "LBRACE":
1871
+ if i.name == Tok.LBRACE:
1835
1872
  self.emit_ln(node, f" {i.value}")
1836
1873
  self.indent_level += 1
1837
- elif i.name == "RBRACE":
1874
+ elif i.name == Tok.RBRACE:
1838
1875
  self.indent_level -= 1
1839
1876
  self.emit(node, f"{i.value}")
1840
1877
  else:
@@ -1,4 +1,5 @@
1
1
  """Pass schedules."""
2
+
2
3
  from typing import Type
3
4
 
4
5
  from jaclang.compiler.passes.ir_pass import Pass
@@ -1,4 +1,5 @@
1
1
  """Jac Blue pass for drawing AST."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import Optional
@@ -1,8 +1,9 @@
1
1
  """Test pass module."""
2
+
2
3
  import os
3
4
 
5
+ from jaclang.compiler.compile import jac_file_to_pass
4
6
  from jaclang.compiler.passes.tool import AstDotGraphPass, AstPrinterPass
5
- from jaclang.compiler.transpiler import jac_file_to_pass
6
7
  from jaclang.utils.test import TestCase
7
8
 
8
9
 
@@ -1,4 +1,5 @@
1
1
  """Test ast build pass module."""
2
+
2
3
  from jaclang.compiler.passes.tool import JacFormatPass
3
4
 
4
5
 
@@ -1,13 +1,14 @@
1
1
  """Test ast build pass module."""
2
+
2
3
  import ast as ast3
3
4
  from difflib import unified_diff
4
5
 
5
6
  import jaclang.compiler.absyntree as ast
7
+ from jaclang.compiler.compile import jac_file_to_pass, jac_str_to_pass
6
8
  from jaclang.compiler.passes.main import PyastGenPass
7
9
  from jaclang.compiler.passes.main.schedules import py_code_gen as without_format
8
10
  from jaclang.compiler.passes.tool import JacFormatPass
9
11
  from jaclang.compiler.passes.tool.schedules import format_pass
10
- from jaclang.compiler.transpiler import jac_file_to_pass, jac_str_to_pass
11
12
  from jaclang.utils.test import AstSyncTestMixin, TestCaseMicroSuite
12
13
 
13
14
 
@@ -107,8 +108,8 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
107
108
  len(code_gen_pure.ir.source.comments),
108
109
  len(code_gen_jac.ir.source.comments),
109
110
  )
110
- before = ast3.dump(code_gen_pure.ir.gen.py_ast, indent=2)
111
- after = ast3.dump(code_gen_jac.ir.gen.py_ast, indent=2)
111
+ before = ast3.dump(code_gen_pure.ir.gen.py_ast[0], indent=2)
112
+ after = ast3.dump(code_gen_jac.ir.gen.py_ast[0], indent=2)
112
113
  self.assertEqual(
113
114
  len("\n".join(unified_diff(before.splitlines(), after.splitlines()))),
114
115
  0,
@@ -1,12 +1,13 @@
1
1
  """Test pass module."""
2
+
2
3
  import os
3
4
 
5
+ from jaclang.compiler.compile import jac_file_to_pass
4
6
  from jaclang.compiler.passes.tool.schedules import (
5
7
  SymbolTableDotGraphPass,
6
8
  SymbolTablePrinterPass,
7
9
  sym_tab_print,
8
10
  )
9
- from jaclang.compiler.transpiler import jac_file_to_pass
10
11
  from jaclang.utils.test import TestCase
11
12
 
12
13
 
@@ -1,4 +1,5 @@
1
1
  """Standardized transformation process and error interface."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from abc import ABC, abstractmethod
@@ -1,22 +1,35 @@
1
1
  """Overrides to mypy build manager for direct AST pass through."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import ast
6
+ import os
7
+ import pathlib
5
8
 
6
- import jaclang.vendor.mypy.build as myb
7
- import jaclang.vendor.mypy.errors as mye
8
- import jaclang.vendor.mypy.fastparse as myfp
9
+ import jaclang
9
10
  from jaclang.compiler.absyntree import AstNode
10
11
  from jaclang.compiler.passes import Pass
11
- from jaclang.vendor.mypy.build import BuildSource
12
- from jaclang.vendor.mypy.build import BuildSourceSet
13
- from jaclang.vendor.mypy.build import FileSystemCache
14
- from jaclang.vendor.mypy.build import compute_search_paths
15
- from jaclang.vendor.mypy.build import load_graph
16
- from jaclang.vendor.mypy.build import load_plugins
17
- from jaclang.vendor.mypy.build import process_graph
18
- from jaclang.vendor.mypy.options import Options
19
- from jaclang.vendor.mypy.semanal_main import semantic_analysis_for_scc
12
+
13
+ import mypy.build as myb
14
+ import mypy.errors as mye
15
+ import mypy.fastparse as myfp
16
+ from mypy.build import BuildSource
17
+ from mypy.build import BuildSourceSet
18
+ from mypy.build import FileSystemCache
19
+ from mypy.build import Graph
20
+ from mypy.build import ModuleNotFound
21
+ from mypy.build import PRI_INDIRECT
22
+ from mypy.build import compute_search_paths
23
+ from mypy.build import find_module_simple
24
+ from mypy.build import load_plugins
25
+ from mypy.build import process_graph
26
+ from mypy.options import Options
27
+ from mypy.semanal_main import semantic_analysis_for_scc
28
+
29
+
30
+ os.environ["MYPYPATH"] = str(
31
+ pathlib.Path(os.path.dirname(jaclang.__file__)).parent / "stubs"
32
+ )
20
33
 
21
34
 
22
35
  mypy_to_jac_node_map: dict[tuple[int, int | None, int | None, int | None], AstNode] = {}
@@ -32,7 +45,7 @@ class BuildManager(myb.BuildManager):
32
45
  source: str,
33
46
  ignore_errors: bool,
34
47
  options: myb.Options,
35
- ast_override: ast.AST | None = None,
48
+ ast_override: myb.MypyFile | None = None,
36
49
  ) -> myb.MypyFile:
37
50
  """Parse the source of a file with the given name.
38
51
 
@@ -83,7 +96,7 @@ class State(myb.State):
83
96
  # process it. With this flag, any changes to external state as well
84
97
  # as error reporting should be avoided.
85
98
  temporary: bool = False,
86
- ast_override: ast.AST | None = None,
99
+ ast_override: myb.MypyFile | None = None,
87
100
  ) -> None:
88
101
  """Override to mypy state for AST pass through."""
89
102
  if not temporary:
@@ -187,7 +200,7 @@ class State(myb.State):
187
200
  self.compute_dependencies()
188
201
 
189
202
  def parse_file(
190
- self, *, temporary: bool = False, ast_override: ast.AST | None = None
203
+ self, *, temporary: bool = False, ast_override: myb.MypyFile | None = None
191
204
  ) -> None:
192
205
  """Parse file and run first pass of semantic analysis.
193
206
 
@@ -304,13 +317,14 @@ class ASTConverter(myfp.ASTConverter):
304
317
  visitor = getattr(self, method)
305
318
  self.visitor_cache[typeobj] = visitor
306
319
  ret = visitor(node)
320
+ # Mypy sometimes inserts its own nodes, such as a Return around lambdas.
307
321
  if hasattr(node, "jac_link"):
308
322
  node.jac_link.gen.mypy_ast.append(ret)
309
323
  mypy_to_jac_node_map[
310
324
  (ret.line, ret.column, ret.end_line, ret.end_column)
311
325
  ] = node.jac_link
312
- else:
313
- raise Exception("AST node not linked to Jac node")
326
+ # else:
327
+ # raise Exception("AST node not linked to Jac node")
314
328
  return ret
315
329
 
316
330
 
@@ -364,6 +378,178 @@ class Errors(mye.Errors):
364
378
  )
365
379
 
366
380
 
381
+ def load_graph(
382
+ sources: list[BuildSource],
383
+ manager: BuildManager,
384
+ old_graph: Graph | None = None,
385
+ new_modules: list[State] | None = None,
386
+ ) -> Graph:
387
+ """Given some source files, load the full dependency graph.
388
+
389
+ If an old_graph is passed in, it is used as the starting point and
390
+ modified during graph loading.
391
+
392
+ If a new_modules is passed in, any modules that are loaded are
393
+ added to the list. This is an argument and not a return value
394
+ so that the caller can access it even if load_graph fails.
395
+
396
+ As this may need to parse files, this can raise CompileError in case
397
+ there are syntax errors.
398
+ """
399
+ graph: Graph = old_graph if old_graph is not None else {}
400
+
401
+ # The deque is used to implement breadth-first traversal.
402
+ # TODO: Consider whether to go depth-first instead. This may
403
+ # affect the order in which we process files within import cycles.
404
+ new = new_modules if new_modules is not None else []
405
+ entry_points: set[str] = set()
406
+ # Seed the graph with the initial root sources.
407
+ for bs in sources:
408
+ try:
409
+ st = State(
410
+ id=bs.module,
411
+ path=bs.path,
412
+ source=bs.text,
413
+ manager=manager,
414
+ root_source=not bs.followed,
415
+ )
416
+ except ModuleNotFound:
417
+ continue
418
+ if st.id in graph:
419
+ manager.errors.set_file(st.xpath, st.id, manager.options)
420
+ manager.errors.report(
421
+ -1,
422
+ -1,
423
+ f'Duplicate module named "{st.id}" (also at "{graph[st.id].xpath}")',
424
+ blocker=True,
425
+ )
426
+ manager.errors.report(
427
+ -1,
428
+ -1,
429
+ "See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules "
430
+ "for more info",
431
+ severity="note",
432
+ )
433
+ manager.errors.report(
434
+ -1,
435
+ -1,
436
+ "Common resolutions include: a) using `--exclude` to avoid checking one of them, "
437
+ "b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or "
438
+ "adjusting MYPYPATH",
439
+ severity="note",
440
+ )
441
+
442
+ manager.errors.raise_error()
443
+ graph[st.id] = st
444
+ new.append(st)
445
+ entry_points.add(bs.module)
446
+
447
+ # Note: Running this each time could be slow in the daemon. If it's a problem, we
448
+ # can do more work to maintain this incrementally.
449
+ seen_files = {st.abspath: st for st in graph.values() if st.path}
450
+
451
+ # Collect dependencies. We go breadth-first.
452
+ # More nodes might get added to new as we go, but that's fine.
453
+ for st in new:
454
+ assert st.ancestors is not None
455
+ # Strip out indirect dependencies. These will be dealt with
456
+ # when they show up as direct dependencies, and there's a
457
+ # scenario where they hurt:
458
+ # - Suppose A imports B and B imports C.
459
+ # - Suppose on the next round:
460
+ # - C is deleted;
461
+ # - B is updated to remove the dependency on C;
462
+ # - A is unchanged.
463
+ # - In this case A's cached *direct* dependencies are still valid
464
+ # (since direct dependencies reflect the imports found in the source)
465
+ # but A's cached *indirect* dependency on C is wrong.
466
+ dependencies = [
467
+ dep
468
+ for dep in st.dependencies
469
+ if st.priorities.get(dep) != PRI_INDIRECT and "jaclang.vendor" not in dep
470
+ ]
471
+ if not manager.use_fine_grained_cache():
472
+ # TODO: Ideally we could skip here modules that appeared in st.suppressed
473
+ # because they are not in build with `follow-imports=skip`.
474
+ # This way we could avoid overhead of cloning options in `State.__init__()`
475
+ # below to get the option value. This is quite minor performance loss however.
476
+ added = [dep for dep in st.suppressed if find_module_simple(dep, manager)]
477
+ else:
478
+ # During initial loading we don't care about newly added modules,
479
+ # they will be taken care of during fine grained update. See also
480
+ # comment about this in `State.__init__()`.
481
+ added = []
482
+ for dep in st.ancestors + dependencies + st.suppressed:
483
+ ignored = dep in st.suppressed_set and dep not in entry_points
484
+ if ignored and dep not in added:
485
+ manager.missing_modules.add(dep)
486
+ elif dep not in graph:
487
+ try:
488
+ if dep in st.ancestors:
489
+ # TODO: Why not 'if dep not in st.dependencies' ?
490
+ # Ancestors don't have import context.
491
+ newst = State(
492
+ id=dep,
493
+ path=None,
494
+ source=None,
495
+ manager=manager,
496
+ ancestor_for=st,
497
+ )
498
+ else:
499
+ newst = State(
500
+ id=dep,
501
+ path=None,
502
+ source=None,
503
+ manager=manager,
504
+ caller_state=st,
505
+ caller_line=st.dep_line_map.get(dep, 1),
506
+ )
507
+ except ModuleNotFound:
508
+ if dep in st.dependencies_set:
509
+ st.suppress_dependency(dep)
510
+ else:
511
+ if newst.path:
512
+ newst_path = os.path.abspath(newst.path)
513
+
514
+ if newst_path in seen_files:
515
+ manager.errors.report(
516
+ -1,
517
+ 0,
518
+ "Source file found twice under different module names: "
519
+ '"{}" and "{}"'.format(
520
+ seen_files[newst_path].id, newst.id
521
+ ),
522
+ blocker=True,
523
+ )
524
+ manager.errors.report(
525
+ -1,
526
+ 0,
527
+ "See https://mypy.readthedocs.io/en/stable/running"
528
+ + "_mypy.html#mapping-file-paths-to-modules "
529
+ "for more info",
530
+ severity="note",
531
+ )
532
+ manager.errors.report(
533
+ -1,
534
+ 0,
535
+ "Common resolutions include: a) adding `__init__.py` somewhere, "
536
+ "b) using `--explicit-package-bases` or adjusting MYPYPATH",
537
+ severity="note",
538
+ )
539
+ manager.errors.raise_error()
540
+
541
+ seen_files[newst_path] = newst
542
+
543
+ assert newst.id not in graph, newst.id
544
+ graph[newst.id] = newst
545
+ new.append(newst) # noqa: B038
546
+ if dep in graph and dep in st.suppressed_set:
547
+ # Previously suppressed file is now visible
548
+ st.add_dependency(dep)
549
+ manager.plugin.set_modules(manager.modules)
550
+ return graph
551
+
552
+
367
553
  __all__ = [
368
554
  "BuildManager",
369
555
  "State",
@@ -1,4 +1,5 @@
1
1
  """Jac Symbol Table."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import Enum
@@ -1,4 +1,5 @@
1
1
  """Tests for Jac Loader."""
2
+
2
3
  import sys
3
4
 
4
5
  from jaclang import jac_import
@@ -14,11 +15,11 @@ class TestLoader(TestCase):
14
15
 
15
16
  def test_import_basic_python(self) -> None:
16
17
  """Test basic self loading."""
17
- h = jac_import("fixtures.hello_world")
18
+ h = jac_import("fixtures.hello_world", base_path=__file__)
18
19
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
19
20
 
20
21
  def test_modules_correct(self) -> None:
21
22
  """Test basic self loading."""
22
- jac_import("fixtures.hello_world")
23
+ jac_import("fixtures.hello_world", base_path=__file__)
23
24
  self.assertIn("module 'hello_world'", str(sys.modules))
24
25
  self.assertIn("/tests/fixtures/hello_world.jac", str(sys.modules))
@@ -1,4 +1,5 @@
1
1
  """Tests for Jac parser."""
2
+
2
3
  import inspect
3
4
 
4
5
  from jaclang.compiler import jac_lark as jl
@@ -1,4 +1,5 @@
1
1
  """Tests for Jac Workspace."""
2
+
2
3
  import os
3
4
 
4
5
  from jaclang.compiler.workspace import Workspace
@@ -1,14 +1,16 @@
1
1
  """Living Workspace of Jac project."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import os
5
6
  from typing import Sequence
6
7
 
7
8
  import jaclang.compiler.absyntree as ast
9
+ from jaclang.compiler.compile import jac_str_to_pass
8
10
  from jaclang.compiler.passes.main import DefUsePass
11
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
9
12
  from jaclang.compiler.passes.transform import Alert
10
13
  from jaclang.compiler.symtable import Symbol, SymbolTable
11
- from jaclang.compiler.transpiler import jac_str_to_pass
12
14
 
13
15
 
14
16
  def sym_tab_list(sym_tab: SymbolTable, file_path: str) -> Sequence[SymbolTable]:
@@ -103,7 +105,7 @@ class Workspace:
103
105
  build = jac_str_to_pass(
104
106
  jac_str=source,
105
107
  file_path=file_path,
106
- target=DefUsePass,
108
+ schedule=py_code_gen_typed,
107
109
  )
108
110
  if not isinstance(build.ir, ast.Module):
109
111
  src = ast.JacSource(source, mod_path=file_path)
@@ -146,15 +148,26 @@ class Workspace:
146
148
  """Return a list of files in the workspace."""
147
149
  return list(self.modules.keys())
148
150
 
149
- def get_dependencies(self, file_path: str, deep: bool = False) -> list[ast.Import]:
151
+ def get_dependencies(
152
+ self, file_path: str, deep: bool = False
153
+ ) -> list[ast.ModulePath]:
150
154
  """Return a list of dependencies for a file."""
151
155
  if deep:
152
- return self.modules[file_path].ir.get_all_sub_nodes(ast.Import)
156
+ return [
157
+ i
158
+ for i in self.modules[file_path].ir.get_all_sub_nodes(ast.ModulePath)
159
+ if i.parent
160
+ and isinstance(i.parent, ast.Import)
161
+ and i.parent.lang.tag.value == "jac"
162
+ ]
153
163
  else:
154
164
  return [
155
165
  i
156
- for i in self.modules[file_path].ir.get_all_sub_nodes(ast.Import)
166
+ for i in self.modules[file_path].ir.get_all_sub_nodes(ast.ModulePath)
157
167
  if i.loc.mod_path == file_path
168
+ and i.parent
169
+ and isinstance(i.parent, ast.Import)
170
+ and i.parent.lang.tag.value == "jac"
158
171
  ]
159
172
 
160
173
  def get_symbols(self, file_path: str) -> Sequence[Symbol]: