jaclang 0.7.14__py3-none-any.whl → 0.7.17__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 +147 -77
- jaclang/cli/cmdreg.py +9 -12
- jaclang/compiler/__init__.py +19 -53
- jaclang/compiler/absyntree.py +94 -16
- jaclang/compiler/constant.py +8 -8
- jaclang/compiler/jac.lark +4 -3
- jaclang/compiler/parser.py +41 -25
- jaclang/compiler/passes/ir_pass.py +4 -13
- 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 +155 -54
- jaclang/compiler/passes/main/import_pass.py +99 -75
- jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +328 -565
- jaclang/compiler/passes/main/pyast_load_pass.py +33 -6
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
- jaclang/compiler/passes/main/registry_pass.py +37 -3
- jaclang/compiler/passes/main/schedules.py +9 -2
- jaclang/compiler/passes/main/sym_tab_build_pass.py +10 -6
- jaclang/compiler/passes/main/tests/__init__.py +1 -1
- 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 +22 -5
- jaclang/compiler/passes/tool/jac_formatter_pass.py +135 -89
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -42
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
- jaclang/compiler/passes/transform.py +4 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
- jaclang/compiler/semtable.py +31 -7
- jaclang/compiler/symtable.py +16 -11
- jaclang/compiler/tests/test_importer.py +25 -10
- jaclang/langserve/engine.py +104 -118
- jaclang/langserve/sem_manager.py +379 -0
- jaclang/langserve/server.py +24 -11
- jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
- jaclang/langserve/tests/fixtures/rename.jac +30 -0
- jaclang/langserve/tests/test_sem_tokens.py +277 -0
- jaclang/langserve/tests/test_server.py +287 -17
- jaclang/langserve/utils.py +184 -98
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +288 -92
- jaclang/plugin/feature.py +65 -27
- jaclang/plugin/spec.py +62 -23
- jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
- jaclang/plugin/tests/test_jaseci.py +414 -42
- jaclang/runtimelib/architype.py +650 -0
- jaclang/{core → runtimelib}/constructs.py +5 -8
- jaclang/{core → runtimelib}/context.py +86 -59
- jaclang/runtimelib/importer.py +361 -0
- jaclang/runtimelib/machine.py +158 -0
- jaclang/runtimelib/memory.py +158 -0
- jaclang/{core → runtimelib}/utils.py +30 -15
- jaclang/settings.py +5 -4
- jaclang/tests/fixtures/abc.jac +3 -3
- 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/baddy.test.jac +3 -0
- jaclang/tests/fixtures/bar.jac +34 -0
- jaclang/tests/fixtures/byllmissue.jac +1 -5
- jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
- jaclang/tests/fixtures/cls_method.jac +41 -0
- jaclang/tests/fixtures/dblhello.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +3 -3
- jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
- jaclang/tests/fixtures/deep_import_mods.jac +13 -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/err.impl.jac +3 -0
- jaclang/tests/fixtures/err.jac +4 -2
- jaclang/tests/fixtures/err_runtime.jac +15 -0
- jaclang/tests/fixtures/foo.jac +43 -0
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/hello.jac +4 -0
- jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
- jaclang/tests/fixtures/impl_grab.jac +4 -1
- jaclang/tests/fixtures/import.jac +9 -0
- jaclang/tests/fixtures/index_slice.jac +30 -0
- jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/needs_import.jac +2 -2
- jaclang/tests/fixtures/pyfunc_1.py +1 -1
- jaclang/tests/fixtures/pyfunc_2.py +5 -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/fixtures/registry.jac +9 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/fixtures/semstr.jac +1 -4
- jaclang/tests/fixtures/simple_archs.jac +1 -1
- jaclang/tests/test_cli.py +109 -3
- jaclang/tests/test_language.py +170 -68
- jaclang/tests/test_reference.py +2 -3
- jaclang/utils/helpers.py +45 -21
- jaclang/utils/test.py +9 -0
- jaclang/utils/treeprinter.py +30 -7
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/METADATA +3 -2
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/RECORD +126 -90
- jaclang/core/architype.py +0 -502
- jaclang/core/importer.py +0 -344
- jaclang/core/memory.py +0 -99
- jaclang/tests/fixtures/aott_raise.jac +0 -25
- jaclang/tests/fixtures/package_import.jac +0 -6
- /jaclang/{core → runtimelib}/__init__.py +0 -0
- /jaclang/{core → runtimelib}/test.py +0 -0
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/WHEEL +0 -0
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/entry_points.txt +0 -0
|
@@ -6,8 +6,7 @@ mypy apis into Jac and use jac py ast in it.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
from typing import Callable, TypeVar
|
|
9
|
+
from typing import Callable, Optional, TypeVar
|
|
11
10
|
|
|
12
11
|
import jaclang.compiler.absyntree as ast
|
|
13
12
|
from jaclang.compiler.passes import Pass
|
|
@@ -30,12 +29,12 @@ class FuseTypeInfoPass(Pass):
|
|
|
30
29
|
|
|
31
30
|
node_type_hash: dict[MypyNodes.Node | VNode, MyType] = {}
|
|
32
31
|
|
|
33
|
-
def __debug_print(self,
|
|
32
|
+
def __debug_print(self, msg: str) -> None:
|
|
34
33
|
if settings.fuse_type_info_debug:
|
|
35
|
-
|
|
34
|
+
self.log_info("FuseTypeInfo::" + msg)
|
|
36
35
|
|
|
37
36
|
def __call_type_handler(
|
|
38
|
-
self, node: ast.AstSymbolNode, mypy_type: MypyTypes.
|
|
37
|
+
self, node: ast.AstSymbolNode, mypy_type: MypyTypes.Type
|
|
39
38
|
) -> None:
|
|
40
39
|
mypy_type_name = pascal_to_snake(mypy_type.__class__.__name__)
|
|
41
40
|
type_handler_name = f"get_type_from_{mypy_type_name}"
|
|
@@ -53,6 +52,9 @@ class FuseTypeInfoPass(Pass):
|
|
|
53
52
|
if typ[0] == "builtins":
|
|
54
53
|
return
|
|
55
54
|
|
|
55
|
+
if node.sym_type == "types.ModuleType" and node.sym:
|
|
56
|
+
node.name_spec.type_sym_tab = node.sym.parent_tab.find_scope(node.sym_name)
|
|
57
|
+
|
|
56
58
|
assert isinstance(self.ir, ast.Module)
|
|
57
59
|
|
|
58
60
|
if typ_sym_table:
|
|
@@ -66,13 +68,44 @@ class FuseTypeInfoPass(Pass):
|
|
|
66
68
|
if typ_sym_table != self.ir.sym_tab:
|
|
67
69
|
node.name_spec.type_sym_tab = typ_sym_table
|
|
68
70
|
|
|
71
|
+
def __collect_python_dependencies(self, node: ast.AstNode) -> None:
|
|
72
|
+
assert isinstance(node, ast.AstSymbolNode)
|
|
73
|
+
assert isinstance(self.ir, ast.Module)
|
|
74
|
+
|
|
75
|
+
mypy_node = node.gen.mypy_ast[0]
|
|
76
|
+
|
|
77
|
+
if isinstance(mypy_node, MypyNodes.RefExpr) and mypy_node.node:
|
|
78
|
+
node_full_name = mypy_node.node.fullname
|
|
79
|
+
if "." in node_full_name:
|
|
80
|
+
mod_name = node_full_name[: node_full_name.rindex(".")]
|
|
81
|
+
else:
|
|
82
|
+
mod_name = node_full_name
|
|
83
|
+
|
|
84
|
+
if mod_name not in self.ir.py_mod_dep_map:
|
|
85
|
+
self.__debug_print(
|
|
86
|
+
f"Can't find a python file associated with {type(node)}::{node.loc}"
|
|
87
|
+
)
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
mode_path = self.ir.py_mod_dep_map[mod_name]
|
|
91
|
+
if mode_path.endswith(".jac"):
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
self.ir.py_raise_map[mod_name] = mode_path
|
|
95
|
+
else:
|
|
96
|
+
self.__debug_print(
|
|
97
|
+
f"Collect python dependencies is not supported in {type(node)}::{node.loc}"
|
|
98
|
+
)
|
|
99
|
+
|
|
69
100
|
@staticmethod
|
|
70
101
|
def __handle_node(
|
|
71
102
|
func: Callable[[FuseTypeInfoPass, T], None]
|
|
72
103
|
) -> Callable[[FuseTypeInfoPass, T], None]:
|
|
73
104
|
def node_handler(self: FuseTypeInfoPass, node: T) -> None:
|
|
74
105
|
if not isinstance(node, ast.AstSymbolNode):
|
|
75
|
-
|
|
106
|
+
self.__debug_print(
|
|
107
|
+
f"Warning {node.__class__.__name__} is not an AstSymbolNode"
|
|
108
|
+
)
|
|
76
109
|
|
|
77
110
|
try:
|
|
78
111
|
jac_node_str = f'jac node "{node.loc}::{node.__class__.__name__}'
|
|
@@ -85,6 +118,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
85
118
|
if len(node.gen.mypy_ast) == 1:
|
|
86
119
|
func(self, node)
|
|
87
120
|
self.__set_sym_table_link(node)
|
|
121
|
+
self.__collect_python_dependencies(node)
|
|
88
122
|
|
|
89
123
|
# Jac node has multiple mypy nodes linked to it
|
|
90
124
|
elif len(node.gen.mypy_ast) > 1:
|
|
@@ -100,27 +134,28 @@ class FuseTypeInfoPass(Pass):
|
|
|
100
134
|
# Check the number of unique mypy nodes linked
|
|
101
135
|
if len(temp) > 1:
|
|
102
136
|
self.__debug_print(
|
|
103
|
-
jac_node_str
|
|
137
|
+
f"{jac_node_str} has multiple mypy nodes associated to it"
|
|
104
138
|
)
|
|
105
139
|
else:
|
|
106
140
|
self.__debug_print(
|
|
107
|
-
jac_node_str
|
|
141
|
+
f"{jac_node_str} has duplicate mypy nodes associated to it"
|
|
108
142
|
)
|
|
109
143
|
func(self, node)
|
|
110
144
|
self.__set_sym_table_link(node)
|
|
145
|
+
self.__collect_python_dependencies(node)
|
|
111
146
|
|
|
112
147
|
# Jac node doesn't have mypy nodes linked to it
|
|
113
148
|
else:
|
|
114
149
|
self.__debug_print(
|
|
115
|
-
jac_node_str
|
|
150
|
+
f"{jac_node_str} doesn't have mypy node associated to it"
|
|
116
151
|
)
|
|
117
152
|
|
|
118
153
|
except AttributeError as e:
|
|
154
|
+
if settings.fuse_type_info_debug:
|
|
155
|
+
raise e
|
|
119
156
|
self.__debug_print(
|
|
120
|
-
f'Internal error happened while parsing "{e.obj.__class__.__name__}"'
|
|
157
|
+
f'{node.loc}: Internal error happened while parsing "{e.obj.__class__.__name__}"'
|
|
121
158
|
)
|
|
122
|
-
traceback.print_exc()
|
|
123
|
-
print(e)
|
|
124
159
|
|
|
125
160
|
return node_handler
|
|
126
161
|
|
|
@@ -129,12 +164,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
129
164
|
|
|
130
165
|
if isinstance(mypy_node, MypyNodes.MemberExpr):
|
|
131
166
|
if mypy_node in self.node_type_hash:
|
|
132
|
-
|
|
133
|
-
if "def" in t and "->" in t:
|
|
134
|
-
t = t.split("->")[1].strip()
|
|
135
|
-
elif "def" in t:
|
|
136
|
-
t = "None"
|
|
137
|
-
node.name_spec.sym_type = t
|
|
167
|
+
self.__call_type_handler(node, self.node_type_hash[mypy_node])
|
|
138
168
|
else:
|
|
139
169
|
self.__debug_print(f"{node.loc} MemberExpr type is not found")
|
|
140
170
|
|
|
@@ -159,8 +189,8 @@ class FuseTypeInfoPass(Pass):
|
|
|
159
189
|
|
|
160
190
|
else:
|
|
161
191
|
self.__debug_print(
|
|
162
|
-
f'"{node.loc}::{node.__class__.__name__}" mypy (with node attr) node isn\'t supported'
|
|
163
|
-
type(mypy_node)
|
|
192
|
+
f'"{node.loc}::{node.__class__.__name__}" mypy (with node attr) node isn\'t supported'
|
|
193
|
+
f"{type(mypy_node)}"
|
|
164
194
|
)
|
|
165
195
|
|
|
166
196
|
else:
|
|
@@ -175,8 +205,8 @@ class FuseTypeInfoPass(Pass):
|
|
|
175
205
|
self.__call_type_handler(node, mypy_node.func.type.ret_type)
|
|
176
206
|
else:
|
|
177
207
|
self.__debug_print(
|
|
178
|
-
f'"{node.loc}::{node.__class__.__name__}" mypy node isn\'t supported'
|
|
179
|
-
type(mypy_node)
|
|
208
|
+
f'"{node.loc}::{node.__class__.__name__}" mypy node isn\'t supported'
|
|
209
|
+
f"{type(mypy_node)}"
|
|
180
210
|
)
|
|
181
211
|
|
|
182
212
|
@__handle_node
|
|
@@ -187,12 +217,12 @@ class FuseTypeInfoPass(Pass):
|
|
|
187
217
|
@__handle_node
|
|
188
218
|
def enter_module_path(self, node: ast.ModulePath) -> None:
|
|
189
219
|
"""Pass handler for ModulePath nodes."""
|
|
190
|
-
self.__debug_print("Getting type not supported in
|
|
220
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
191
221
|
|
|
192
222
|
@__handle_node
|
|
193
223
|
def enter_module_item(self, node: ast.ModuleItem) -> None:
|
|
194
224
|
"""Pass handler for ModuleItem nodes."""
|
|
195
|
-
self.__debug_print("Getting type not supported in
|
|
225
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
196
226
|
|
|
197
227
|
@__handle_node
|
|
198
228
|
def enter_architype(self, node: ast.Architype) -> None:
|
|
@@ -202,7 +232,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
202
232
|
@__handle_node
|
|
203
233
|
def enter_arch_def(self, node: ast.ArchDef) -> None:
|
|
204
234
|
"""Pass handler for ArchDef nodes."""
|
|
205
|
-
self.__debug_print("Getting type not supported in
|
|
235
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
206
236
|
|
|
207
237
|
@__handle_node
|
|
208
238
|
def enter_enum(self, node: ast.Enum) -> None:
|
|
@@ -212,7 +242,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
212
242
|
@__handle_node
|
|
213
243
|
def enter_enum_def(self, node: ast.EnumDef) -> None:
|
|
214
244
|
"""Pass handler for EnumDef nodes."""
|
|
215
|
-
self.__debug_print("Getting type not supported in
|
|
245
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
216
246
|
|
|
217
247
|
@__handle_node
|
|
218
248
|
def enter_ability(self, node: ast.Ability) -> None:
|
|
@@ -221,8 +251,8 @@ class FuseTypeInfoPass(Pass):
|
|
|
221
251
|
self.__call_type_handler(node, node.gen.mypy_ast[0].type.ret_type)
|
|
222
252
|
else:
|
|
223
253
|
self.__debug_print(
|
|
224
|
-
f"{node.loc}: Can't get type of an ability from mypy node other than Ability."
|
|
225
|
-
type(node.gen.mypy_ast[0])
|
|
254
|
+
f"{node.loc}: Can't get type of an ability from mypy node other than Ability. "
|
|
255
|
+
f"{type(node.gen.mypy_ast[0])}"
|
|
226
256
|
)
|
|
227
257
|
|
|
228
258
|
@__handle_node
|
|
@@ -232,8 +262,8 @@ class FuseTypeInfoPass(Pass):
|
|
|
232
262
|
self.__call_type_handler(node, node.gen.mypy_ast[0].type.ret_type)
|
|
233
263
|
else:
|
|
234
264
|
self.__debug_print(
|
|
235
|
-
f"{node.loc}: Can't get type of an AbilityDef from mypy node other than FuncDef."
|
|
236
|
-
type(node.gen.mypy_ast[0])
|
|
265
|
+
f"{node.loc}: Can't get type of an AbilityDef from mypy node other than FuncDef. "
|
|
266
|
+
f"{type(node.gen.mypy_ast[0])}"
|
|
237
267
|
)
|
|
238
268
|
|
|
239
269
|
@__handle_node
|
|
@@ -279,7 +309,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
279
309
|
@__handle_node
|
|
280
310
|
def enter_f_string(self, node: ast.FString) -> None:
|
|
281
311
|
"""Pass handler for FString nodes."""
|
|
282
|
-
self.__debug_print("Getting type not supported in
|
|
312
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
283
313
|
|
|
284
314
|
@__handle_node
|
|
285
315
|
def enter_list_val(self, node: ast.ListVal) -> None:
|
|
@@ -332,7 +362,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
332
362
|
@__handle_node
|
|
333
363
|
def enter_index_slice(self, node: ast.IndexSlice) -> None:
|
|
334
364
|
"""Pass handler for IndexSlice nodes."""
|
|
335
|
-
self.__debug_print("Getting type not supported in
|
|
365
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
336
366
|
|
|
337
367
|
@__handle_node
|
|
338
368
|
def enter_arch_ref(self, node: ast.ArchRef) -> None:
|
|
@@ -346,8 +376,8 @@ class FuseTypeInfoPass(Pass):
|
|
|
346
376
|
self.__call_type_handler(node, mypy_node2.type)
|
|
347
377
|
else:
|
|
348
378
|
self.__debug_print(
|
|
349
|
-
f"{node.loc}: Can't get ArchRef value from mypyNode other than ClassDef"
|
|
350
|
-
type(node.gen.mypy_ast[0])
|
|
379
|
+
f"{node.loc}: Can't get ArchRef value from mypyNode other than ClassDef "
|
|
380
|
+
f"type(node.gen.mypy_ast[0])"
|
|
351
381
|
)
|
|
352
382
|
|
|
353
383
|
@__handle_node
|
|
@@ -363,12 +393,12 @@ class FuseTypeInfoPass(Pass):
|
|
|
363
393
|
@__handle_node
|
|
364
394
|
def enter_filter_compr(self, node: ast.FilterCompr) -> None:
|
|
365
395
|
"""Pass handler for FilterCompr nodes."""
|
|
366
|
-
self.__debug_print("Getting type not supported in
|
|
396
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
367
397
|
|
|
368
398
|
@__handle_node
|
|
369
399
|
def enter_assign_compr(self, node: ast.AssignCompr) -> None:
|
|
370
400
|
"""Pass handler for AssignCompr nodes."""
|
|
371
|
-
self.__debug_print("Getting type not supported in
|
|
401
|
+
self.__debug_print(f"Getting type not supported in {type(node)}")
|
|
372
402
|
|
|
373
403
|
@__handle_node
|
|
374
404
|
def enter_int(self, node: ast.Int) -> None:
|
|
@@ -405,7 +435,7 @@ class FuseTypeInfoPass(Pass):
|
|
|
405
435
|
self, node: ast.AstSymbolNode, mypy_type: MypyTypes.CallableType
|
|
406
436
|
) -> None:
|
|
407
437
|
"""Get type info from mypy type CallableType."""
|
|
408
|
-
node
|
|
438
|
+
self.__call_type_handler(node, mypy_type.ret_type)
|
|
409
439
|
|
|
410
440
|
# TODO: Which overloaded function to get the return value from?
|
|
411
441
|
def get_type_from_overloaded(
|
|
@@ -432,6 +462,12 @@ class FuseTypeInfoPass(Pass):
|
|
|
432
462
|
"""Get type info from mypy type TupleType."""
|
|
433
463
|
node.name_spec.sym_type = "builtins.tuple"
|
|
434
464
|
|
|
465
|
+
def get_type_from_type_type(
|
|
466
|
+
self, node: ast.AstSymbolNode, mypy_type: MypyTypes.TypeType
|
|
467
|
+
) -> None:
|
|
468
|
+
"""Get type info from mypy type TypeType."""
|
|
469
|
+
node.name_spec.sym_type = str(mypy_type.item)
|
|
470
|
+
|
|
435
471
|
def exit_assignment(self, node: ast.Assignment) -> None:
|
|
436
472
|
"""Add new symbols in the symbol table in case of self."""
|
|
437
473
|
# This will fix adding new items to the class through self
|
|
@@ -447,20 +483,85 @@ class FuseTypeInfoPass(Pass):
|
|
|
447
483
|
if self_obj.type_sym_tab and isinstance(right_obj, ast.AstSymbolNode):
|
|
448
484
|
self_obj.type_sym_tab.def_insert(right_obj)
|
|
449
485
|
|
|
450
|
-
def
|
|
451
|
-
"""
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if isinstance(
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
486
|
+
def expand_atom_trailer(self, node_list: list[ast.AstNode]) -> list[ast.AstNode]:
|
|
487
|
+
"""Expand the atom trailer object in a list of AstNode."""
|
|
488
|
+
out: list[ast.AstNode] = []
|
|
489
|
+
for i in node_list:
|
|
490
|
+
if isinstance(i, ast.AtomTrailer):
|
|
491
|
+
out.append(i.target)
|
|
492
|
+
out.append(i.right)
|
|
493
|
+
elif isinstance(i, ast.FuncCall):
|
|
494
|
+
out.append(i.target)
|
|
495
|
+
else:
|
|
496
|
+
out.append(i)
|
|
497
|
+
return out
|
|
498
|
+
|
|
499
|
+
def exit_atom_trailer(self, node: ast.AtomTrailer) -> None:
|
|
500
|
+
"""Adding symbol links to AtomTrailer right nodes."""
|
|
501
|
+
# This will fix adding the symbol links to nodes in atom trailer
|
|
502
|
+
# self.x.z = 5 # will add symbol links to both x and z
|
|
503
|
+
|
|
504
|
+
# This function originally used `as_attr_list` in AtomTrailer
|
|
505
|
+
# but an issue happened when doing stuff like fool_me().CONST_VALUE2
|
|
506
|
+
# The issue was due to the way `as_attr_list` implemented so the fix
|
|
507
|
+
# was to implement it again to get all items in AtomTrailer even if
|
|
508
|
+
# their type is not an AstSymbolNode
|
|
509
|
+
atom_trailer_unwind = self.expand_atom_trailer([node])
|
|
510
|
+
iteration_count = 0
|
|
511
|
+
while any(
|
|
512
|
+
isinstance(i, (ast.AtomTrailer, ast.FuncCall)) for i in atom_trailer_unwind
|
|
513
|
+
):
|
|
514
|
+
atom_trailer_unwind = self.expand_atom_trailer(atom_trailer_unwind)
|
|
515
|
+
iteration_count += 1
|
|
516
|
+
if iteration_count > 50:
|
|
517
|
+
break
|
|
518
|
+
|
|
519
|
+
for i in range(1, len(atom_trailer_unwind)):
|
|
520
|
+
left = atom_trailer_unwind[i - 1]
|
|
521
|
+
right = atom_trailer_unwind[i]
|
|
522
|
+
|
|
523
|
+
assert isinstance(left, ast.AstSymbolNode)
|
|
524
|
+
assert isinstance(right, ast.AstSymbolNode)
|
|
525
|
+
|
|
526
|
+
if isinstance(right, ast.IndexSlice):
|
|
527
|
+
# In case of index slice, left won't have a symbol table as it's a list/dict/set
|
|
528
|
+
node_type: str = ""
|
|
529
|
+
|
|
530
|
+
# left type is a list
|
|
531
|
+
if left.sym_type.startswith("builtins.list["):
|
|
532
|
+
node_type = left.sym_type[len("builtins.list[") : -1]
|
|
533
|
+
|
|
534
|
+
# right index slice is a range then it's type is the same as left
|
|
535
|
+
if right.is_range:
|
|
536
|
+
right.name_spec.sym_type = left.sym_type
|
|
537
|
+
continue
|
|
538
|
+
|
|
539
|
+
# left type is a dictionary
|
|
540
|
+
elif left.sym_type.startswith("builtins.dict["):
|
|
541
|
+
node_type = (
|
|
542
|
+
left.sym_type[len("builtins.dict[") : -1].split(",")[1].strip()
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
# unsupported type
|
|
546
|
+
else:
|
|
547
|
+
continue
|
|
548
|
+
|
|
549
|
+
right.name_spec.sym_type = node_type
|
|
550
|
+
|
|
551
|
+
# Getting the correct symbol table and link it
|
|
552
|
+
type_symtab: Optional[SymbolTable] = self.ir.sym_tab
|
|
553
|
+
assert isinstance(self.ir, ast.Module)
|
|
554
|
+
assert isinstance(type_symtab, SymbolTable)
|
|
555
|
+
for j in node_type.split("."):
|
|
556
|
+
if j == self.ir.name:
|
|
557
|
+
continue
|
|
558
|
+
type_symtab = type_symtab.find_scope(j)
|
|
559
|
+
if type_symtab is None:
|
|
560
|
+
break
|
|
561
|
+
right.name_spec.type_sym_tab = type_symtab
|
|
562
|
+
|
|
563
|
+
else:
|
|
564
|
+
if left.type_sym_tab:
|
|
565
|
+
right.name_spec.sym = left.type_sym_tab.lookup(right.sym_name)
|
|
566
|
+
if right.name_spec.sym:
|
|
567
|
+
right.name_spec.sym.add_use(right.name_spec)
|
|
@@ -6,17 +6,17 @@ 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.
|
|
19
|
-
|
|
15
|
+
from jaclang.compiler.passes.main import SubNodeTabPass, SymTabBuildPass
|
|
16
|
+
from jaclang.utils.log import logging
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class JacImportPass(Pass):
|
|
@@ -25,40 +25,29 @@ class JacImportPass(Pass):
|
|
|
25
25
|
def before_pass(self) -> None:
|
|
26
26
|
"""Run once before pass."""
|
|
27
27
|
self.import_table: dict[str, ast.Module] = {}
|
|
28
|
-
self.__py_imports: set[str] = set()
|
|
29
|
-
self.py_resolve_list: set[str] = set()
|
|
30
28
|
|
|
31
29
|
def enter_module(self, node: ast.Module) -> None:
|
|
32
30
|
"""Run Importer."""
|
|
33
31
|
self.cur_node = node
|
|
34
32
|
self.import_table[node.loc.mod_path] = node
|
|
35
|
-
self.
|
|
36
|
-
self.__annex_impl(node)
|
|
33
|
+
self.annex_impl(node)
|
|
37
34
|
self.terminate() # Turns off auto traversal for deliberate traversal
|
|
38
35
|
self.run_again = True
|
|
39
36
|
while self.run_again:
|
|
40
37
|
self.run_again = False
|
|
41
38
|
all_imports = self.get_all_sub_nodes(node, ast.ModulePath)
|
|
42
39
|
for i in all_imports:
|
|
43
|
-
self.process_import(
|
|
40
|
+
self.process_import(i)
|
|
44
41
|
self.enter_module_path(i)
|
|
45
42
|
SubNodeTabPass(prior=self, input_ir=node)
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
self.enter_atom_trailer(i)
|
|
49
|
-
|
|
50
|
-
node.mod_deps = self.import_table
|
|
44
|
+
node.mod_deps.update(self.import_table)
|
|
51
45
|
|
|
52
|
-
def process_import(self,
|
|
46
|
+
def process_import(self, i: ast.ModulePath) -> None:
|
|
53
47
|
"""Process an import."""
|
|
54
|
-
|
|
55
|
-
if
|
|
56
|
-
self.import_jac_module(
|
|
57
|
-
node=i,
|
|
58
|
-
mod_path=node.loc.mod_path,
|
|
59
|
-
)
|
|
60
|
-
elif lang == "py":
|
|
61
|
-
self.__py_imports.add(i.path_str)
|
|
48
|
+
imp_node = i.parent_of_type(ast.Import)
|
|
49
|
+
if imp_node.is_jac and not i.sub_module:
|
|
50
|
+
self.import_jac_module(node=i)
|
|
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,19 +121,10 @@ class JacImportPass(Pass):
|
|
|
131
121
|
node.sub_module.name = node.alias.value
|
|
132
122
|
# Items matched during def/decl pass
|
|
133
123
|
|
|
134
|
-
def
|
|
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
|
-
def import_jac_module(self, node: ast.ModulePath, mod_path: str) -> None:
|
|
124
|
+
def import_jac_module(self, node: ast.ModulePath) -> None:
|
|
140
125
|
"""Import a module."""
|
|
141
126
|
self.cur_node = node # impacts error reporting
|
|
142
|
-
target =
|
|
143
|
-
level=node.level,
|
|
144
|
-
target=node.path_str,
|
|
145
|
-
base_path=os.path.dirname(node.loc.mod_path),
|
|
146
|
-
)
|
|
127
|
+
target = node.resolve_relative_path()
|
|
147
128
|
# If the module is a package (dir)
|
|
148
129
|
if os.path.isdir(target):
|
|
149
130
|
self.attach_mod_to_node(node, self.import_jac_mod_from_dir(target))
|
|
@@ -153,11 +134,7 @@ class JacImportPass(Pass):
|
|
|
153
134
|
# Import all from items as modules or packages
|
|
154
135
|
for i in import_node.items.items:
|
|
155
136
|
if isinstance(i, ast.ModuleItem):
|
|
156
|
-
from_mod_target =
|
|
157
|
-
level=node.level,
|
|
158
|
-
target=node.path_str + "." + i.name.value,
|
|
159
|
-
base_path=os.path.dirname(node.loc.mod_path),
|
|
160
|
-
)
|
|
137
|
+
from_mod_target = node.resolve_relative_path(i.name.value)
|
|
161
138
|
# If package
|
|
162
139
|
if os.path.isdir(from_mod_target):
|
|
163
140
|
self.attach_mod_to_node(
|
|
@@ -204,7 +181,7 @@ class JacImportPass(Pass):
|
|
|
204
181
|
self.warnings_had += mod_pass.warnings_had
|
|
205
182
|
mod = mod_pass.ir
|
|
206
183
|
except Exception as e:
|
|
207
|
-
|
|
184
|
+
logger.info(e)
|
|
208
185
|
mod = None
|
|
209
186
|
if isinstance(mod, ast.Module):
|
|
210
187
|
self.import_table[target] = mod
|
|
@@ -222,55 +199,102 @@ class PyImportPass(JacImportPass):
|
|
|
222
199
|
def before_pass(self) -> None:
|
|
223
200
|
"""Only run pass if settings are set to raise python."""
|
|
224
201
|
super().before_pass()
|
|
225
|
-
if not settings.py_raise:
|
|
226
|
-
self.terminate()
|
|
227
202
|
|
|
228
|
-
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:
|
|
229
213
|
"""Process an import."""
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
|
220
|
+
imp_node = i.parent_of_type(ast.Import)
|
|
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
|
+
)
|
|
238
245
|
|
|
239
246
|
def import_py_module(
|
|
240
|
-
self,
|
|
247
|
+
self,
|
|
248
|
+
parent_node: ast.ModulePath | ast.ModuleItem,
|
|
249
|
+
imported_mod_name: str,
|
|
250
|
+
mod_path: str,
|
|
241
251
|
) -> Optional[ast.Module]:
|
|
242
252
|
"""Import a module."""
|
|
243
253
|
from jaclang.compiler.passes.main import PyastBuildPass
|
|
244
254
|
|
|
245
|
-
|
|
246
|
-
|
|
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
|
+
|
|
247
273
|
try:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return self.import_table[spec.origin]
|
|
254
|
-
with open(spec.origin, "r", encoding="utf-8") as f:
|
|
255
|
-
# print(f"\nImporting python module {node.path_str}")
|
|
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:
|
|
256
279
|
mod = PyastBuildPass(
|
|
257
280
|
input_ir=ast.PythonModuleAst(
|
|
258
|
-
py_ast.parse(f.read()), mod_path=
|
|
281
|
+
py_ast.parse(f.read()), mod_path=file_to_raise
|
|
259
282
|
),
|
|
260
283
|
).ir
|
|
284
|
+
SubNodeTabPass(input_ir=mod, prior=self)
|
|
261
285
|
if mod:
|
|
262
|
-
|
|
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)
|
|
263
290
|
return mod
|
|
264
291
|
else:
|
|
265
|
-
raise self.ice(
|
|
266
|
-
f"Failed to import python module {node.path_str}: {spec.origin}"
|
|
267
|
-
)
|
|
292
|
+
raise self.ice(f"Failed to import python module {mod_path}")
|
|
268
293
|
except Exception as e:
|
|
269
|
-
|
|
270
|
-
return None
|
|
271
|
-
self.error(
|
|
272
|
-
f"Failed to import python module {node.path_str}: {e}",
|
|
273
|
-
node_override=node,
|
|
274
|
-
)
|
|
294
|
+
self.error(f"Failed to import python module {mod_path}")
|
|
275
295
|
raise e
|
|
276
296
|
return None
|
|
297
|
+
|
|
298
|
+
def annex_impl(self, node: ast.Module) -> None:
|
|
299
|
+
"""Annex impl and test modules."""
|
|
300
|
+
return None
|