jaclang 0.5.7__py3-none-any.whl → 0.5.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 (49) hide show
  1. jaclang/cli/cli.py +113 -7
  2. jaclang/cli/cmdreg.py +12 -0
  3. jaclang/compiler/__init__.py +58 -2
  4. jaclang/compiler/absyntree.py +1775 -61
  5. jaclang/compiler/codeloc.py +7 -0
  6. jaclang/compiler/compile.py +1 -1
  7. jaclang/compiler/constant.py +17 -0
  8. jaclang/compiler/parser.py +134 -112
  9. jaclang/compiler/passes/ir_pass.py +18 -0
  10. jaclang/compiler/passes/main/__init__.py +2 -0
  11. jaclang/compiler/passes/main/def_impl_match_pass.py +19 -3
  12. jaclang/compiler/passes/main/def_use_pass.py +1 -1
  13. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +357 -0
  14. jaclang/compiler/passes/main/import_pass.py +7 -3
  15. jaclang/compiler/passes/main/pyast_gen_pass.py +350 -109
  16. jaclang/compiler/passes/main/pyast_load_pass.py +1779 -206
  17. jaclang/compiler/passes/main/registry_pass.py +126 -0
  18. jaclang/compiler/passes/main/schedules.py +4 -1
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +20 -28
  20. jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +14 -5
  21. jaclang/compiler/passes/main/tests/test_registry_pass.py +39 -0
  22. jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +8 -8
  23. jaclang/compiler/passes/main/tests/test_typeinfo_pass.py +7 -0
  24. jaclang/compiler/passes/main/type_check_pass.py +0 -1
  25. jaclang/compiler/passes/tool/jac_formatter_pass.py +8 -17
  26. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +65 -0
  27. jaclang/compiler/passes/utils/mypy_ast_build.py +28 -14
  28. jaclang/compiler/symtable.py +23 -2
  29. jaclang/compiler/tests/test_parser.py +53 -0
  30. jaclang/compiler/workspace.py +52 -26
  31. jaclang/core/aott.py +193 -28
  32. jaclang/core/construct.py +59 -2
  33. jaclang/core/registry.py +115 -0
  34. jaclang/core/utils.py +25 -0
  35. jaclang/plugin/default.py +108 -26
  36. jaclang/plugin/feature.py +22 -4
  37. jaclang/plugin/spec.py +13 -7
  38. jaclang/utils/helpers.py +66 -3
  39. jaclang/utils/lang_tools.py +6 -38
  40. jaclang/utils/test.py +1 -0
  41. jaclang/utils/tests/test_lang_tools.py +11 -14
  42. jaclang/utils/treeprinter.py +10 -2
  43. {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/METADATA +1 -1
  44. {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/RECORD +47 -43
  45. {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/WHEEL +1 -1
  46. jaclang/compiler/__jac_gen__/__init__.py +0 -0
  47. jaclang/compiler/__jac_gen__/jac_parser.py +0 -4069
  48. {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/entry_points.txt +0 -0
  49. {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,126 @@
1
+ """Jac Registry Pass.
2
+
3
+ This pass is responsible for creating object containing the senstring, scope,
4
+ type of different important nodes in the AST as we loose access to the
5
+ semstrings after PyASTGen pass. So we create those as a pickled file for
6
+ each module
7
+ """
8
+
9
+ import os
10
+ import pickle
11
+
12
+ import jaclang.compiler.absyntree as ast
13
+ from jaclang.compiler.constant import Constants as Con
14
+ from jaclang.compiler.passes import Pass
15
+ from jaclang.core.registry import SemInfo, SemRegistry
16
+ from jaclang.core.utils import get_sem_scope
17
+
18
+
19
+ class RegistryPass(Pass):
20
+ """Creates a registry for each module."""
21
+
22
+ modules_visited: list[ast.Module] = []
23
+
24
+ def enter_module(self, node: ast.Module) -> None:
25
+ """Create registry for each module."""
26
+ node.registry = SemRegistry()
27
+ self.modules_visited.append(node)
28
+
29
+ def exit_module(self, node: ast.Module) -> None:
30
+ """Save registry for each module."""
31
+ module_dir = os.path.join(
32
+ os.path.abspath(os.path.dirname(node.source.file_path)), Con.JAC_GEN_DIR
33
+ )
34
+ module_name = node.name
35
+ os.makedirs(module_dir, exist_ok=True)
36
+ with open(os.path.join(module_dir, f"{module_name}.registry.pkl"), "wb") as f:
37
+ pickle.dump(node.registry, f)
38
+ self.modules_visited.pop()
39
+
40
+ def exit_architype(self, node: ast.Architype) -> None:
41
+ """Save architype information."""
42
+ scope = get_sem_scope(node)
43
+ seminfo = SemInfo(
44
+ node.name.value,
45
+ node.arch_type.value,
46
+ node.semstr.lit_value if node.semstr else None,
47
+ )
48
+ if (
49
+ len(self.modules_visited)
50
+ and self.modules_visited[-1].registry
51
+ and scope.parent
52
+ ):
53
+ self.modules_visited[-1].registry.add(scope.parent, seminfo)
54
+
55
+ def exit_enum(self, node: ast.Enum) -> None:
56
+ """Save enum information."""
57
+ scope = get_sem_scope(node)
58
+ seminfo = SemInfo(
59
+ node.name.value, "Enum", node.semstr.lit_value if node.semstr else None
60
+ )
61
+ if (
62
+ len(self.modules_visited)
63
+ and self.modules_visited[-1].registry
64
+ and scope.parent
65
+ ):
66
+ self.modules_visited[-1].registry.add(scope.parent, seminfo)
67
+
68
+ def exit_has_var(self, node: ast.HasVar) -> None:
69
+ """Save variable information."""
70
+ extracted_type = (
71
+ "".join(self.extract_type(node.type_tag.kid[1:][0]))
72
+ if node.type_tag
73
+ else None
74
+ )
75
+ scope = get_sem_scope(node)
76
+ seminfo = SemInfo(
77
+ node.name.value,
78
+ extracted_type,
79
+ node.semstr.lit_value if node.semstr else None,
80
+ )
81
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
82
+ self.modules_visited[-1].registry.add(scope, seminfo)
83
+
84
+ def exit_assignment(self, node: ast.Assignment) -> None:
85
+ """Save assignment information."""
86
+ if node.aug_op:
87
+ return
88
+
89
+ extracted_type = (
90
+ "".join(self.extract_type(node.type_tag.kid[1:][0]))
91
+ if node.type_tag
92
+ else None
93
+ )
94
+ scope = get_sem_scope(node)
95
+ seminfo = SemInfo(
96
+ (
97
+ node.target.items[0].value
98
+ if isinstance(node.target.items[0], ast.Name)
99
+ else ""
100
+ ),
101
+ extracted_type,
102
+ node.semstr.lit_value if node.semstr else None,
103
+ )
104
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
105
+ self.modules_visited[-1].registry.add(scope, seminfo)
106
+
107
+ def exit_name(self, node: ast.Name) -> None:
108
+ """Save name information. for enum stmts."""
109
+ if (
110
+ node.parent
111
+ and node.parent.parent
112
+ and node.parent.parent.__class__.__name__ == "Enum"
113
+ ):
114
+ scope = get_sem_scope(node)
115
+ seminfo = SemInfo(node.value, None, None)
116
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
117
+ self.modules_visited[-1].registry.add(scope, seminfo)
118
+
119
+ def extract_type(self, node: ast.AstNode) -> list[str]:
120
+ """Collect type information in assignment using bfs."""
121
+ extracted_type = []
122
+ if isinstance(node, (ast.BuiltinType, ast.Token)):
123
+ extracted_type.append(node.value)
124
+ for child in node.kid:
125
+ extracted_type.extend(self.extract_type(child))
126
+ return extracted_type
@@ -15,6 +15,8 @@ from .pyout_pass import PyOutPass # noqa: I100
15
15
  from .pybc_gen_pass import PyBytecodeGenPass # noqa: I100
16
16
  from .pyast_gen_pass import PyastGenPass # noqa: I100
17
17
  from .type_check_pass import JacTypeCheckPass # noqa: I100
18
+ from .fuse_typeinfo_pass import FuseTypeInfoPass # noqa: I100
19
+ from .registry_pass import RegistryPass # noqa: I100
18
20
 
19
21
  py_code_gen = [
20
22
  SubNodeTabPass,
@@ -22,9 +24,10 @@ py_code_gen = [
22
24
  SymTabBuildPass,
23
25
  DeclDefMatchPass,
24
26
  DefUsePass,
27
+ RegistryPass,
25
28
  PyastGenPass,
26
29
  PyBytecodeGenPass,
27
30
  ]
28
31
 
29
- py_code_gen_typed = [*py_code_gen, JacTypeCheckPass]
32
+ py_code_gen_typed = [*py_code_gen, JacTypeCheckPass, FuseTypeInfoPass]
30
33
  py_compiler = [*py_code_gen, PyOutPass]
@@ -34,7 +34,7 @@ class SymTabPass(Pass):
34
34
  self,
35
35
  node: ast.AstSymbolNode,
36
36
  access_spec: Optional[ast.AstAccessNode] = None,
37
- single_use: Optional[str] = None,
37
+ single_decl: Optional[str] = None,
38
38
  table_override: Optional[SymbolTable] = None,
39
39
  ) -> Optional[Symbol]:
40
40
  """Insert into symbol table."""
@@ -44,18 +44,18 @@ class SymTabPass(Pass):
44
44
  if (
45
45
  table
46
46
  and (
47
- collide := table.insert(
48
- node=node, single=single_use is not None, access_spec=access_spec
47
+ table.insert(
48
+ node=node, single=single_decl is not None, access_spec=access_spec
49
49
  )
50
50
  )
51
- and single_use
51
+ and single_decl
52
52
  ):
53
- self.ice("Symbol Table Should be present by now") if not table else None
54
- self.already_declared_err(
55
- name=node.sym_name,
56
- typ=single_use if single_use else "ICE",
57
- original=collide,
58
- )
53
+ # self.already_declared_err(
54
+ # name=node.sym_name,
55
+ # typ=single_decl if single_decl else "ICE",
56
+ # original=collide,
57
+ # )
58
+ pass # TODO: Sort this out at some point
59
59
  node.py_ctx_func = ast3.Store
60
60
  if isinstance(node.sym_name_node, ast.AstSymbolNode):
61
61
  node.sym_name_node.py_ctx_func = ast3.Store
@@ -246,7 +246,6 @@ class SymTabBuildPass(SymTabPass):
246
246
  col_end=0,
247
247
  pos_start=0,
248
248
  pos_end=0,
249
- kid=[],
250
249
  )
251
250
  self.sync_node_to_scope(builtin)
252
251
  self.def_insert(builtin)
@@ -294,7 +293,7 @@ class SymTabBuildPass(SymTabPass):
294
293
  for i in self.get_all_sub_nodes(node, ast.Assignment):
295
294
  for j in i.target.items:
296
295
  if isinstance(j, ast.AstSymbolNode):
297
- self.def_insert(j, access_spec=node, single_use="global var")
296
+ self.def_insert(j, access_spec=node, single_decl="global var")
298
297
  else:
299
298
  self.ice("Expected name type for globabl vars")
300
299
 
@@ -330,7 +329,7 @@ class SymTabBuildPass(SymTabPass):
330
329
  description: Token,
331
330
  body: CodeBlock,
332
331
  """
333
- self.def_insert(node, single_use="test")
332
+ self.def_insert(node, single_decl="test")
334
333
  self.push_scope(node.name.value, node)
335
334
  self.sync_node_to_scope(node)
336
335
  self.pop_scope()
@@ -384,7 +383,7 @@ class SymTabBuildPass(SymTabPass):
384
383
  """
385
384
  if node.items:
386
385
  for i in node.items.items:
387
- self.def_insert(i, single_use="import item")
386
+ self.def_insert(i, single_decl="import item")
388
387
  elif node.is_absorb and node.lang.tag.value == "jac":
389
388
  if not node.paths[0].sub_module or not node.paths[0].sub_module.sym_tab:
390
389
  self.error(
@@ -411,7 +410,7 @@ class SymTabBuildPass(SymTabPass):
411
410
  sub_module: Optional[Module] = None,
412
411
  """
413
412
  if node.alias:
414
- self.def_insert(node.alias, single_use="import")
413
+ self.def_insert(node.alias, single_decl="import")
415
414
  elif node.path and isinstance(node.path[0], ast.Name):
416
415
  self.def_insert(node.path[0])
417
416
  else:
@@ -438,7 +437,7 @@ class SymTabBuildPass(SymTabPass):
438
437
  body: Optional[ArchBlock],
439
438
  """
440
439
  self.sync_node_to_scope(node)
441
- self.def_insert(node, single_use="architype")
440
+ self.def_insert(node, single_decl="architype")
442
441
  self.push_scope(node.name.value, node)
443
442
  self.sync_node_to_scope(node)
444
443
 
@@ -464,7 +463,7 @@ class SymTabBuildPass(SymTabPass):
464
463
  body: ArchBlock,
465
464
  """
466
465
  self.sync_node_to_scope(node)
467
- self.def_insert(node, single_use="arch def")
466
+ self.def_insert(node, single_decl="arch def")
468
467
  self.push_scope(node.sym_name, node)
469
468
  self.sync_node_to_scope(node)
470
469
 
@@ -492,7 +491,7 @@ class SymTabBuildPass(SymTabPass):
492
491
  body: Optional[CodeBlock],
493
492
  """
494
493
  self.sync_node_to_scope(node)
495
- self.def_insert(node, single_use="ability")
494
+ self.def_insert(node, single_decl="ability")
496
495
  self.push_scope(node.sym_name, node)
497
496
  self.sync_node_to_scope(node)
498
497
 
@@ -520,7 +519,7 @@ class SymTabBuildPass(SymTabPass):
520
519
  body: CodeBlock,
521
520
  """
522
521
  self.sync_node_to_scope(node)
523
- self.def_insert(node, single_use="ability def")
522
+ self.def_insert(node, single_decl="ability def")
524
523
  self.push_scope(node.sym_name, node)
525
524
  self.sync_node_to_scope(node)
526
525
 
@@ -580,7 +579,7 @@ class SymTabBuildPass(SymTabPass):
580
579
  body: Optional['EnumBlock'],
581
580
  """
582
581
  self.sync_node_to_scope(node)
583
- self.def_insert(node, single_use="enum")
582
+ self.def_insert(node, single_decl="enum")
584
583
  self.push_scope(node.sym_name, node)
585
584
  self.sync_node_to_scope(node)
586
585
 
@@ -604,7 +603,7 @@ class SymTabBuildPass(SymTabPass):
604
603
  body: EnumBlock,
605
604
  """
606
605
  self.sync_node_to_scope(node)
607
- self.def_insert(node, single_use="enum def")
606
+ self.def_insert(node, single_decl="enum def")
608
607
  self.push_scope(node.sym_name, node)
609
608
  self.sync_node_to_scope(node)
610
609
 
@@ -1048,13 +1047,6 @@ class SymTabBuildPass(SymTabPass):
1048
1047
  """
1049
1048
  self.sync_node_to_scope(node)
1050
1049
 
1051
- def enter_expr_list(self, node: ast.ExprList) -> None:
1052
- """Sub objects.
1053
-
1054
- values: list[ExprType],
1055
- """
1056
- self.sync_node_to_scope(node)
1057
-
1058
1050
  def enter_list_val(self, node: ast.ListVal) -> None:
1059
1051
  """Sub objects.
1060
1052
 
@@ -17,9 +17,18 @@ class PyastBuildPassTests(TestCase):
17
17
 
18
18
  def test_synced_to_latest_py_ast(self) -> None:
19
19
  """Basic test for pass."""
20
- visit_methods = [
21
- method for method in dir(py_ast._Unparser) if method.startswith("visit_") # type: ignore
22
- ]
20
+ unparser_cls = py_ast._Unparser
21
+ visit_methods = (
22
+ [
23
+ method
24
+ for method in dir(unparser_cls) # noqa: B009
25
+ if method.startswith("visit_")
26
+ ]
27
+ + list(unparser_cls.binop.keys())
28
+ + list(unparser_cls.unop.keys())
29
+ + list(unparser_cls.boolops.keys())
30
+ + list(unparser_cls.cmpops.keys())
31
+ )
23
32
  node_names = [
24
33
  pascal_to_snake(method.replace("visit_", "")) for method in visit_methods
25
34
  ]
@@ -28,6 +37,6 @@ class PyastBuildPassTests(TestCase):
28
37
  if name.startswith("proc_") and inspect.isfunction(value):
29
38
  pass_func_names.append(name.replace("proc_", ""))
30
39
  for name in pass_func_names:
31
- self.assertIn(name, node_names) # type: ignore
40
+ self.assertIn(name, node_names)
32
41
  for name in node_names:
33
- self.assertIn(name, pass_func_names) # type: ignore
42
+ self.assertIn(name, pass_func_names)
@@ -0,0 +1,39 @@
1
+ """Test registry pass."""
2
+
3
+ import os
4
+
5
+ from jaclang.compiler.compile import jac_file_to_pass
6
+ from jaclang.compiler.passes.main import RegistryPass
7
+ from jaclang.utils.test import TestCase
8
+
9
+
10
+ class RegistryPassTests(TestCase):
11
+ """Test pass module."""
12
+
13
+ def setUp(self) -> None:
14
+ """Set up test."""
15
+ return super().setUp()
16
+
17
+ def test_registry_pass(self) -> None:
18
+ """Basic test for pass."""
19
+ state = jac_file_to_pass(self.fixture_abs_path("registry.jac"), RegistryPass)
20
+ self.assertFalse(state.errors_had)
21
+ self.assertTrue(
22
+ os.path.exists(
23
+ os.path.join(
24
+ os.path.dirname(self.fixture_abs_path("registry.jac")),
25
+ "__jac_gen__",
26
+ "registry.registry.pkl",
27
+ )
28
+ )
29
+ )
30
+ self.assertTrue(
31
+ os.path.exists(
32
+ os.path.join(
33
+ os.path.dirname(self.fixture_abs_path("registry.jac")),
34
+ "__jac_gen__",
35
+ "fstrings.registry.pkl",
36
+ )
37
+ )
38
+ )
39
+ self.assertIn("109", str(state.ir.to_dict()))
@@ -1,6 +1,6 @@
1
1
  """Test pass module."""
2
2
 
3
- from jaclang.compiler.compile import jac_file_to_pass
3
+ # from jaclang.compiler.compile import jac_file_to_pass
4
4
  from jaclang.compiler.passes.main import SymTabBuildPass
5
5
  from jaclang.utils.test import AstSyncTestMixin, TestCase
6
6
 
@@ -14,10 +14,10 @@ class SymTabBuildPassTests(TestCase, AstSyncTestMixin):
14
14
  """Set up test."""
15
15
  return super().setUp()
16
16
 
17
- def test_name_collision(self) -> None:
18
- """Basic test for pass."""
19
- state = jac_file_to_pass(
20
- self.fixture_abs_path("multi_def_err.jac"), SymTabBuildPass
21
- )
22
- self.assertGreater(len(state.warnings_had), 0)
23
- self.assertIn("MyObject", str(state.warnings_had[0]))
17
+ # def test_name_collision(self) -> None:
18
+ # """Basic test for pass."""
19
+ # state = jac_file_to_pass(
20
+ # self.fixture_abs_path("multi_def_err.jac"), SymTabBuildPass
21
+ # )
22
+ # self.assertGreater(len(state.warnings_had), 0)
23
+ # self.assertIn("MyObject", str(state.warnings_had[0]))
@@ -0,0 +1,7 @@
1
+ """Test pass module."""
2
+
3
+ from jaclang.utils.test import TestCase
4
+
5
+
6
+ class TestFuseTypeInfo(TestCase):
7
+ """Test pass module."""
@@ -101,4 +101,3 @@ class JacTypeCheckPass(Pass):
101
101
  new_modules=new_modules, # To parse the dependancies of modules
102
102
  )
103
103
  myab.process_graph(graph, manager)
104
- myab.semantic_analysis_for_scc(graph, [self.__modules[0].name], errors)
@@ -342,18 +342,6 @@ class JacFormatPass(Pass):
342
342
  if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
343
343
  self.emit_ln(node, "")
344
344
 
345
- def exit_expr_list(self, node: ast.ExprList) -> None:
346
- """Sub objects.
347
-
348
- values: Optional[SubNodeList[ExprType]],
349
- """
350
- if node.values is not None:
351
- self.sep_node_list(node.values, delim=";")
352
- self.emit(
353
- node,
354
- f"{', '.join([value.gen.jac for value in node.values.items])}",
355
- )
356
-
357
345
  def exit_multi_string(self, node: ast.MultiString) -> None:
358
346
  """Sub objects.
359
347
 
@@ -1478,7 +1466,7 @@ class JacFormatPass(Pass):
1478
1466
  elif isinstance(i, ast.Semi) or i.gen.jac == ",":
1479
1467
  self.emit(node, i.gen.jac)
1480
1468
  else:
1481
- if start:
1469
+ if start or i.gen.jac == "}":
1482
1470
  self.emit(node, i.gen.jac)
1483
1471
  start = False
1484
1472
  else:
@@ -1500,7 +1488,7 @@ class JacFormatPass(Pass):
1500
1488
  f"{node.collection.gen.jac}"
1501
1489
  )
1502
1490
  if node.conditional:
1503
- partial += f" if {node.conditional.gen.jac}"
1491
+ partial += " if " + " if ".join(i.gen.jac for i in node.conditional)
1504
1492
  self.emit(node, f"{partial}")
1505
1493
 
1506
1494
  def exit_list_compr(self, node: ast.ListCompr) -> None:
@@ -1552,7 +1540,10 @@ class JacFormatPass(Pass):
1552
1540
  value: ExprType,
1553
1541
  """
1554
1542
  for i in node.kid:
1555
- self.emit(node, i.gen.jac)
1543
+ if i.gen.jac == ":":
1544
+ self.emit(node, f"{i.gen.jac} ")
1545
+ else:
1546
+ self.emit(node, i.gen.jac)
1556
1547
 
1557
1548
  def exit_k_w_pair(self, node: ast.KWPair) -> None:
1558
1549
  """Sub objects.
@@ -1916,7 +1907,7 @@ class JacFormatPass(Pass):
1916
1907
 
1917
1908
  pattern: ExprType,
1918
1909
  guard: Optional[ExprType],
1919
- body: SubNodeList[CodeBlockStmt],
1910
+ body: list[CodeBlockStmt],
1920
1911
  """
1921
1912
  start = True
1922
1913
  for i in node.kid:
@@ -1930,7 +1921,7 @@ class JacFormatPass(Pass):
1930
1921
  self.emit(node, i.gen.jac)
1931
1922
  elif isinstance(i, ast.Token) and i.value == ":":
1932
1923
  self.emit_ln(node, i.gen.jac)
1933
- elif isinstance(i, ast.SubNodeList):
1924
+ elif isinstance(i, ast.CodeBlockStmt):
1934
1925
  self.indent_level += 1
1935
1926
  self.emit(node, i.gen.jac.strip())
1936
1927
  self.indent_level -= 1
@@ -0,0 +1,65 @@
1
+ """Test ast build pass module."""
2
+
3
+ import ast as ast3
4
+ from difflib import unified_diff
5
+
6
+ import jaclang.compiler.absyntree as ast
7
+ from jaclang.compiler.compile import jac_file_to_pass, jac_str_to_pass
8
+ from jaclang.compiler.passes.main import PyastGenPass
9
+ from jaclang.compiler.passes.main.schedules import py_code_gen as without_format
10
+ from jaclang.compiler.passes.tool import JacFormatPass
11
+ from jaclang.utils.test import AstSyncTestMixin, TestCaseMicroSuite
12
+
13
+
14
+ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
15
+ """Test pass module."""
16
+
17
+ TargetPass = JacFormatPass
18
+
19
+ def micro_suite_test(self, filename: str) -> None:
20
+ """Parse micro jac file."""
21
+ try:
22
+ code_gen_pure = jac_file_to_pass(
23
+ self.fixture_abs_path(filename),
24
+ target=PyastGenPass,
25
+ schedule=without_format,
26
+ )
27
+ before = ast3.dump(code_gen_pure.ir.gen.py_ast[0], indent=2)
28
+ x = code_gen_pure.ir.unparse()
29
+ # print(x)
30
+ # print(f"Testing {code_gen_pure.ir.name}")
31
+ # print(code_gen_pure.ir.pp())
32
+ code_gen_jac = jac_str_to_pass(
33
+ jac_str=x,
34
+ file_path=filename,
35
+ target=PyastGenPass,
36
+ schedule=without_format,
37
+ )
38
+ after = ast3.dump(code_gen_jac.ir.gen.py_ast[0], indent=2)
39
+ if "circle_clean_tests.jac" in filename:
40
+ self.assertEqual(
41
+ len(
42
+ [
43
+ i
44
+ for i in unified_diff(
45
+ before.splitlines(), after.splitlines(), n=0
46
+ )
47
+ if "test" not in i
48
+ ]
49
+ ),
50
+ 5,
51
+ )
52
+ else:
53
+ self.assertEqual(
54
+ len(
55
+ "\n".join(unified_diff(before.splitlines(), after.splitlines()))
56
+ ),
57
+ 0,
58
+ )
59
+
60
+ except Exception as e:
61
+ raise e
62
+ # self.skipTest(f"Test failed, but skipping instead of failing: {e}")
63
+
64
+
65
+ JacUnparseTests.self_attach_micro_tests()
@@ -32,7 +32,9 @@ os.environ["MYPYPATH"] = str(
32
32
  )
33
33
 
34
34
 
35
- mypy_to_jac_node_map: dict[tuple[int, int | None, int | None, int | None], AstNode] = {}
35
+ mypy_to_jac_node_map: dict[
36
+ tuple[int, int | None, int | None, int | None], list[AstNode]
37
+ ] = {}
36
38
 
37
39
 
38
40
  class BuildManager(myb.BuildManager):
@@ -308,24 +310,36 @@ class ASTConverter(myfp.ASTConverter):
308
310
 
309
311
  def visit(self, node: ast.AST | None) -> myfp.Any: # noqa: ANN401
310
312
  """Override to mypy AST converter for direct AST pass through."""
311
- if node is None:
312
- return None
313
- typeobj = type(node)
314
- visitor = self.visitor_cache.get(typeobj)
315
- if visitor is None:
316
- method = "visit_" + node.__class__.__name__
317
- visitor = getattr(self, method)
318
- self.visitor_cache[typeobj] = visitor
319
- ret = visitor(node)
320
- # Mypy sometimes inserts its own nodes, such as a Return around lambdas.
313
+ ret = super().visit(node)
314
+ if node and ret:
315
+ self.link_mypy_to_jac_node(node, ret)
316
+ return ret
317
+
318
+ def make_argument(
319
+ self,
320
+ arg: ast.arg,
321
+ default: ast.expr | None,
322
+ kind: myfp.ArgKind,
323
+ no_type_check: bool,
324
+ pos_only: bool = False,
325
+ ) -> myfp.Argument:
326
+ """Override to mypy AST converter for direct AST pass through."""
327
+ ret = super().make_argument(arg, default, kind, no_type_check, pos_only)
328
+ self.link_mypy_to_jac_node(arg, ret)
329
+ return ret
330
+
331
+ def link_mypy_to_jac_node(
332
+ self, node: ast.AST, ret: myfp.Any # noqa: ANN401
333
+ ) -> None:
334
+ """Link mypy AST node to Jac AST node."""
321
335
  if hasattr(node, "jac_link"):
322
- node.jac_link.gen.mypy_ast.append(ret)
336
+ for i in range(len(node.jac_link)):
337
+ node.jac_link[i].gen.mypy_ast.append(ret)
323
338
  mypy_to_jac_node_map[
324
339
  (ret.line, ret.column, ret.end_line, ret.end_column)
325
340
  ] = node.jac_link
326
341
  # else:
327
342
  # raise Exception("AST node not linked to Jac node")
328
- return ret
329
343
 
330
344
 
331
345
  class Errors(mye.Errors):
@@ -374,7 +388,7 @@ class Errors(mye.Errors):
374
388
  msg=message,
375
389
  node_override=mypy_to_jac_node_map[
376
390
  (line, column, end_line, end_column)
377
- ],
391
+ ][0],
378
392
  )
379
393
 
380
394
 
@@ -43,6 +43,15 @@ class SymbolType(Enum):
43
43
  return self.value
44
44
 
45
45
 
46
+ class SymbolInfo:
47
+ """Symbol Info."""
48
+
49
+ def __init__(self, typ: str = "NoType") -> None: # noqa: ANN401
50
+ """Initialize."""
51
+ self.typ = typ
52
+ self.typ_sym_table: Optional[SymbolTable] = None
53
+
54
+
46
55
  class SymbolAccess(Enum):
47
56
  """Symbol types."""
48
57
 
@@ -55,6 +64,8 @@ class SymbolAccess(Enum):
55
64
  return self.value
56
65
 
57
66
 
67
+ # Symbols can have mulitple definitions but resolves decl to be the
68
+ # first such definition in a given scope.
58
69
  class Symbol:
59
70
  """Symbol."""
60
71
 
@@ -143,8 +154,11 @@ class SymbolTable:
143
154
  Returns original symbol as collision if single check fails, none otherwise.
144
155
  Also updates node.sym to create pointer to symbol.
145
156
  """
146
- if single and node.sym_name in self.tab:
147
- return self.tab[node.sym_name].defn[-1]
157
+ collision = (
158
+ self.tab[node.sym_name].defn[-1]
159
+ if single and node.sym_name in self.tab
160
+ else None
161
+ )
148
162
  if node.sym_name not in self.tab:
149
163
  self.tab[node.sym_name] = Symbol(
150
164
  defn=node,
@@ -154,6 +168,13 @@ class SymbolTable:
154
168
  else:
155
169
  self.tab[node.sym_name].add_defn(node)
156
170
  node.sym_link = self.tab[node.sym_name]
171
+ return collision
172
+
173
+ def find_scope(self, name: str) -> Optional[SymbolTable]:
174
+ """Find a scope in the symbol table."""
175
+ for k in self.kid:
176
+ if k.name == name:
177
+ return k
157
178
  return None
158
179
 
159
180
  def push_scope(self, name: str, key_node: ast.AstNode) -> SymbolTable: