jaclang 0.7.16__py3-none-any.whl → 0.7.18__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 +140 -77
- jaclang/compiler/absyntree.py +9 -4
- jaclang/compiler/constant.py +8 -8
- jaclang/compiler/parser.py +10 -2
- jaclang/compiler/passes/main/__init__.py +1 -1
- jaclang/compiler/passes/main/access_modifier_pass.py +96 -147
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +152 -50
- jaclang/compiler/passes/main/import_pass.py +88 -59
- jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +46 -6
- jaclang/compiler/passes/main/pyast_load_pass.py +1 -0
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
- jaclang/compiler/passes/main/schedules.py +9 -2
- jaclang/compiler/passes/main/sym_tab_build_pass.py +9 -5
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.empty.impl.jac +0 -0
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.jac +1 -1
- jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac +29 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/color.py +3 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/constants.py +5 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/display.py +2 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +72 -13
- jaclang/compiler/passes/main/type_check_pass.py +15 -5
- jaclang/compiler/passes/tool/jac_formatter_pass.py +13 -3
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
- jaclang/compiler/symtable.py +16 -11
- jaclang/compiler/tests/test_importer.py +17 -9
- jaclang/langserve/engine.py +64 -16
- jaclang/langserve/server.py +16 -1
- jaclang/langserve/tests/fixtures/import_include_statements.jac +3 -3
- jaclang/langserve/tests/fixtures/rename.jac +30 -0
- jaclang/langserve/tests/test_server.py +224 -6
- jaclang/langserve/utils.py +28 -98
- jaclang/plugin/builtin.py +8 -4
- jaclang/plugin/default.py +86 -64
- jaclang/plugin/feature.py +13 -13
- jaclang/plugin/spec.py +10 -11
- jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
- jaclang/plugin/tests/test_jaseci.py +414 -42
- jaclang/runtimelib/architype.py +481 -333
- jaclang/runtimelib/constructs.py +5 -8
- jaclang/runtimelib/context.py +89 -69
- jaclang/runtimelib/importer.py +16 -15
- jaclang/runtimelib/machine.py +66 -2
- jaclang/runtimelib/memory.py +134 -75
- jaclang/runtimelib/utils.py +17 -10
- jaclang/settings.py +2 -4
- jaclang/tests/fixtures/access_checker.jac +12 -17
- jaclang/tests/fixtures/access_modifier.jac +88 -33
- jaclang/tests/fixtures/baddy.jac +3 -0
- jaclang/tests/fixtures/bar.jac +34 -0
- jaclang/tests/fixtures/builtin_dotgen.jac +1 -0
- jaclang/tests/fixtures/edge_node_walk.jac +1 -1
- jaclang/tests/fixtures/edge_ops.jac +1 -1
- jaclang/tests/fixtures/edges_walk.jac +1 -1
- jaclang/tests/fixtures/foo.jac +43 -0
- jaclang/tests/fixtures/game1.jac +1 -1
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/import.jac +9 -0
- jaclang/tests/fixtures/index_slice.jac +30 -0
- jaclang/tests/fixtures/objref.jac +12 -0
- jaclang/tests/fixtures/pyfunc_1.py +1 -1
- jaclang/tests/fixtures/pyfunc_2.py +2 -2
- jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
- jaclang/tests/fixtures/pygame_mock/color.py +3 -0
- jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
- jaclang/tests/fixtures/pygame_mock/display.py +2 -0
- jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
- jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
- jaclang/tests/test_cli.py +49 -6
- jaclang/tests/test_language.py +126 -80
- jaclang/tests/test_reference.py +2 -9
- jaclang/utils/treeprinter.py +30 -3
- {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/METADATA +3 -1
- {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/RECORD +81 -59
- /jaclang/tests/fixtures/{err.test.jac → baddy.test.jac} +0 -0
- {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/WHEEL +0 -0
- {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/entry_points.txt +0 -0
|
@@ -6,19 +6,16 @@ symbols are available for matching.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import ast as py_ast
|
|
9
|
-
import importlib.util
|
|
10
9
|
import os
|
|
11
|
-
import sys
|
|
12
10
|
from typing import Optional
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
import jaclang.compiler.absyntree as ast
|
|
16
14
|
from jaclang.compiler.passes import Pass
|
|
17
|
-
from jaclang.compiler.passes.main import SubNodeTabPass
|
|
18
|
-
from jaclang.settings import settings
|
|
19
|
-
from jaclang.utils.helpers import is_standard_lib_module
|
|
15
|
+
from jaclang.compiler.passes.main import SubNodeTabPass, SymTabBuildPass
|
|
20
16
|
from jaclang.utils.log import logging
|
|
21
17
|
|
|
18
|
+
|
|
22
19
|
logger = logging.getLogger(__name__)
|
|
23
20
|
|
|
24
21
|
|
|
@@ -28,37 +25,29 @@ class JacImportPass(Pass):
|
|
|
28
25
|
def before_pass(self) -> None:
|
|
29
26
|
"""Run once before pass."""
|
|
30
27
|
self.import_table: dict[str, ast.Module] = {}
|
|
31
|
-
self.__py_imports: set[str] = set()
|
|
32
|
-
self.py_resolve_list: set[str] = set()
|
|
33
28
|
|
|
34
29
|
def enter_module(self, node: ast.Module) -> None:
|
|
35
30
|
"""Run Importer."""
|
|
36
31
|
self.cur_node = node
|
|
37
32
|
self.import_table[node.loc.mod_path] = node
|
|
38
|
-
self.
|
|
39
|
-
self.__annex_impl(node)
|
|
33
|
+
self.annex_impl(node)
|
|
40
34
|
self.terminate() # Turns off auto traversal for deliberate traversal
|
|
41
35
|
self.run_again = True
|
|
42
36
|
while self.run_again:
|
|
43
37
|
self.run_again = False
|
|
44
38
|
all_imports = self.get_all_sub_nodes(node, ast.ModulePath)
|
|
45
39
|
for i in all_imports:
|
|
46
|
-
self.process_import(
|
|
40
|
+
self.process_import(i)
|
|
47
41
|
self.enter_module_path(i)
|
|
48
42
|
SubNodeTabPass(prior=self, input_ir=node)
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
self.enter_atom_trailer(i)
|
|
52
|
-
|
|
53
|
-
node.mod_deps = self.import_table
|
|
44
|
+
node.mod_deps.update(self.import_table)
|
|
54
45
|
|
|
55
|
-
def process_import(self,
|
|
46
|
+
def process_import(self, i: ast.ModulePath) -> None:
|
|
56
47
|
"""Process an import."""
|
|
57
48
|
imp_node = i.parent_of_type(ast.Import)
|
|
58
49
|
if imp_node.is_jac and not i.sub_module:
|
|
59
50
|
self.import_jac_module(node=i)
|
|
60
|
-
elif imp_node.is_py:
|
|
61
|
-
self.__py_imports.add(i.path_str)
|
|
62
51
|
|
|
63
52
|
def attach_mod_to_node(
|
|
64
53
|
self, node: ast.ModulePath | ast.ModuleItem, mod: ast.Module | None
|
|
@@ -67,10 +56,11 @@ class JacImportPass(Pass):
|
|
|
67
56
|
if mod:
|
|
68
57
|
self.run_again = True
|
|
69
58
|
node.sub_module = mod
|
|
70
|
-
self.
|
|
59
|
+
self.annex_impl(mod)
|
|
71
60
|
node.add_kids_right([mod], pos_update=False)
|
|
61
|
+
mod.parent = node
|
|
72
62
|
|
|
73
|
-
def
|
|
63
|
+
def annex_impl(self, node: ast.Module) -> None:
|
|
74
64
|
"""Annex impl and test modules."""
|
|
75
65
|
if node.stub_only:
|
|
76
66
|
return
|
|
@@ -131,11 +121,6 @@ class JacImportPass(Pass):
|
|
|
131
121
|
node.sub_module.name = node.alias.value
|
|
132
122
|
# Items matched during def/decl pass
|
|
133
123
|
|
|
134
|
-
def enter_atom_trailer(self, node: ast.AtomTrailer) -> None:
|
|
135
|
-
"""Iterate on AtomTrailer nodes to get python paths to resolve."""
|
|
136
|
-
if node.as_attr_list[0].sym_name in self.__py_imports:
|
|
137
|
-
self.py_resolve_list.add(".".join([i.sym_name for i in node.as_attr_list]))
|
|
138
|
-
|
|
139
124
|
def import_jac_module(self, node: ast.ModulePath) -> None:
|
|
140
125
|
"""Import a module."""
|
|
141
126
|
self.cur_node = node # impacts error reporting
|
|
@@ -214,58 +199,102 @@ class PyImportPass(JacImportPass):
|
|
|
214
199
|
def before_pass(self) -> None:
|
|
215
200
|
"""Only run pass if settings are set to raise python."""
|
|
216
201
|
super().before_pass()
|
|
217
|
-
if not settings.py_raise:
|
|
218
|
-
self.terminate()
|
|
219
202
|
|
|
220
|
-
def
|
|
203
|
+
def __get_current_module(self, node: ast.AstNode) -> str:
|
|
204
|
+
parent = node.find_parent_of_type(ast.Module)
|
|
205
|
+
mod_list = []
|
|
206
|
+
while parent is not None:
|
|
207
|
+
mod_list.append(parent)
|
|
208
|
+
parent = parent.find_parent_of_type(ast.Module)
|
|
209
|
+
mod_list.reverse()
|
|
210
|
+
return ".".join(p.name for p in mod_list)
|
|
211
|
+
|
|
212
|
+
def process_import(self, i: ast.ModulePath) -> None:
|
|
221
213
|
"""Process an import."""
|
|
214
|
+
# Process import is orginally implemented to handle ModulePath in Jaclang
|
|
215
|
+
# This won't work with py imports as this will fail to import stuff in form of
|
|
216
|
+
# from a import b
|
|
217
|
+
# from a import (c, d, e)
|
|
218
|
+
# Solution to that is to get the import node and check the from loc then
|
|
219
|
+
# handle it based on if there a from loc or not
|
|
222
220
|
imp_node = i.parent_of_type(ast.Import)
|
|
223
|
-
if
|
|
224
|
-
imp_node.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
221
|
+
if imp_node.is_py and not i.sub_module:
|
|
222
|
+
if imp_node.from_loc:
|
|
223
|
+
for j in imp_node.items.items:
|
|
224
|
+
assert isinstance(j, ast.ModuleItem)
|
|
225
|
+
mod_path = f"{imp_node.from_loc.dot_path_str}.{j.name.sym_name}"
|
|
226
|
+
self.import_py_module(
|
|
227
|
+
parent_node=j,
|
|
228
|
+
mod_path=mod_path,
|
|
229
|
+
imported_mod_name=(
|
|
230
|
+
j.name.sym_name if not j.alias else j.alias.sym_name
|
|
231
|
+
),
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
for j in imp_node.items.items:
|
|
235
|
+
assert isinstance(j, ast.ModulePath)
|
|
236
|
+
self.import_py_module(
|
|
237
|
+
parent_node=j,
|
|
238
|
+
mod_path=j.dot_path_str,
|
|
239
|
+
imported_mod_name=(
|
|
240
|
+
j.dot_path_str.replace(".", "")
|
|
241
|
+
if not j.alias
|
|
242
|
+
else j.alias.sym_name
|
|
243
|
+
),
|
|
244
|
+
)
|
|
234
245
|
|
|
235
246
|
def import_py_module(
|
|
236
|
-
self,
|
|
247
|
+
self,
|
|
248
|
+
parent_node: ast.ModulePath | ast.ModuleItem,
|
|
249
|
+
imported_mod_name: str,
|
|
250
|
+
mod_path: str,
|
|
237
251
|
) -> Optional[ast.Module]:
|
|
238
252
|
"""Import a module."""
|
|
239
253
|
from jaclang.compiler.passes.main import PyastBuildPass
|
|
240
254
|
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
assert isinstance(self.ir, ast.Module)
|
|
256
|
+
|
|
257
|
+
python_raise_map = self.ir.py_raise_map
|
|
258
|
+
file_to_raise = None
|
|
259
|
+
|
|
260
|
+
if mod_path in python_raise_map:
|
|
261
|
+
file_to_raise = python_raise_map[mod_path]
|
|
262
|
+
else:
|
|
263
|
+
resolved_mod_path = (
|
|
264
|
+
f"{self.__get_current_module(parent_node)}.{imported_mod_name}"
|
|
265
|
+
)
|
|
266
|
+
assert isinstance(self.ir, ast.Module)
|
|
267
|
+
resolved_mod_path = resolved_mod_path.replace(f"{self.ir.name}.", "")
|
|
268
|
+
file_to_raise = python_raise_map.get(resolved_mod_path)
|
|
269
|
+
|
|
270
|
+
if file_to_raise is None:
|
|
271
|
+
return None
|
|
272
|
+
|
|
243
273
|
try:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return self.import_table[spec.origin]
|
|
250
|
-
with open(spec.origin, "r", encoding="utf-8") as f:
|
|
274
|
+
if file_to_raise not in {None, "built-in", "frozen"}:
|
|
275
|
+
if file_to_raise in self.import_table:
|
|
276
|
+
return self.import_table[file_to_raise]
|
|
277
|
+
|
|
278
|
+
with open(file_to_raise, "r", encoding="utf-8") as f:
|
|
251
279
|
mod = PyastBuildPass(
|
|
252
280
|
input_ir=ast.PythonModuleAst(
|
|
253
|
-
py_ast.parse(f.read()), mod_path=
|
|
281
|
+
py_ast.parse(f.read()), mod_path=file_to_raise
|
|
254
282
|
),
|
|
255
283
|
).ir
|
|
284
|
+
SubNodeTabPass(input_ir=mod, prior=self)
|
|
256
285
|
if mod:
|
|
257
|
-
|
|
286
|
+
mod.name = imported_mod_name
|
|
287
|
+
self.import_table[file_to_raise] = mod
|
|
288
|
+
self.attach_mod_to_node(parent_node, mod)
|
|
289
|
+
SymTabBuildPass(input_ir=mod, prior=self)
|
|
258
290
|
return mod
|
|
259
291
|
else:
|
|
260
|
-
raise self.ice(
|
|
261
|
-
f"Failed to import python module {node.path_str}: {spec.origin}"
|
|
262
|
-
)
|
|
292
|
+
raise self.ice(f"Failed to import python module {mod_path}")
|
|
263
293
|
except Exception as e:
|
|
264
|
-
|
|
265
|
-
return None
|
|
266
|
-
self.error(
|
|
267
|
-
f"Failed to import python module {node.path_str}: {e}",
|
|
268
|
-
node_override=node,
|
|
269
|
-
)
|
|
294
|
+
self.error(f"Failed to import python module {mod_path}")
|
|
270
295
|
raise e
|
|
271
296
|
return None
|
|
297
|
+
|
|
298
|
+
def annex_impl(self, node: ast.Module) -> None:
|
|
299
|
+
"""Annex impl and test modules."""
|
|
300
|
+
return None
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Collect Python dependencies based on reference sourced from Jac.
|
|
2
|
+
|
|
3
|
+
This pass will use mypy to calculate the python package/module dependencies
|
|
4
|
+
that are only relevant to actual references source from Jac code.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import jaclang.compiler.absyntree as ast
|
|
11
|
+
from jaclang.compiler.passes import Pass
|
|
12
|
+
from jaclang.settings import settings
|
|
13
|
+
|
|
14
|
+
import mypy.nodes as MypyNodes # noqa N812
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PyCollectDepsPass(Pass):
|
|
18
|
+
"""Python and bytecode file self.__debug_printing pass."""
|
|
19
|
+
|
|
20
|
+
def __debug_print(self, msg: str) -> None:
|
|
21
|
+
if settings.collect_py_dep_debug:
|
|
22
|
+
self.log_info("CollectPythonDependencies::" + msg)
|
|
23
|
+
|
|
24
|
+
def enter_node(self, node: ast.AstNode) -> None:
|
|
25
|
+
"""Collect python dependencies from all Jac Nodes."""
|
|
26
|
+
assert isinstance(self.ir, ast.Module)
|
|
27
|
+
|
|
28
|
+
if not isinstance(node, ast.AstSymbolNode):
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
path: str = ""
|
|
32
|
+
if isinstance(node, ast.ModulePath):
|
|
33
|
+
if node.path:
|
|
34
|
+
path = ".".join([i.value for i in node.path])
|
|
35
|
+
node.abs_path = self.ir.py_mod_dep_map.get(path)
|
|
36
|
+
elif isinstance(node, ast.ModuleItem):
|
|
37
|
+
imp = node.parent_of_type(ast.Import)
|
|
38
|
+
mod_path_node = imp.get_all_sub_nodes(ast.ModulePath)[0]
|
|
39
|
+
if mod_path_node.path:
|
|
40
|
+
path = ".".join([i.value for i in mod_path_node.path])
|
|
41
|
+
path += f".{node.name.value}"
|
|
42
|
+
node.abs_path = self.ir.py_mod_dep_map.get(path)
|
|
43
|
+
|
|
44
|
+
if len(node.gen.mypy_ast) == 0:
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
mypy_node = node.gen.mypy_ast[0]
|
|
48
|
+
|
|
49
|
+
if isinstance(mypy_node, MypyNodes.RefExpr) and mypy_node.node:
|
|
50
|
+
node_full_name = mypy_node.node.fullname
|
|
51
|
+
if "." in node_full_name:
|
|
52
|
+
mod_name = node_full_name[: node_full_name.rindex(".")]
|
|
53
|
+
else:
|
|
54
|
+
mod_name = node_full_name
|
|
55
|
+
|
|
56
|
+
if mod_name not in self.ir.py_mod_dep_map:
|
|
57
|
+
self.__debug_print(
|
|
58
|
+
f"Can't find a python file associated with {type(node)}::{node.loc}"
|
|
59
|
+
)
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
mode_path = self.ir.py_mod_dep_map[mod_name]
|
|
63
|
+
if mode_path.endswith(".jac"):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
self.ir.py_raise_map[mod_name] = mode_path
|
|
67
|
+
else:
|
|
68
|
+
self.__debug_print(
|
|
69
|
+
f"Collect python dependencies is not supported in {type(node)}::{node.loc}"
|
|
70
|
+
)
|
|
@@ -529,7 +529,7 @@ class PyastGenPass(Pass):
|
|
|
529
529
|
sub_module: Optional[Module],
|
|
530
530
|
"""
|
|
531
531
|
path_alias: dict[str, Optional[str]] = (
|
|
532
|
-
{node.from_loc.
|
|
532
|
+
{node.from_loc.dot_path_str: None} if node.from_loc else {}
|
|
533
533
|
)
|
|
534
534
|
imp_from = {}
|
|
535
535
|
if node.items:
|
|
@@ -539,7 +539,7 @@ class PyastGenPass(Pass):
|
|
|
539
539
|
item.alias.sym_name if item.alias else None
|
|
540
540
|
)
|
|
541
541
|
elif isinstance(item, ast.ModulePath):
|
|
542
|
-
path_alias[item.
|
|
542
|
+
path_alias[item.dot_path_str] = (
|
|
543
543
|
item.alias.sym_name if item.alias else None
|
|
544
544
|
)
|
|
545
545
|
|
|
@@ -828,7 +828,7 @@ class PyastGenPass(Pass):
|
|
|
828
828
|
typecheck_nodes.append(
|
|
829
829
|
self.sync(
|
|
830
830
|
py_node=ast3.ImportFrom(
|
|
831
|
-
module=(source.
|
|
831
|
+
module=(source.dot_path_str.lstrip(".") if source else None),
|
|
832
832
|
names=[self.sync(ast3.alias(name="*"), node)],
|
|
833
833
|
level=0,
|
|
834
834
|
),
|
|
@@ -842,7 +842,7 @@ class PyastGenPass(Pass):
|
|
|
842
842
|
self.sync(
|
|
843
843
|
ast3.ImportFrom(
|
|
844
844
|
module=(
|
|
845
|
-
node.from_loc.
|
|
845
|
+
node.from_loc.dot_path_str.lstrip(".")
|
|
846
846
|
if node.from_loc
|
|
847
847
|
else None
|
|
848
848
|
),
|
|
@@ -879,7 +879,7 @@ class PyastGenPass(Pass):
|
|
|
879
879
|
node.gen.py_ast = [
|
|
880
880
|
self.sync(
|
|
881
881
|
ast3.alias(
|
|
882
|
-
name=f"{node.
|
|
882
|
+
name=f"{node.dot_path_str}",
|
|
883
883
|
asname=node.alias.sym_name if node.alias else None,
|
|
884
884
|
)
|
|
885
885
|
)
|
|
@@ -2367,7 +2367,22 @@ class PyastGenPass(Pass):
|
|
|
2367
2367
|
node.left.gen.py_ast[0],
|
|
2368
2368
|
node.right.gen.py_ast[0],
|
|
2369
2369
|
self.sync(
|
|
2370
|
-
ast3.
|
|
2370
|
+
ast3.Attribute(
|
|
2371
|
+
value=self.sync(
|
|
2372
|
+
ast3.Attribute(
|
|
2373
|
+
value=self.sync(
|
|
2374
|
+
ast3.Name(
|
|
2375
|
+
id=Con.JAC_FEATURE.value,
|
|
2376
|
+
ctx=ast3.Load(),
|
|
2377
|
+
)
|
|
2378
|
+
),
|
|
2379
|
+
attr="EdgeDir",
|
|
2380
|
+
ctx=ast3.Load(),
|
|
2381
|
+
)
|
|
2382
|
+
),
|
|
2383
|
+
attr=node.op.edge_spec.edge_dir.name,
|
|
2384
|
+
ctx=ast3.Load(),
|
|
2385
|
+
)
|
|
2371
2386
|
),
|
|
2372
2387
|
(
|
|
2373
2388
|
node.op.edge_spec.filter_cond.gen.py_ast[0]
|
|
@@ -2626,6 +2641,31 @@ class PyastGenPass(Pass):
|
|
|
2626
2641
|
]
|
|
2627
2642
|
elif node.op.name in [Tok.STAR_POW]:
|
|
2628
2643
|
node.gen.py_ast = node.operand.gen.py_ast
|
|
2644
|
+
elif node.op.name in [Tok.BW_AND]:
|
|
2645
|
+
node.gen.py_ast = [
|
|
2646
|
+
self.sync(
|
|
2647
|
+
ast3.Call(
|
|
2648
|
+
func=self.sync(
|
|
2649
|
+
ast3.Attribute(
|
|
2650
|
+
value=self.sync(
|
|
2651
|
+
ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
|
|
2652
|
+
),
|
|
2653
|
+
attr="get_object",
|
|
2654
|
+
ctx=ast3.Load(),
|
|
2655
|
+
)
|
|
2656
|
+
),
|
|
2657
|
+
args=[],
|
|
2658
|
+
keywords=[
|
|
2659
|
+
self.sync(
|
|
2660
|
+
ast3.keyword(
|
|
2661
|
+
arg="id",
|
|
2662
|
+
value=node.operand.gen.py_ast[0],
|
|
2663
|
+
)
|
|
2664
|
+
),
|
|
2665
|
+
],
|
|
2666
|
+
)
|
|
2667
|
+
)
|
|
2668
|
+
]
|
|
2629
2669
|
else:
|
|
2630
2670
|
self.ice(f"Unknown Unary operator {node.op.value}")
|
|
2631
2671
|
|
|
@@ -162,6 +162,13 @@ class PyJacAstLinkPass(Pass):
|
|
|
162
162
|
py_nodes=node.parent.signature.return_type.gen.py_ast,
|
|
163
163
|
)
|
|
164
164
|
|
|
165
|
+
if isinstance(node.decl_link, ast.Ability) and isinstance(
|
|
166
|
+
node.target, ast.ArchRefChain
|
|
167
|
+
):
|
|
168
|
+
for arch in node.target.archs:
|
|
169
|
+
if arch.arch_name.sym:
|
|
170
|
+
arch.arch_name.sym.add_use(arch.arch_name)
|
|
171
|
+
|
|
165
172
|
def exit_param_var(self, node: ast.ParamVar) -> None:
|
|
166
173
|
"""Sub objects.
|
|
167
174
|
|
|
@@ -19,11 +19,11 @@ from .type_check_pass import JacTypeCheckPass # noqa: I100
|
|
|
19
19
|
from .fuse_typeinfo_pass import FuseTypeInfoPass # noqa: I100
|
|
20
20
|
from .registry_pass import RegistryPass # noqa: I100
|
|
21
21
|
from .access_modifier_pass import AccessCheckPass # noqa: I100
|
|
22
|
+
from .py_collect_dep_pass import PyCollectDepsPass # noqa: I100
|
|
22
23
|
|
|
23
24
|
py_code_gen = [
|
|
24
25
|
SubNodeTabPass,
|
|
25
26
|
JacImportPass,
|
|
26
|
-
PyImportPass,
|
|
27
27
|
SymTabBuildPass,
|
|
28
28
|
DeclImplMatchPass,
|
|
29
29
|
DefUsePass,
|
|
@@ -33,6 +33,13 @@ py_code_gen = [
|
|
|
33
33
|
PyBytecodeGenPass,
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
-
type_checker_sched = [
|
|
36
|
+
type_checker_sched = [
|
|
37
|
+
JacTypeCheckPass,
|
|
38
|
+
PyCollectDepsPass,
|
|
39
|
+
PyImportPass,
|
|
40
|
+
DefUsePass,
|
|
41
|
+
FuseTypeInfoPass,
|
|
42
|
+
AccessCheckPass,
|
|
43
|
+
]
|
|
37
44
|
py_code_gen_typed = [*py_code_gen, *type_checker_sched]
|
|
38
45
|
py_compiler = [*py_code_gen, PyOutPass]
|
|
@@ -19,12 +19,16 @@ class SymTabBuildPass(Pass):
|
|
|
19
19
|
"""Before pass."""
|
|
20
20
|
self.cur_sym_tab: list[SymbolTable] = []
|
|
21
21
|
|
|
22
|
-
def push_scope(self, name: str, key_node: ast.AstNode
|
|
22
|
+
def push_scope(self, name: str, key_node: ast.AstNode) -> None:
|
|
23
23
|
"""Push scope."""
|
|
24
|
-
|
|
24
|
+
inherit = key_node.parent
|
|
25
|
+
if not len(self.cur_sym_tab) and not inherit:
|
|
25
26
|
self.cur_sym_tab.append(SymbolTable(name, key_node))
|
|
27
|
+
elif not len(self.cur_sym_tab) and inherit:
|
|
28
|
+
self.cur_sym_tab.append(inherit.sym_tab)
|
|
29
|
+
self.cur_sym_tab.append(self.cur_scope.push_kid_scope(name, key_node))
|
|
26
30
|
else:
|
|
27
|
-
self.cur_sym_tab.append(self.cur_scope.
|
|
31
|
+
self.cur_sym_tab.append(self.cur_scope.push_kid_scope(name, key_node))
|
|
28
32
|
|
|
29
33
|
def pop_scope(self) -> SymbolTable:
|
|
30
34
|
"""Pop scope."""
|
|
@@ -48,7 +52,7 @@ class SymTabBuildPass(Pass):
|
|
|
48
52
|
mod_path: str,
|
|
49
53
|
is_imported: bool,
|
|
50
54
|
"""
|
|
51
|
-
self.push_scope(node.name, node
|
|
55
|
+
self.push_scope(node.name, node)
|
|
52
56
|
self.sync_node_to_scope(node)
|
|
53
57
|
for obj in dir(builtins):
|
|
54
58
|
builtin = ast.Name(
|
|
@@ -197,7 +201,7 @@ class SymTabBuildPass(Pass):
|
|
|
197
201
|
source = node.items.items[0]
|
|
198
202
|
if not isinstance(source, ast.ModulePath) or not source.sub_module:
|
|
199
203
|
self.error(
|
|
200
|
-
f"Module {node.from_loc.
|
|
204
|
+
f"Module {node.from_loc.dot_path_str if node.from_loc else 'from location'}"
|
|
201
205
|
f" not found to include *, or ICE occurred!"
|
|
202
206
|
)
|
|
203
207
|
else:
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import:py math;
|
|
2
|
+
import:py argparse;
|
|
3
|
+
import:py from pygame_mock { color, display }
|
|
4
|
+
import:py pygame_mock;
|
|
5
|
+
import:py os;
|
|
6
|
+
|
|
7
|
+
can fool_me -> `Type[pygame_mock.constants.CL] {
|
|
8
|
+
return pygame_mock.constants.CL;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
obj kk {
|
|
12
|
+
can fool_me -> `Type[pygame_mock.constants.CL] {
|
|
13
|
+
return pygame_mock.constants.CL;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
with entry {
|
|
18
|
+
b = math.floor(1.7);
|
|
19
|
+
c: color.Color = color.Color(pygame_mock.constants.CONST_VALUE);
|
|
20
|
+
c2: pygame_mock.color.Color = color.Color(pygame_mock.constants.CL.CONST_VALUE2);
|
|
21
|
+
c3: pygame_mock.color.Color = color.Color(fool_me().CONST_VALUE2);
|
|
22
|
+
c4: pygame_mock.color.Color = color.Color(kk().fool_me().CONST_VALUE2);
|
|
23
|
+
g = fool_me();
|
|
24
|
+
c4: pygame_mock.color.Color = color.Color(g.CONST_VALUE2);
|
|
25
|
+
a: argparse.ArgumentParser = argparse.ArgumentParser();
|
|
26
|
+
print("Hello", 1, b);
|
|
27
|
+
pygame_mock.display.set_mode(WIN_WIDTH, WIN_HEIGHT);
|
|
28
|
+
print(os.path.isfile("/jj"));
|
|
29
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"""Test pass module."""
|
|
2
2
|
|
|
3
|
+
import io
|
|
4
|
+
import re
|
|
5
|
+
import sys
|
|
6
|
+
|
|
3
7
|
import jaclang.compiler.absyntree as ast
|
|
8
|
+
from jaclang.cli import cli
|
|
4
9
|
from jaclang.compiler.compile import jac_file_to_pass
|
|
5
10
|
from jaclang.compiler.passes.main import JacImportPass
|
|
11
|
+
from jaclang.compiler.passes.main.fuse_typeinfo_pass import FuseTypeInfoPass
|
|
12
|
+
from jaclang.compiler.passes.main.schedules import py_code_gen_typed
|
|
6
13
|
from jaclang.utils.test import TestCase
|
|
7
14
|
|
|
8
15
|
|
|
@@ -24,7 +31,7 @@ class ImportPassPassTests(TestCase):
|
|
|
24
31
|
state = jac_file_to_pass(self.fixture_abs_path("autoimpl.jac"), JacImportPass)
|
|
25
32
|
num_modules = len(state.ir.get_all_sub_nodes(ast.Module))
|
|
26
33
|
mod_names = [i.name for i in state.ir.get_all_sub_nodes(ast.Module)]
|
|
27
|
-
self.assertEqual(num_modules,
|
|
34
|
+
self.assertEqual(num_modules, 4)
|
|
28
35
|
self.assertIn("getme.impl", mod_names)
|
|
29
36
|
self.assertIn("autoimpl.impl", mod_names)
|
|
30
37
|
self.assertIn("autoimpl.something.else.impl", mod_names)
|
|
@@ -36,7 +43,7 @@ class ImportPassPassTests(TestCase):
|
|
|
36
43
|
)
|
|
37
44
|
num_modules = len(state.ir.get_all_sub_nodes(ast.Module))
|
|
38
45
|
mod_names = [i.name for i in state.ir.get_all_sub_nodes(ast.Module)]
|
|
39
|
-
self.assertEqual(num_modules,
|
|
46
|
+
self.assertEqual(num_modules, 5)
|
|
40
47
|
self.assertIn("getme.impl", mod_names)
|
|
41
48
|
self.assertIn("autoimpl", mod_names)
|
|
42
49
|
self.assertIn("autoimpl.impl", mod_names)
|
|
@@ -52,17 +59,69 @@ class ImportPassPassTests(TestCase):
|
|
|
52
59
|
if i.name != "autoimpl":
|
|
53
60
|
count += 1
|
|
54
61
|
self.assertEqual(i.annexable_by, self.fixture_abs_path("autoimpl.jac"))
|
|
55
|
-
self.assertEqual(count,
|
|
62
|
+
self.assertEqual(count, 4)
|
|
63
|
+
|
|
64
|
+
def test_py_raise_map(self) -> None:
|
|
65
|
+
"""Basic test for pass."""
|
|
66
|
+
build = jac_file_to_pass(
|
|
67
|
+
self.fixture_abs_path("py_imp_test.jac"),
|
|
68
|
+
FuseTypeInfoPass,
|
|
69
|
+
schedule=py_code_gen_typed,
|
|
70
|
+
)
|
|
71
|
+
assert isinstance(build.ir, ast.Module)
|
|
72
|
+
p = {
|
|
73
|
+
"math": "jaclang/jaclang/vendor/mypy/typeshed/stdlib/math.pyi",
|
|
74
|
+
"pygame_mock": "pygame_mock/__init__.py",
|
|
75
|
+
"pygame_mock.color": "pygame_mock/color.py",
|
|
76
|
+
"pygame_mock.constants": "pygame_mock/constants.py",
|
|
77
|
+
"argparse": "jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi",
|
|
78
|
+
"builtins": "jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi",
|
|
79
|
+
"pygame_mock.display": "pygame_mock/display.py",
|
|
80
|
+
"os": "jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi",
|
|
81
|
+
"genericpath": "jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi",
|
|
82
|
+
}
|
|
83
|
+
for i in p:
|
|
84
|
+
self.assertIn(i, build.ir.py_raise_map)
|
|
85
|
+
self.assertIn(p[i], re.sub(r".*fixtures/", "", build.ir.py_raise_map[i]))
|
|
56
86
|
|
|
57
|
-
def
|
|
87
|
+
def test_py_raised_mods(self) -> None:
|
|
58
88
|
"""Basic test for pass."""
|
|
59
|
-
state
|
|
60
|
-
self.
|
|
61
|
-
|
|
89
|
+
state = jac_file_to_pass(
|
|
90
|
+
self.fixture_abs_path("py_imp_test.jac"), schedule=py_code_gen_typed
|
|
91
|
+
)
|
|
92
|
+
self.assertEqual(
|
|
93
|
+
len(
|
|
94
|
+
list(
|
|
95
|
+
filter(
|
|
96
|
+
lambda x: x.is_raised_from_py,
|
|
97
|
+
state.ir.get_all_sub_nodes(ast.Module),
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
7,
|
|
62
102
|
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
103
|
+
|
|
104
|
+
# def test_py_resolve_list(self) -> None:
|
|
105
|
+
# """Basic test for pass."""
|
|
106
|
+
# state: JacImportPass = jac_file_to_pass(
|
|
107
|
+
# self.examples_abs_path("rpg_game/jac_impl/jac_impl_5/main.jac"),
|
|
108
|
+
# JacImportPass,
|
|
109
|
+
# )
|
|
110
|
+
# self.assertGreater(len(state.py_resolve_list), 20)
|
|
111
|
+
# self.assertIn("pygame.sprite.Sprite.__init__", state.py_resolve_list)
|
|
112
|
+
# self.assertIn("pygame.mouse.get_pressed", state.py_resolve_list)
|
|
113
|
+
# self.assertIn("pygame.K_SPACE", state.py_resolve_list)
|
|
114
|
+
# self.assertIn("random.randint", state.py_resolve_list)
|
|
115
|
+
# self.assertIn("pygame.font.Font", state.py_resolve_list)
|
|
116
|
+
|
|
117
|
+
def test_double_empty_anx(self) -> None:
|
|
118
|
+
"""Test importing python."""
|
|
119
|
+
captured_output = io.StringIO()
|
|
120
|
+
sys.stdout = captured_output
|
|
121
|
+
cli.run(self.fixture_abs_path("autoimpl.jac"))
|
|
122
|
+
cli.run(self.fixture_abs_path("autoimpl.jac"))
|
|
123
|
+
sys.stdout = sys.__stdout__
|
|
124
|
+
stdout_value = captured_output.getvalue()
|
|
125
|
+
self.assertIn("foo", stdout_value)
|
|
126
|
+
self.assertIn("bar", stdout_value)
|
|
127
|
+
self.assertIn("baz", stdout_value)
|