jaclang 0.0.1__py3-none-any.whl → 0.0.3__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/__init__.py +4 -0
- jaclang/cli/__init__.py +7 -0
- jaclang/cli/cli.jac +46 -0
- jaclang/cli/cmds.jac +14 -0
- jaclang/cli/impl/__init__.py +1 -0
- jaclang/cli/impl/cli_impl.jac +93 -0
- jaclang/cli/impl/cmds_impl.jac +26 -0
- jaclang/core/__init__.py +12 -0
- jaclang/core/impl/__init__.py +1 -0
- jaclang/core/impl/arch_impl.jac +112 -0
- jaclang/core/impl/element_impl.jac +95 -0
- jaclang/core/impl/exec_ctx_impl.jac +17 -0
- jaclang/core/impl/memory_impl.jac +57 -0
- jaclang/core/primitives.jac +104 -0
- jaclang/jac/__init__.py +1 -0
- jaclang/jac/absyntree.py +1787 -0
- jaclang/jac/constant.py +46 -0
- jaclang/jac/importer.py +130 -0
- jaclang/jac/lexer.py +538 -0
- jaclang/jac/parser.py +1474 -0
- jaclang/jac/passes/__init__.py +5 -0
- jaclang/jac/passes/blue/__init__.py +25 -0
- jaclang/jac/passes/blue/ast_build_pass.py +3190 -0
- jaclang/jac/passes/blue/blue_pygen_pass.py +1335 -0
- jaclang/jac/passes/blue/decl_def_match_pass.py +278 -0
- jaclang/jac/passes/blue/import_pass.py +75 -0
- jaclang/jac/passes/blue/sub_node_tab_pass.py +30 -0
- jaclang/jac/passes/blue/tests/__init__.py +1 -0
- jaclang/jac/passes/blue/tests/test_ast_build_pass.py +61 -0
- jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +117 -0
- jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +43 -0
- jaclang/jac/passes/blue/tests/test_import_pass.py +18 -0
- jaclang/jac/passes/blue/tests/test_sub_node_pass.py +26 -0
- jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +53 -0
- jaclang/jac/passes/blue/type_analyze_pass.py +731 -0
- jaclang/jac/passes/ir_pass.py +154 -0
- jaclang/jac/passes/purple/__init__.py +17 -0
- jaclang/jac/passes/purple/impl/__init__.py +1 -0
- jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +289 -0
- jaclang/jac/passes/purple/purple_pygen_pass.jac +35 -0
- jaclang/jac/sym_table.py +127 -0
- jaclang/jac/tests/__init__.py +1 -0
- jaclang/jac/tests/fixtures/__init__.py +1 -0
- jaclang/jac/tests/fixtures/activity.py +10 -0
- jaclang/jac/tests/fixtures/fam.jac +68 -0
- jaclang/jac/tests/fixtures/hello_world.jac +5 -0
- jaclang/jac/tests/fixtures/lexer_fam.jac +61 -0
- jaclang/jac/tests/fixtures/stuff.jac +6 -0
- jaclang/jac/tests/test_importer.py +24 -0
- jaclang/jac/tests/test_lexer.py +57 -0
- jaclang/jac/tests/test_parser.py +50 -0
- jaclang/jac/tests/test_utils.py +12 -0
- jaclang/jac/transform.py +63 -0
- jaclang/jac/transpiler.py +69 -0
- jaclang/jac/utils.py +120 -0
- jaclang/utils/__init__.py +1 -0
- jaclang/utils/fstring_parser.py +73 -0
- jaclang/utils/log.py +9 -0
- jaclang/utils/sly/__init__.py +6 -0
- jaclang/utils/sly/docparse.py +62 -0
- jaclang/utils/sly/lex.py +510 -0
- jaclang/utils/sly/yacc.py +2398 -0
- jaclang/utils/test.py +81 -0
- jaclang/utils/tests/__init__.py +1 -0
- jaclang/utils/tests/test_fstring_parser.py +55 -0
- jaclang-0.0.3.dist-info/METADATA +12 -0
- jaclang-0.0.3.dist-info/RECORD +70 -0
- {jaclang-0.0.1.dist-info → jaclang-0.0.3.dist-info}/WHEEL +1 -1
- jaclang-0.0.3.dist-info/entry_points.txt +3 -0
- jaclang-0.0.3.dist-info/top_level.txt +1 -0
- jaclang-0.0.1.dist-info/METADATA +0 -7
- jaclang-0.0.1.dist-info/RECORD +0 -4
- jaclang-0.0.1.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Connect Decls and Defs in AST."""
|
|
2
|
+
import jaclang.jac.absyntree as ast
|
|
3
|
+
from jaclang.jac.lexer import Tokens as Tok
|
|
4
|
+
from jaclang.jac.passes import Pass
|
|
5
|
+
from jaclang.jac.sym_table import DefDeclSymbol, SymbolTable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DeclDefMatchPass(Pass, SymbolTable):
|
|
9
|
+
"""Decls and Def matching pass."""
|
|
10
|
+
|
|
11
|
+
def before_pass(self) -> None:
|
|
12
|
+
"""Initialize pass."""
|
|
13
|
+
self.sym_tab = SymbolTable(scope_name="global")
|
|
14
|
+
|
|
15
|
+
def exit_global_vars(self, node: ast.GlobalVars) -> None:
|
|
16
|
+
"""Sub objects.
|
|
17
|
+
|
|
18
|
+
doc: Optional[DocString],
|
|
19
|
+
access: Optional[Token],
|
|
20
|
+
assignments: AssignmentList,
|
|
21
|
+
"""
|
|
22
|
+
for i in self.get_all_sub_nodes(node, ast.Assignment):
|
|
23
|
+
if type(i.target) != ast.Name:
|
|
24
|
+
self.ice("Only name targets should be possible to in global vars.")
|
|
25
|
+
else:
|
|
26
|
+
decl = self.sym_tab.lookup(i.target.value)
|
|
27
|
+
if decl:
|
|
28
|
+
if decl.has_def:
|
|
29
|
+
self.error(f"Name {i.target.value} already bound.")
|
|
30
|
+
else:
|
|
31
|
+
decl.has_def = True
|
|
32
|
+
decl.other_node = i
|
|
33
|
+
decl.node.body = i # TODO: I dont think this line makes sense
|
|
34
|
+
self.sym_tab.set(decl)
|
|
35
|
+
|
|
36
|
+
def exit_test(self, node: ast.Test) -> None:
|
|
37
|
+
"""Sub objects.
|
|
38
|
+
|
|
39
|
+
name: Name,
|
|
40
|
+
doc: Optional[DocString],
|
|
41
|
+
description: Token,
|
|
42
|
+
body: CodeBlock,
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def enter_import(self, node: ast.Import) -> None:
|
|
46
|
+
"""Sub objects.
|
|
47
|
+
|
|
48
|
+
lang: Name,
|
|
49
|
+
path: ModulePath,
|
|
50
|
+
alias: Optional[Name],
|
|
51
|
+
items: Optional[ModuleItems],
|
|
52
|
+
is_absorb: bool,
|
|
53
|
+
sub_module: Optional[Module],
|
|
54
|
+
"""
|
|
55
|
+
if not node.is_absorb:
|
|
56
|
+
self.sym_tab = self.sym_tab.push(node.path.path_str)
|
|
57
|
+
|
|
58
|
+
def exit_import(self, node: ast.Import) -> None:
|
|
59
|
+
"""Sub objects.
|
|
60
|
+
|
|
61
|
+
lang: Name,
|
|
62
|
+
path: ModulePath,
|
|
63
|
+
alias: Optional[Name],
|
|
64
|
+
items: Optional[ModuleItems],
|
|
65
|
+
is_absorb: bool,
|
|
66
|
+
sub_module: Optional[Module],
|
|
67
|
+
"""
|
|
68
|
+
if not node.is_absorb and not self.sym_tab.parent:
|
|
69
|
+
self.ice("Import should have a parent sym_table scope.")
|
|
70
|
+
elif not node.is_absorb:
|
|
71
|
+
self.sym_tab = self.sym_tab.pop()
|
|
72
|
+
if node.items: # now treat imported items as global
|
|
73
|
+
for i in node.items.items:
|
|
74
|
+
name = i.alias if i.alias else i.name
|
|
75
|
+
decl = self.sym_tab.lookup(name.value)
|
|
76
|
+
if not decl:
|
|
77
|
+
self.sym_tab.set(
|
|
78
|
+
DefDeclSymbol(name=name.value, node=i, has_def=True)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def exit_module_item(self, node: ast.ModuleItem) -> None:
|
|
82
|
+
"""Sub objects.
|
|
83
|
+
|
|
84
|
+
name: Name,
|
|
85
|
+
alias: Optional[Token],
|
|
86
|
+
body: Optional[AstNode],
|
|
87
|
+
"""
|
|
88
|
+
if not self.sym_tab.lookup(node.name.value):
|
|
89
|
+
self.sym_tab.set(
|
|
90
|
+
DefDeclSymbol(name=node.name.value, node=node, has_decl=True)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def exit_architype(self, node: ast.Architype) -> None:
|
|
94
|
+
"""Sub objects.
|
|
95
|
+
|
|
96
|
+
name: Name,
|
|
97
|
+
arch_type: Token,
|
|
98
|
+
doc: Optional[DocString],
|
|
99
|
+
decorators: Optional[Decorators],
|
|
100
|
+
access: Optional[Token],
|
|
101
|
+
base_classes: BaseClasses,
|
|
102
|
+
body: Optional[ArchBlock],
|
|
103
|
+
"""
|
|
104
|
+
# if no body, check for def
|
|
105
|
+
# if no def, register as decl
|
|
106
|
+
# if complete register as def
|
|
107
|
+
# nota: can allow static overriding perhaps?
|
|
108
|
+
# note: if arch has not body ok, imports body is the arch itself
|
|
109
|
+
|
|
110
|
+
def exit_arch_def(self, node: ast.ArchDef) -> None:
|
|
111
|
+
"""Sub objects.
|
|
112
|
+
|
|
113
|
+
doc: Optional[DocString],
|
|
114
|
+
mod: Optional[NameList],
|
|
115
|
+
arch: ObjectRef | NodeRef | EdgeRef | WalkerRef,
|
|
116
|
+
body: ArchBlock,
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def enter_ability(self, node: ast.Ability) -> None:
|
|
120
|
+
"""Sub objects.
|
|
121
|
+
|
|
122
|
+
name: Name,
|
|
123
|
+
is_func: bool,
|
|
124
|
+
doc: Optional[DocString],
|
|
125
|
+
decorators: Optional["Decorators"],
|
|
126
|
+
access: Optional[Token],
|
|
127
|
+
signature: "FuncSignature | TypeSpec | EventSignature",
|
|
128
|
+
body: Optional["CodeBlock"],
|
|
129
|
+
arch_attached: Optional["ArchBlock"] = None,
|
|
130
|
+
"""
|
|
131
|
+
self.sym_tab = self.sym_tab.push(node.name.value)
|
|
132
|
+
|
|
133
|
+
def exit_ability(self, node: ast.Ability) -> None:
|
|
134
|
+
"""Sub objects.
|
|
135
|
+
|
|
136
|
+
name: Name,
|
|
137
|
+
is_func: bool,
|
|
138
|
+
doc: Optional[DocString],
|
|
139
|
+
decorators: Optional["Decorators"],
|
|
140
|
+
access: Optional[Token],
|
|
141
|
+
signature: "FuncSignature | TypeSpec | EventSignature",
|
|
142
|
+
body: Optional["CodeBlock"],
|
|
143
|
+
arch_attached: Optional["ArchBlock"] = None,
|
|
144
|
+
"""
|
|
145
|
+
name = (
|
|
146
|
+
f"{node.arch_attached.parent.name.value}.{node.name.value}"
|
|
147
|
+
if node.arch_attached and type(node.arch_attached.parent) == ast.Architype
|
|
148
|
+
else node.name.value
|
|
149
|
+
)
|
|
150
|
+
decl = self.sym_tab.lookup(name)
|
|
151
|
+
if decl and decl.has_decl:
|
|
152
|
+
self.error(
|
|
153
|
+
f"Ability bound with name {name} already defined on "
|
|
154
|
+
f"Line {decl.node.line} in {decl.node.mod_link.rel_mod_path}."
|
|
155
|
+
)
|
|
156
|
+
elif decl and decl.has_def:
|
|
157
|
+
decl.has_decl = True
|
|
158
|
+
decl.node = node
|
|
159
|
+
decl.node.body = (
|
|
160
|
+
decl.other_node.body
|
|
161
|
+
if type(decl.other_node) == ast.AbilityDef
|
|
162
|
+
else self.ice("Expected node of type AbilityDef in symbol table.")
|
|
163
|
+
)
|
|
164
|
+
ast.append_node(decl.node, decl.other_node)
|
|
165
|
+
self.sym_tab.set(decl)
|
|
166
|
+
else:
|
|
167
|
+
decl = DefDeclSymbol(name=name, node=node, has_decl=True)
|
|
168
|
+
if node.body:
|
|
169
|
+
decl.has_def = True
|
|
170
|
+
decl.other_node = node
|
|
171
|
+
self.sym_tab.set(decl)
|
|
172
|
+
self.sym_tab = self.sym_tab.pop()
|
|
173
|
+
|
|
174
|
+
def exit_ability_def(self, node: ast.AbilityDef) -> None:
|
|
175
|
+
"""Sub objects.
|
|
176
|
+
|
|
177
|
+
doc: Optional[DocString],
|
|
178
|
+
target: Optional["NameList"],
|
|
179
|
+
ability: "ArchRef",
|
|
180
|
+
signature: "FuncSignature | EventSignature",
|
|
181
|
+
body: "CodeBlock",
|
|
182
|
+
"""
|
|
183
|
+
name = node.ability.name.value
|
|
184
|
+
if node.target:
|
|
185
|
+
owner = node.target.names[-1]
|
|
186
|
+
if not isinstance(owner, ast.ArchRef):
|
|
187
|
+
self.error("Expected reference to Architype!")
|
|
188
|
+
owner = ""
|
|
189
|
+
else:
|
|
190
|
+
owner = owner.name.value
|
|
191
|
+
name = f"{owner}.{name}"
|
|
192
|
+
decl = self.sym_tab.lookup(name)
|
|
193
|
+
if decl and decl.has_def:
|
|
194
|
+
self.error(
|
|
195
|
+
f"Ability bound with name {name} already defined on "
|
|
196
|
+
f"Line {decl.other_node.line} in {decl.other_node.mod_link.rel_mod_path}."
|
|
197
|
+
)
|
|
198
|
+
elif decl and decl.has_decl:
|
|
199
|
+
decl.has_def = True
|
|
200
|
+
decl.other_node = node
|
|
201
|
+
decl.node.body = decl.other_node.body
|
|
202
|
+
ast.append_node(decl.node, decl.other_node)
|
|
203
|
+
self.sym_tab.set(decl)
|
|
204
|
+
else:
|
|
205
|
+
self.sym_tab.set(DefDeclSymbol(name=name, other_node=node, has_def=True))
|
|
206
|
+
|
|
207
|
+
def enter_arch_block(self, node: ast.ArchBlock) -> None:
|
|
208
|
+
"""Sub objects.
|
|
209
|
+
|
|
210
|
+
members: list['ArchHas | Ability'],
|
|
211
|
+
"""
|
|
212
|
+
# Tags all function signatures whether method style or not
|
|
213
|
+
for i in self.get_all_sub_nodes(node, ast.Ability):
|
|
214
|
+
i.arch_attached = node
|
|
215
|
+
if (
|
|
216
|
+
type(node.parent) == ast.Architype
|
|
217
|
+
and node.parent.arch_type.name == Tok.KW_WALKER
|
|
218
|
+
):
|
|
219
|
+
for i in self.get_all_sub_nodes(node, ast.VisitStmt):
|
|
220
|
+
i.from_walker = True
|
|
221
|
+
for i in self.get_all_sub_nodes(node, ast.DisengageStmt):
|
|
222
|
+
i.from_walker = True
|
|
223
|
+
|
|
224
|
+
def exit_enum(self, node: ast.Enum) -> None:
|
|
225
|
+
"""Sub objects.
|
|
226
|
+
|
|
227
|
+
name: Name,
|
|
228
|
+
doc: Optional[DocString],
|
|
229
|
+
decorators: Optional[Decorators],
|
|
230
|
+
access: Optional[Token],
|
|
231
|
+
base_classes: BaseClasses,
|
|
232
|
+
body: Optional[EnumBlock],
|
|
233
|
+
"""
|
|
234
|
+
name = node.name.value
|
|
235
|
+
decl = self.sym_tab.lookup(name)
|
|
236
|
+
if decl and decl.has_decl:
|
|
237
|
+
self.error(
|
|
238
|
+
f"Enum bound with name {name} already defined on Line {decl.node.line}."
|
|
239
|
+
)
|
|
240
|
+
elif decl and decl.has_def:
|
|
241
|
+
decl.has_decl = True
|
|
242
|
+
decl.node = node
|
|
243
|
+
decl.node.body = (
|
|
244
|
+
decl.other_node.body
|
|
245
|
+
if type(decl.other_node) == ast.EnumDef
|
|
246
|
+
else self.ice("Expected node of type EnumDef in symbol table.")
|
|
247
|
+
)
|
|
248
|
+
ast.append_node(decl.node, decl.other_node)
|
|
249
|
+
self.sym_tab.set(decl)
|
|
250
|
+
else:
|
|
251
|
+
decl = DefDeclSymbol(name=name, node=node, has_decl=True)
|
|
252
|
+
if node.body:
|
|
253
|
+
decl.has_def = True
|
|
254
|
+
decl.other_node = node
|
|
255
|
+
self.sym_tab.set(decl)
|
|
256
|
+
|
|
257
|
+
def exit_enum_def(self, node: ast.EnumDef) -> None:
|
|
258
|
+
"""Sub objects.
|
|
259
|
+
|
|
260
|
+
doc: Optional[DocString],
|
|
261
|
+
enum: "EnumRef",
|
|
262
|
+
mod: Optional["NameList"],
|
|
263
|
+
body: "EnumBlock",
|
|
264
|
+
"""
|
|
265
|
+
name = node.enum.name.value
|
|
266
|
+
decl = self.sym_tab.lookup(name)
|
|
267
|
+
if decl and decl.has_def:
|
|
268
|
+
self.error(
|
|
269
|
+
f"Enum bound with name {name} already defined on Line {decl.other_node.line}."
|
|
270
|
+
)
|
|
271
|
+
elif decl and decl.has_decl:
|
|
272
|
+
decl.has_def = True
|
|
273
|
+
decl.other_node = node
|
|
274
|
+
decl.node.body = decl.other_node.body
|
|
275
|
+
ast.append_node(decl.node, decl.other_node)
|
|
276
|
+
self.sym_tab.set(decl)
|
|
277
|
+
else:
|
|
278
|
+
self.sym_tab.set(DefDeclSymbol(name=name, other_node=node, has_def=True))
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Static Import Pass."""
|
|
2
|
+
from os import path
|
|
3
|
+
|
|
4
|
+
import jaclang.jac.absyntree as ast
|
|
5
|
+
from jaclang.jac.passes import Pass
|
|
6
|
+
from jaclang.jac.passes.blue import SubNodeTabPass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ImportPass(Pass):
|
|
10
|
+
"""Jac statically imports all modules."""
|
|
11
|
+
|
|
12
|
+
def before_pass(self) -> None:
|
|
13
|
+
"""Run once before pass."""
|
|
14
|
+
self.import_table = {}
|
|
15
|
+
|
|
16
|
+
def enter_module(self, node: ast.Module) -> None:
|
|
17
|
+
"""Run Importer."""
|
|
18
|
+
self.cur_node = node
|
|
19
|
+
self.terminate() # Turns off auto traversal for deliberate traversal
|
|
20
|
+
self.run_again = True
|
|
21
|
+
while self.run_again:
|
|
22
|
+
self.run_again = False
|
|
23
|
+
for i in self.get_all_sub_nodes(node, ast.Import):
|
|
24
|
+
if i.lang.value == "jac" and not i.sub_module:
|
|
25
|
+
self.run_again = True
|
|
26
|
+
ast.append_node(i, self.import_module(i, node.mod_path))
|
|
27
|
+
i.sub_module = i.kid[-1]
|
|
28
|
+
self.enter_import(i)
|
|
29
|
+
SubNodeTabPass(mod_path=node.mod_path, input_ir=node)
|
|
30
|
+
|
|
31
|
+
def enter_import(self, node: ast.Import) -> None:
|
|
32
|
+
"""Sub objects.
|
|
33
|
+
|
|
34
|
+
lang: Name,
|
|
35
|
+
path: ModulePath,
|
|
36
|
+
alias: Optional[Name],
|
|
37
|
+
items: Optional[ModuleItems], # Items matched during def/decl pass
|
|
38
|
+
is_absorb: bool,
|
|
39
|
+
self.sub_module = None
|
|
40
|
+
"""
|
|
41
|
+
self.cur_node = node
|
|
42
|
+
if node.alias and node.sub_module:
|
|
43
|
+
node.sub_module.name = node.alias.value
|
|
44
|
+
# Items matched during def/decl pass
|
|
45
|
+
|
|
46
|
+
# Utility functions
|
|
47
|
+
# -----------------
|
|
48
|
+
|
|
49
|
+
def import_module(self, node: ast.Import, mod_path: str) -> ast.AstNode:
|
|
50
|
+
"""Import a module."""
|
|
51
|
+
from jaclang.jac.transpiler import jac_file_to_pass
|
|
52
|
+
from jaclang.jac.passes.blue.ast_build_pass import AstBuildPass
|
|
53
|
+
|
|
54
|
+
base_dir = path.dirname(mod_path)
|
|
55
|
+
target = path.normpath(
|
|
56
|
+
path.normpath(
|
|
57
|
+
path.join(base_dir, *(node.path.path_str.split("."))) + ".jac"
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
if target in self.import_table:
|
|
61
|
+
# self.warning(f"Circular import detected, module {target} already imported.")
|
|
62
|
+
return self.import_table[target]
|
|
63
|
+
|
|
64
|
+
if not path.exists(target):
|
|
65
|
+
self.error(f"Could not find module {target}")
|
|
66
|
+
mod = jac_file_to_pass(
|
|
67
|
+
file_path=target, base_dir=base_dir, target=AstBuildPass
|
|
68
|
+
).ir
|
|
69
|
+
if isinstance(mod, ast.Module):
|
|
70
|
+
self.import_table[target] = mod
|
|
71
|
+
mod.is_imported = True
|
|
72
|
+
else:
|
|
73
|
+
self.error(f"Module {target} is not a valid Jac module.")
|
|
74
|
+
raise Exception(f"Module {target} is not a valid Jac module.")
|
|
75
|
+
return mod
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Subnode Table building pass."""
|
|
2
|
+
from copy import copy
|
|
3
|
+
|
|
4
|
+
import jaclang.jac.absyntree as ast
|
|
5
|
+
from jaclang.jac.passes import Pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SubNodeTabPass(Pass):
|
|
9
|
+
"""AST Enrichment Pass for basic high level semantics."""
|
|
10
|
+
|
|
11
|
+
def enter_node(self, node: ast.AstNode) -> None:
|
|
12
|
+
"""Table builder."""
|
|
13
|
+
super().enter_node(node)
|
|
14
|
+
node._sub_node_tab = {} # clears on entry
|
|
15
|
+
|
|
16
|
+
def exit_node(self, node: ast.AstNode) -> None:
|
|
17
|
+
"""Table builder."""
|
|
18
|
+
super().exit_node(node)
|
|
19
|
+
for i in node.kid:
|
|
20
|
+
if not i:
|
|
21
|
+
continue
|
|
22
|
+
for k, v in i._sub_node_tab.items():
|
|
23
|
+
if k in node._sub_node_tab:
|
|
24
|
+
node._sub_node_tab[k].extend(v)
|
|
25
|
+
else:
|
|
26
|
+
node._sub_node_tab[k] = copy(v)
|
|
27
|
+
if type(i) in node._sub_node_tab:
|
|
28
|
+
node._sub_node_tab[type(i)].append(i)
|
|
29
|
+
else:
|
|
30
|
+
node._sub_node_tab[type(i)] = [i]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tests for Jac passes."""
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Test ast build pass module."""
|
|
2
|
+
import inspect
|
|
3
|
+
|
|
4
|
+
from jaclang.jac.lexer import JacLexer
|
|
5
|
+
from jaclang.jac.parser import JacParser
|
|
6
|
+
from jaclang.jac.passes.blue import AstBuildPass
|
|
7
|
+
from jaclang.utils.fstring_parser import FStringParser
|
|
8
|
+
from jaclang.utils.test import TestCaseMicroSuite
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AstBuildPassTests(TestCaseMicroSuite):
|
|
12
|
+
"""Test pass module."""
|
|
13
|
+
|
|
14
|
+
def setUp(self) -> None:
|
|
15
|
+
"""Set up test."""
|
|
16
|
+
return super().setUp()
|
|
17
|
+
|
|
18
|
+
def test_pass_grammar_complete(self) -> None:
|
|
19
|
+
"""Test for enter/exit name diffs with parser."""
|
|
20
|
+
from jaclang.jac.parser import JacParser
|
|
21
|
+
|
|
22
|
+
parser_func_names = []
|
|
23
|
+
for name, value in [
|
|
24
|
+
*inspect.getmembers(JacParser),
|
|
25
|
+
*inspect.getmembers(FStringParser),
|
|
26
|
+
]:
|
|
27
|
+
if (
|
|
28
|
+
inspect.isfunction(value)
|
|
29
|
+
and value.__qualname__.split(".")[0]
|
|
30
|
+
in [JacParser.__name__, FStringParser.__name__]
|
|
31
|
+
and name not in ["__init__", "error", "transform"]
|
|
32
|
+
):
|
|
33
|
+
parser_func_names.append(name)
|
|
34
|
+
ast_build_func_names = []
|
|
35
|
+
for name, value in inspect.getmembers(AstBuildPass):
|
|
36
|
+
if (
|
|
37
|
+
(name.startswith("enter_") or name.startswith("exit_"))
|
|
38
|
+
and inspect.isfunction(value)
|
|
39
|
+
and not getattr(AstBuildPass.__base__, value.__name__, False)
|
|
40
|
+
and value.__qualname__.split(".")[0]
|
|
41
|
+
== AstBuildPass.__name__.replace("enter_", "").replace("exit_", "")
|
|
42
|
+
):
|
|
43
|
+
ast_build_func_names.append(
|
|
44
|
+
name.replace("enter_", "").replace("exit_", "")
|
|
45
|
+
)
|
|
46
|
+
for name in ast_build_func_names:
|
|
47
|
+
self.assertIn(name, parser_func_names)
|
|
48
|
+
for name in parser_func_names:
|
|
49
|
+
self.assertIn(name, ast_build_func_names)
|
|
50
|
+
|
|
51
|
+
def micro_suite_test(self, filename: str) -> None:
|
|
52
|
+
"""Parse micro jac file."""
|
|
53
|
+
lex = JacLexer(mod_path=f"{filename}", input_ir=self.file_to_str(filename)).ir
|
|
54
|
+
prse = JacParser(mod_path=f"{filename}", input_ir=lex).ir
|
|
55
|
+
build_pass = AstBuildPass(mod_path="", input_ir=prse).ir
|
|
56
|
+
self.assertIsNotNone(build_pass)
|
|
57
|
+
if build_pass:
|
|
58
|
+
self.assertGreater(len(str(build_pass.to_dict())), 200)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
AstBuildPassTests.self_attach_micro_tests()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Test ast build pass module."""
|
|
2
|
+
import inspect
|
|
3
|
+
|
|
4
|
+
from jaclang.jac.passes.blue import BluePygenPass
|
|
5
|
+
from jaclang.jac.transpiler import jac_file_to_pass, transpile_jac_blue
|
|
6
|
+
from jaclang.jac.utils import get_ast_nodes_as_snake_case as ast_snakes
|
|
7
|
+
from jaclang.utils.test import TestCaseMicroSuite
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BluePygenPassTests(TestCaseMicroSuite):
|
|
11
|
+
"""Test pass module."""
|
|
12
|
+
|
|
13
|
+
def setUp(self) -> None:
|
|
14
|
+
"""Set up test."""
|
|
15
|
+
return super().setUp()
|
|
16
|
+
|
|
17
|
+
def test_jac_cli(self) -> None:
|
|
18
|
+
"""Basic test for pass."""
|
|
19
|
+
code_gen = jac_file_to_pass(
|
|
20
|
+
self.fixture_abs_path("../../../../../cli/cli.jac"), target=BluePygenPass
|
|
21
|
+
)
|
|
22
|
+
self.assertFalse(code_gen.errors_had)
|
|
23
|
+
|
|
24
|
+
def test_pipe_operator(self) -> None:
|
|
25
|
+
"""Basic test for pass."""
|
|
26
|
+
code_gen = jac_file_to_pass(
|
|
27
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
28
|
+
)
|
|
29
|
+
self.assertFalse(code_gen.errors_had)
|
|
30
|
+
self.assertIn(
|
|
31
|
+
'say((dump(print(len)))({"name": "value"}))', code_gen.ir.meta["py_code"]
|
|
32
|
+
)
|
|
33
|
+
self.assertIn(
|
|
34
|
+
'{"name": "value"}(len(print(print(print))))', code_gen.ir.meta["py_code"]
|
|
35
|
+
)
|
|
36
|
+
self.assertIn("a = (5 + 10) * 2", code_gen.ir.meta["py_code"])
|
|
37
|
+
|
|
38
|
+
def test_atomic_pipe_operator(self) -> None:
|
|
39
|
+
"""Basic test for pass."""
|
|
40
|
+
code_gen = jac_file_to_pass(
|
|
41
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
42
|
+
)
|
|
43
|
+
self.assertFalse(code_gen.errors_had)
|
|
44
|
+
self.assertIn(
|
|
45
|
+
'say((dump(print)(len))({"name": "value"}))', code_gen.ir.meta["py_code"]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def test_pipe_operator_multi_param(self) -> None:
|
|
49
|
+
"""Basic test for pass."""
|
|
50
|
+
code_gen = jac_file_to_pass(
|
|
51
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
52
|
+
)
|
|
53
|
+
self.assertFalse(code_gen.errors_had)
|
|
54
|
+
self.assertIn("self.func(*args, **kwargs)", code_gen.ir.meta["py_code"])
|
|
55
|
+
self.assertIn("inspect.signature(func)", code_gen.ir.meta["py_code"])
|
|
56
|
+
self.assertIn("self.registry.items()", code_gen.ir.meta["py_code"])
|
|
57
|
+
|
|
58
|
+
def test_with_stmt(self) -> None:
|
|
59
|
+
"""Basic test for pass."""
|
|
60
|
+
code_gen = jac_file_to_pass(
|
|
61
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
62
|
+
)
|
|
63
|
+
self.assertFalse(code_gen.errors_had)
|
|
64
|
+
self.assertIn(
|
|
65
|
+
'with open("file.txt") as f, open("file2.txt") as f:',
|
|
66
|
+
code_gen.ir.meta["py_code"],
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def test_empty_codeblock(self) -> None:
|
|
70
|
+
"""Basic test for pass."""
|
|
71
|
+
code_gen = jac_file_to_pass(
|
|
72
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
73
|
+
)
|
|
74
|
+
self.assertFalse(code_gen.errors_had)
|
|
75
|
+
self.assertIn("pass", code_gen.ir.meta["py_code"])
|
|
76
|
+
|
|
77
|
+
def test_enum_gen(self) -> None:
|
|
78
|
+
"""Basic test for pass."""
|
|
79
|
+
code_gen = jac_file_to_pass(
|
|
80
|
+
self.fixture_abs_path("codegentext.jac"), target=BluePygenPass
|
|
81
|
+
)
|
|
82
|
+
self.assertFalse(code_gen.errors_had)
|
|
83
|
+
self.assertIn(
|
|
84
|
+
"from enum import Enum as __jac_Enum__, auto as __jac_auto__",
|
|
85
|
+
code_gen.ir.meta["py_code"],
|
|
86
|
+
)
|
|
87
|
+
self.assertIn("class Color(__jac_Enum__):", code_gen.ir.meta["py_code"])
|
|
88
|
+
self.assertIn("GREEN = __jac_auto__()", code_gen.ir.meta["py_code"])
|
|
89
|
+
self.assertIn("RED = 1", code_gen.ir.meta["py_code"])
|
|
90
|
+
|
|
91
|
+
def test_pass_ast_complete(self) -> None:
|
|
92
|
+
"""Test for enter/exit name diffs with parser."""
|
|
93
|
+
ast_func_names = [
|
|
94
|
+
x for x in ast_snakes() if x not in ["ast_node", "o_o_p_access_node"]
|
|
95
|
+
]
|
|
96
|
+
pygen_func_names = []
|
|
97
|
+
for name, value in inspect.getmembers(BluePygenPass):
|
|
98
|
+
if (
|
|
99
|
+
(name.startswith("enter_") or name.startswith("exit_"))
|
|
100
|
+
and inspect.isfunction(value)
|
|
101
|
+
and not getattr(BluePygenPass.__base__, value.__name__, False)
|
|
102
|
+
and value.__qualname__.split(".")[0]
|
|
103
|
+
== BluePygenPass.__name__.replace("enter_", "").replace("exit_", "")
|
|
104
|
+
):
|
|
105
|
+
pygen_func_names.append(name.replace("enter_", "").replace("exit_", ""))
|
|
106
|
+
for name in pygen_func_names:
|
|
107
|
+
self.assertIn(name, ast_func_names)
|
|
108
|
+
for name in ast_func_names:
|
|
109
|
+
self.assertIn(name, pygen_func_names)
|
|
110
|
+
|
|
111
|
+
def micro_suite_test(self, filename: str) -> None:
|
|
112
|
+
"""Parse micro jac file."""
|
|
113
|
+
code_gen = transpile_jac_blue(filename, "")
|
|
114
|
+
self.assertGreater(len(code_gen), 10)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
BluePygenPassTests.self_attach_micro_tests()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Test pass module."""
|
|
2
|
+
from jaclang.jac.passes.blue import DeclDefMatchPass
|
|
3
|
+
from jaclang.jac.transpiler import jac_file_to_pass
|
|
4
|
+
from jaclang.utils.test import TestCase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DeclDefMatchPassTests(TestCase):
|
|
8
|
+
"""Test pass module."""
|
|
9
|
+
|
|
10
|
+
def setUp(self) -> None:
|
|
11
|
+
"""Set up test."""
|
|
12
|
+
return super().setUp()
|
|
13
|
+
|
|
14
|
+
def test_import_values_avail(self) -> None:
|
|
15
|
+
"""Basic test for pass."""
|
|
16
|
+
state = jac_file_to_pass(
|
|
17
|
+
self.fixture_abs_path("base.jac"), "", DeclDefMatchPass
|
|
18
|
+
)
|
|
19
|
+
self.assertFalse(state.errors_had)
|
|
20
|
+
self.assertIn("mine", state.sym_tab.tab)
|
|
21
|
+
self.assertIsNotNone(state.sym_tab.tab["mine"].node.body)
|
|
22
|
+
|
|
23
|
+
def test_ability_connected_to_decl(self) -> None:
|
|
24
|
+
"""Basic test for pass."""
|
|
25
|
+
state = jac_file_to_pass(
|
|
26
|
+
self.fixture_abs_path("base.jac"), "", DeclDefMatchPass
|
|
27
|
+
)
|
|
28
|
+
self.assertFalse(state.errors_had)
|
|
29
|
+
self.assertIn("Test.say_hi", state.sym_tab.tab)
|
|
30
|
+
self.assertIsNotNone(state.sym_tab.tab["Test.say_hi"].node.body)
|
|
31
|
+
self.assertIn("Test.init", state.sym_tab.tab)
|
|
32
|
+
self.assertIsNotNone(state.sym_tab.tab["Test.init"].node.body)
|
|
33
|
+
|
|
34
|
+
def test_collision_error_correct(self) -> None:
|
|
35
|
+
"""Basic test for multi defs."""
|
|
36
|
+
state = jac_file_to_pass(
|
|
37
|
+
self.fixture_abs_path("decls.jac"), "", DeclDefMatchPass
|
|
38
|
+
)
|
|
39
|
+
self.assertTrue(state.errors_had)
|
|
40
|
+
self.assertIn("/impl/defs2.jac", state.errors_had[0])
|
|
41
|
+
self.assertIn("/impl/defs1.jac", state.errors_had[0])
|
|
42
|
+
self.assertIn("/impl/defs2.jac", state.errors_had[1])
|
|
43
|
+
self.assertIn("/impl/defs1.jac", state.errors_had[1])
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Test pass module."""
|
|
2
|
+
from jaclang.jac.passes.blue import ImportPass
|
|
3
|
+
from jaclang.jac.transpiler import jac_file_to_pass
|
|
4
|
+
from jaclang.utils.test import TestCase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImportPassPassTests(TestCase):
|
|
8
|
+
"""Test pass module."""
|
|
9
|
+
|
|
10
|
+
def setUp(self) -> None:
|
|
11
|
+
"""Set up test."""
|
|
12
|
+
return super().setUp()
|
|
13
|
+
|
|
14
|
+
def test_pygen_jac_cli(self) -> None:
|
|
15
|
+
"""Basic test for pass."""
|
|
16
|
+
state = jac_file_to_pass(self.fixture_abs_path("base.jac"), "", ImportPass)
|
|
17
|
+
self.assertFalse(state.errors_had)
|
|
18
|
+
self.assertIn("56", str(state.ir.to_dict()))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Test sub node pass module."""
|
|
2
|
+
|
|
3
|
+
from jaclang.jac.passes.blue import SubNodeTabPass
|
|
4
|
+
from jaclang.jac.transpiler import jac_file_to_pass
|
|
5
|
+
from jaclang.utils.test import TestCase
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SubNodePassTests(TestCase):
|
|
9
|
+
"""Test pass module."""
|
|
10
|
+
|
|
11
|
+
def setUp(self) -> None:
|
|
12
|
+
"""Set up test."""
|
|
13
|
+
return super().setUp()
|
|
14
|
+
|
|
15
|
+
def test_sub_node_pass(self) -> None:
|
|
16
|
+
"""Basic test for pass."""
|
|
17
|
+
code_gen = jac_file_to_pass(
|
|
18
|
+
file_path=self.fixture_abs_path("../../../../../cli/cli.jac"),
|
|
19
|
+
base_dir="",
|
|
20
|
+
target=SubNodeTabPass,
|
|
21
|
+
)
|
|
22
|
+
for i in code_gen.ir.kid[1].kid:
|
|
23
|
+
for k, v in i._sub_node_tab.items():
|
|
24
|
+
for n in v:
|
|
25
|
+
self.assertIn(n, code_gen.get_all_sub_nodes(i, k, brute_force=True))
|
|
26
|
+
self.assertFalse(code_gen.errors_had)
|