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.
- jaclang/cli/cli.py +113 -7
- jaclang/cli/cmdreg.py +12 -0
- jaclang/compiler/__init__.py +58 -2
- jaclang/compiler/absyntree.py +1775 -61
- jaclang/compiler/codeloc.py +7 -0
- jaclang/compiler/compile.py +1 -1
- jaclang/compiler/constant.py +17 -0
- jaclang/compiler/parser.py +134 -112
- jaclang/compiler/passes/ir_pass.py +18 -0
- jaclang/compiler/passes/main/__init__.py +2 -0
- jaclang/compiler/passes/main/def_impl_match_pass.py +19 -3
- jaclang/compiler/passes/main/def_use_pass.py +1 -1
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +357 -0
- jaclang/compiler/passes/main/import_pass.py +7 -3
- jaclang/compiler/passes/main/pyast_gen_pass.py +350 -109
- jaclang/compiler/passes/main/pyast_load_pass.py +1779 -206
- jaclang/compiler/passes/main/registry_pass.py +126 -0
- jaclang/compiler/passes/main/schedules.py +4 -1
- jaclang/compiler/passes/main/sym_tab_build_pass.py +20 -28
- jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +14 -5
- jaclang/compiler/passes/main/tests/test_registry_pass.py +39 -0
- jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +8 -8
- jaclang/compiler/passes/main/tests/test_typeinfo_pass.py +7 -0
- jaclang/compiler/passes/main/type_check_pass.py +0 -1
- jaclang/compiler/passes/tool/jac_formatter_pass.py +8 -17
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +65 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +28 -14
- jaclang/compiler/symtable.py +23 -2
- jaclang/compiler/tests/test_parser.py +53 -0
- jaclang/compiler/workspace.py +52 -26
- jaclang/core/aott.py +193 -28
- jaclang/core/construct.py +59 -2
- jaclang/core/registry.py +115 -0
- jaclang/core/utils.py +25 -0
- jaclang/plugin/default.py +108 -26
- jaclang/plugin/feature.py +22 -4
- jaclang/plugin/spec.py +13 -7
- jaclang/utils/helpers.py +66 -3
- jaclang/utils/lang_tools.py +6 -38
- jaclang/utils/test.py +1 -0
- jaclang/utils/tests/test_lang_tools.py +11 -14
- jaclang/utils/treeprinter.py +10 -2
- {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/METADATA +1 -1
- {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/RECORD +47 -43
- {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/WHEEL +1 -1
- jaclang/compiler/__jac_gen__/__init__.py +0 -0
- jaclang/compiler/__jac_gen__/jac_parser.py +0 -4069
- {jaclang-0.5.7.dist-info → jaclang-0.5.9.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
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
|
-
|
|
48
|
-
node=node, single=
|
|
47
|
+
table.insert(
|
|
48
|
+
node=node, single=single_decl is not None, access_spec=access_spec
|
|
49
49
|
)
|
|
50
50
|
)
|
|
51
|
-
and
|
|
51
|
+
and single_decl
|
|
52
52
|
):
|
|
53
|
-
self.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
21
|
-
|
|
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)
|
|
40
|
+
self.assertIn(name, node_names)
|
|
32
41
|
for name in node_names:
|
|
33
|
-
self.assertIn(name, pass_func_names)
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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]))
|
|
@@ -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 +=
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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[
|
|
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
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
|
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
|
|
jaclang/compiler/symtable.py
CHANGED
|
@@ -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
|
-
|
|
147
|
-
|
|
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:
|