jaclang 0.8.8__py3-none-any.whl → 0.8.10__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 +194 -10
- jaclang/cli/cmdreg.py +144 -8
- jaclang/compiler/__init__.py +6 -1
- jaclang/compiler/codeinfo.py +16 -1
- jaclang/compiler/constant.py +33 -8
- jaclang/compiler/jac.lark +154 -62
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +656 -149
- jaclang/compiler/passes/__init__.py +2 -1
- jaclang/compiler/passes/ast_gen/__init__.py +5 -0
- jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
- jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
- jaclang/compiler/passes/ecmascript/__init__.py +25 -0
- jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
- jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
- jaclang/compiler/passes/ecmascript/estree.py +972 -0
- jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
- jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
- jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
- jaclang/compiler/passes/main/__init__.py +0 -3
- jaclang/compiler/passes/main/annex_pass.py +23 -1
- jaclang/compiler/passes/main/def_use_pass.py +1 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +413 -255
- jaclang/compiler/passes/main/pyast_load_pass.py +48 -11
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
- jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
- jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -3
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +13 -14
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
- jaclang/compiler/passes/main/type_checker_pass.py +7 -0
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +219 -20
- jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +135 -29
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
- jaclang/compiler/passes/transform.py +9 -1
- jaclang/compiler/passes/uni_pass.py +5 -7
- jaclang/compiler/program.py +27 -26
- jaclang/compiler/tests/test_client_codegen.py +113 -0
- jaclang/compiler/tests/test_importer.py +12 -10
- jaclang/compiler/tests/test_parser.py +249 -3
- jaclang/compiler/type_system/type_evaluator.jac +1078 -0
- jaclang/compiler/type_system/type_utils.py +1 -1
- jaclang/compiler/type_system/types.py +6 -0
- jaclang/compiler/unitree.py +438 -82
- jaclang/langserve/engine.jac +224 -288
- jaclang/langserve/sem_manager.jac +12 -8
- jaclang/langserve/server.jac +48 -48
- jaclang/langserve/tests/fixtures/greet.py +17 -0
- jaclang/langserve/tests/fixtures/md_path.jac +22 -0
- jaclang/langserve/tests/fixtures/user.jac +15 -0
- jaclang/langserve/tests/test_server.py +66 -371
- jaclang/lib.py +17 -0
- jaclang/runtimelib/archetype.py +25 -25
- jaclang/runtimelib/client_bundle.py +169 -0
- jaclang/runtimelib/client_runtime.jac +586 -0
- jaclang/runtimelib/constructs.py +4 -2
- jaclang/runtimelib/machine.py +308 -139
- jaclang/runtimelib/meta_importer.py +111 -22
- jaclang/runtimelib/mtp.py +15 -0
- jaclang/runtimelib/server.py +1089 -0
- jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
- jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
- jaclang/runtimelib/tests/test_client_bundle.py +55 -0
- jaclang/runtimelib/tests/test_client_render.py +63 -0
- jaclang/runtimelib/tests/test_serve.py +1069 -0
- jaclang/settings.py +0 -3
- jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
- jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
- jaclang/tests/fixtures/funccall_genexpr.py +5 -0
- jaclang/tests/fixtures/iife_functions.jac +142 -0
- jaclang/tests/fixtures/iife_functions_client.jac +143 -0
- jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
- jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
- jaclang/tests/fixtures/needs_import_dup.jac +6 -4
- jaclang/tests/fixtures/py2jac_empty.py +0 -0
- jaclang/tests/fixtures/py_run.py +7 -5
- jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
- jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
- jaclang/tests/test_cli.py +134 -18
- jaclang/tests/test_language.py +120 -32
- jaclang/tests/test_reference.py +20 -3
- jaclang/utils/NonGPT.py +375 -0
- jaclang/utils/helpers.py +64 -20
- jaclang/utils/lang_tools.py +31 -4
- jaclang/utils/tests/test_lang_tools.py +5 -16
- jaclang/utils/treeprinter.py +8 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/RECORD +106 -71
- jaclang/compiler/passes/main/binder_pass.py +0 -594
- jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
- jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
- jaclang/compiler/type_system/type_evaluator.py +0 -844
- jaclang/langserve/tests/session.jac +0 -294
- jaclang/langserve/tests/test_dev_server.py +0 -80
- jaclang/runtimelib/importer.py +0 -351
- jaclang/tests/test_typecheck.py +0 -542
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
|
@@ -1,594 +0,0 @@
|
|
|
1
|
-
"""Binding Pass for the Jac compiler."""
|
|
2
|
-
|
|
3
|
-
import ast as py_ast
|
|
4
|
-
import os
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
import jaclang.compiler.unitree as uni
|
|
8
|
-
from jaclang.compiler.passes import UniPass
|
|
9
|
-
from jaclang.compiler.unitree import UniScopeNode
|
|
10
|
-
from jaclang.runtimelib.utils import read_file_with_encoding
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class BinderPass(UniPass):
|
|
14
|
-
"""Jac Binder pass."""
|
|
15
|
-
|
|
16
|
-
def before_pass(self) -> None:
|
|
17
|
-
"""Before pass."""
|
|
18
|
-
if self.prog.mod.main == self.ir_in:
|
|
19
|
-
self.load_builtins()
|
|
20
|
-
self.scope_stack: list[UniScopeNode] = []
|
|
21
|
-
self.globals_stack: list[list[uni.Symbol]] = []
|
|
22
|
-
|
|
23
|
-
###########################################################
|
|
24
|
-
## Helper functions for symbol table stack manipulations ##
|
|
25
|
-
###########################################################
|
|
26
|
-
def push_scope_and_link(self, key_node: uni.UniScopeNode) -> None:
|
|
27
|
-
"""Add scope into scope stack."""
|
|
28
|
-
if not len(self.scope_stack):
|
|
29
|
-
self.scope_stack.append(key_node)
|
|
30
|
-
else:
|
|
31
|
-
self.scope_stack.append(self.cur_scope.link_kid_scope(key_node=key_node))
|
|
32
|
-
|
|
33
|
-
def pop_scope(self) -> UniScopeNode:
|
|
34
|
-
"""Remove current scope from scope stack."""
|
|
35
|
-
return self.scope_stack.pop()
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def cur_scope(self) -> UniScopeNode:
|
|
39
|
-
"""Return current scope."""
|
|
40
|
-
return self.scope_stack[-1]
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def cur_globals(self) -> list[uni.Symbol]:
|
|
44
|
-
"""Get current global symbols."""
|
|
45
|
-
if len(self.globals_stack):
|
|
46
|
-
return self.globals_stack[-1]
|
|
47
|
-
else:
|
|
48
|
-
return []
|
|
49
|
-
|
|
50
|
-
# TODO: Every call for this function should be moved to symbol table it self
|
|
51
|
-
def check_global(self, node_name: str) -> Optional[uni.Symbol]:
|
|
52
|
-
"""Check if symbol exists in global scope."""
|
|
53
|
-
for symbol in self.cur_globals:
|
|
54
|
-
if symbol.sym_name == node_name:
|
|
55
|
-
return symbol
|
|
56
|
-
return None
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def cur_module_scope(self) -> UniScopeNode:
|
|
60
|
-
"""Return the current module."""
|
|
61
|
-
return self.scope_stack[0]
|
|
62
|
-
|
|
63
|
-
###############################################
|
|
64
|
-
## Handling for nodes that creates new scope ##
|
|
65
|
-
###############################################
|
|
66
|
-
SCOPE_NODES = (
|
|
67
|
-
uni.MatchCase,
|
|
68
|
-
uni.DictCompr,
|
|
69
|
-
uni.ListCompr,
|
|
70
|
-
uni.GenCompr,
|
|
71
|
-
uni.SetCompr,
|
|
72
|
-
uni.LambdaExpr,
|
|
73
|
-
uni.WithStmt,
|
|
74
|
-
uni.WhileStmt,
|
|
75
|
-
uni.InForStmt,
|
|
76
|
-
uni.IterForStmt,
|
|
77
|
-
uni.TryStmt,
|
|
78
|
-
uni.Except,
|
|
79
|
-
uni.FinallyStmt,
|
|
80
|
-
uni.IfStmt,
|
|
81
|
-
uni.ElseIf,
|
|
82
|
-
uni.ElseStmt,
|
|
83
|
-
uni.TypedCtxBlock,
|
|
84
|
-
uni.Module,
|
|
85
|
-
uni.Ability,
|
|
86
|
-
uni.Test,
|
|
87
|
-
uni.Archetype,
|
|
88
|
-
uni.ImplDef,
|
|
89
|
-
uni.SemDef,
|
|
90
|
-
uni.Enum,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
GLOBAL_STACK_NODES = (uni.Ability, uni.Archetype)
|
|
94
|
-
|
|
95
|
-
def enter_node(self, node: uni.UniNode) -> None:
|
|
96
|
-
if isinstance(node, self.SCOPE_NODES):
|
|
97
|
-
self.push_scope_and_link(node)
|
|
98
|
-
if isinstance(node, self.GLOBAL_STACK_NODES):
|
|
99
|
-
self.globals_stack.append([])
|
|
100
|
-
super().enter_node(node)
|
|
101
|
-
|
|
102
|
-
def exit_node(self, node: uni.UniNode) -> None:
|
|
103
|
-
if isinstance(node, self.SCOPE_NODES):
|
|
104
|
-
self.pop_scope()
|
|
105
|
-
if isinstance(node, self.GLOBAL_STACK_NODES):
|
|
106
|
-
self.globals_stack.pop()
|
|
107
|
-
super().exit_node(node)
|
|
108
|
-
|
|
109
|
-
#########################################
|
|
110
|
-
## AtomTrailer and Symbol Chain Helpers ##
|
|
111
|
-
#########################################
|
|
112
|
-
def handle_symbol_chain(self, node: uni.AtomTrailer, operation: str) -> bool:
|
|
113
|
-
"""Handle symbol chains in AtomTrailer nodes."""
|
|
114
|
-
attr_list = node.as_attr_list
|
|
115
|
-
if not attr_list:
|
|
116
|
-
return False
|
|
117
|
-
|
|
118
|
-
first_obj = attr_list[0]
|
|
119
|
-
first_obj_sym = self.cur_scope.lookup(first_obj.sym_name)
|
|
120
|
-
|
|
121
|
-
if not first_obj_sym:
|
|
122
|
-
return False
|
|
123
|
-
|
|
124
|
-
if first_obj_sym.imported:
|
|
125
|
-
return self._handle_imported_chain(node, operation)
|
|
126
|
-
else:
|
|
127
|
-
return self._handle_local_chain(first_obj_sym, attr_list, operation)
|
|
128
|
-
|
|
129
|
-
def _handle_imported_chain(self, node: uni.AtomTrailer, operation: str) -> bool:
|
|
130
|
-
"""Handle chains that start with imported symbols."""
|
|
131
|
-
try:
|
|
132
|
-
self.resolve_import(node)
|
|
133
|
-
return True
|
|
134
|
-
except Exception:
|
|
135
|
-
return False
|
|
136
|
-
|
|
137
|
-
def _handle_local_chain(
|
|
138
|
-
self, first_sym: uni.Symbol, attr_list: list[uni.AstSymbolNode], operation: str
|
|
139
|
-
) -> bool:
|
|
140
|
-
"""Handle chains within local scope."""
|
|
141
|
-
try:
|
|
142
|
-
current_sym_tab = first_sym.symbol_table
|
|
143
|
-
|
|
144
|
-
if operation == "define":
|
|
145
|
-
first_sym.add_defn(attr_list[0].name_spec)
|
|
146
|
-
else: # operation == 'use'
|
|
147
|
-
first_sym.add_use(attr_list[0].name_spec)
|
|
148
|
-
|
|
149
|
-
for attr_node in attr_list[1:]:
|
|
150
|
-
if not current_sym_tab:
|
|
151
|
-
break
|
|
152
|
-
|
|
153
|
-
attr_sym = current_sym_tab.lookup(attr_node.sym_name)
|
|
154
|
-
if not attr_sym:
|
|
155
|
-
# TODO # self.log_error(
|
|
156
|
-
# f"Could not resolve attribute '{attr_node.sym_name}' in chain"
|
|
157
|
-
# )
|
|
158
|
-
return False
|
|
159
|
-
|
|
160
|
-
if operation == "define":
|
|
161
|
-
attr_sym.add_defn(attr_node)
|
|
162
|
-
else: # operation == 'use'
|
|
163
|
-
attr_sym.add_use(attr_node)
|
|
164
|
-
|
|
165
|
-
current_sym_tab = attr_sym.symbol_table
|
|
166
|
-
return True
|
|
167
|
-
except Exception:
|
|
168
|
-
return False
|
|
169
|
-
|
|
170
|
-
def handle_simple_symbol(
|
|
171
|
-
self, symbol_node: uni.AstSymbolNode, operation: str
|
|
172
|
-
) -> bool:
|
|
173
|
-
"""Handle simple symbol nodes (non-chain)."""
|
|
174
|
-
glob_sym = self.check_global(symbol_node.sym_name)
|
|
175
|
-
|
|
176
|
-
if glob_sym:
|
|
177
|
-
symbol_node.name_spec._sym = glob_sym
|
|
178
|
-
if operation == "define":
|
|
179
|
-
glob_sym.add_defn(symbol_node)
|
|
180
|
-
else: # operation == 'use'
|
|
181
|
-
glob_sym.add_use(symbol_node)
|
|
182
|
-
return True
|
|
183
|
-
else:
|
|
184
|
-
if operation == "define":
|
|
185
|
-
self.cur_scope.def_insert(symbol_node, single_decl="assignment")
|
|
186
|
-
else: # operation == 'use'
|
|
187
|
-
found_symbol = self.cur_scope.lookup(symbol_node.sym_name)
|
|
188
|
-
if found_symbol:
|
|
189
|
-
found_symbol.add_use(symbol_node)
|
|
190
|
-
else:
|
|
191
|
-
# Symbol not found, could be first use - define it
|
|
192
|
-
self.cur_scope.def_insert(symbol_node)
|
|
193
|
-
return True
|
|
194
|
-
|
|
195
|
-
#####################################
|
|
196
|
-
## Main logic for symbols creation ##
|
|
197
|
-
#####################################
|
|
198
|
-
def enter_assignment(self, node: uni.Assignment) -> None:
|
|
199
|
-
"""Enter assignment node."""
|
|
200
|
-
for target in node.target:
|
|
201
|
-
self._process_assignment_target(target)
|
|
202
|
-
|
|
203
|
-
def _process_assignment_target(self, target: uni.Expr) -> None:
|
|
204
|
-
"""Process individual assignment target."""
|
|
205
|
-
if isinstance(target, uni.AtomTrailer):
|
|
206
|
-
self.handle_symbol_chain(target, "define")
|
|
207
|
-
elif isinstance(target, uni.AstSymbolNode):
|
|
208
|
-
self.handle_simple_symbol(target, "define")
|
|
209
|
-
else:
|
|
210
|
-
pass
|
|
211
|
-
# TODO
|
|
212
|
-
# self.log_error("Assignment target not valid")
|
|
213
|
-
|
|
214
|
-
def enter_ability(self, node: uni.Ability) -> None:
|
|
215
|
-
"""Enter ability node and set up method context."""
|
|
216
|
-
assert node.parent_scope is not None
|
|
217
|
-
node.parent_scope.def_insert(node, access_spec=node, single_decl="ability")
|
|
218
|
-
|
|
219
|
-
if node.is_method:
|
|
220
|
-
self._setup_method_context(node)
|
|
221
|
-
|
|
222
|
-
def _setup_method_context(self, node: uni.Ability) -> None:
|
|
223
|
-
"""Set up method context by defining 'self', 'super', and event context symbols if needed."""
|
|
224
|
-
self_name = uni.Name.gen_stub_from_node(node, "self")
|
|
225
|
-
self.cur_scope.def_insert(self_name)
|
|
226
|
-
node.parent_of_type(uni.Archetype)
|
|
227
|
-
|
|
228
|
-
self.cur_scope.def_insert(
|
|
229
|
-
uni.Name.gen_stub_from_node(node, "super", set_name_of=node.method_owner)
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
if node.signature and isinstance(node.signature, uni.EventSignature):
|
|
233
|
-
self._setup_event_context(node)
|
|
234
|
-
|
|
235
|
-
def _setup_event_context(self, node: uni.Ability) -> None:
|
|
236
|
-
"""Set up 'here' and 'visitor' symbols for event signatures."""
|
|
237
|
-
try:
|
|
238
|
-
arch_type = node.method_owner.arch_type.name
|
|
239
|
-
|
|
240
|
-
if arch_type == "KW_WALKER":
|
|
241
|
-
self._setup_walker_context(node)
|
|
242
|
-
elif arch_type == "KW_NODE":
|
|
243
|
-
self._setup_node_context(node)
|
|
244
|
-
except Exception:
|
|
245
|
-
pass
|
|
246
|
-
# TODO
|
|
247
|
-
# self.log_error(f"Error while setting up event context: {str(e)}")
|
|
248
|
-
|
|
249
|
-
def _setup_walker_context(self, node: uni.Ability) -> None:
|
|
250
|
-
"""Init 'here' for walker; link symbol table to parent."""
|
|
251
|
-
self.cur_scope.def_insert(
|
|
252
|
-
uni.Name.gen_stub_from_node(node, "here", set_name_of=node.method_owner)
|
|
253
|
-
)
|
|
254
|
-
node_name = node.signature.arch_tag_info.unparse()
|
|
255
|
-
self.cur_scope.lookup(node_name).symbol_table
|
|
256
|
-
|
|
257
|
-
def _setup_node_context(self, node: uni.Ability) -> None:
|
|
258
|
-
"""Init 'visitor' for node; link symbol table to parent."""
|
|
259
|
-
self.cur_scope.def_insert(
|
|
260
|
-
uni.Name.gen_stub_from_node(node, "visitor", set_name_of=node.method_owner)
|
|
261
|
-
)
|
|
262
|
-
walker_name = node.signature.arch_tag_info.unparse()
|
|
263
|
-
self.cur_scope.lookup(walker_name).symbol_table
|
|
264
|
-
|
|
265
|
-
def enter_global_stmt(self, node: uni.GlobalStmt) -> None:
|
|
266
|
-
"""Enter global statement."""
|
|
267
|
-
for name in node.target:
|
|
268
|
-
sym = self.cur_module_scope.lookup(name.sym_name)
|
|
269
|
-
if not sym:
|
|
270
|
-
sym = self.cur_module_scope.def_insert(name, single_decl="assignment")
|
|
271
|
-
self.globals_stack[-1].append(sym)
|
|
272
|
-
|
|
273
|
-
def enter_import(self, node: uni.Import) -> None:
|
|
274
|
-
"""Enter import statement."""
|
|
275
|
-
if node.is_absorb:
|
|
276
|
-
return None
|
|
277
|
-
for item in node.items:
|
|
278
|
-
if item.alias:
|
|
279
|
-
self.cur_scope.def_insert(
|
|
280
|
-
item.alias, imported=True, single_decl="import"
|
|
281
|
-
)
|
|
282
|
-
else:
|
|
283
|
-
self.cur_scope.def_insert(item, imported=True)
|
|
284
|
-
|
|
285
|
-
def enter_test(self, node: uni.Test) -> None:
|
|
286
|
-
"""Enter test node and add unittest methods."""
|
|
287
|
-
import unittest
|
|
288
|
-
|
|
289
|
-
for method_name in [
|
|
290
|
-
j for j in dir(unittest.TestCase()) if j.startswith("assert")
|
|
291
|
-
]:
|
|
292
|
-
self.cur_scope.def_insert(
|
|
293
|
-
uni.Name.gen_stub_from_node(node, method_name, set_name_of=node)
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
def enter_archetype(self, node: uni.Archetype) -> None:
|
|
297
|
-
"""Enter archetype node."""
|
|
298
|
-
assert node.parent_scope is not None
|
|
299
|
-
node.parent_scope.def_insert(node, access_spec=node, single_decl="archetype")
|
|
300
|
-
|
|
301
|
-
def enter_impl_def(self, node: uni.ImplDef) -> None:
|
|
302
|
-
"""Enter implementation definition."""
|
|
303
|
-
assert node.parent_scope is not None
|
|
304
|
-
node.parent_scope.def_insert(node, single_decl="impl")
|
|
305
|
-
|
|
306
|
-
def enter_sem_def(self, node: uni.SemDef) -> None:
|
|
307
|
-
"""Enter semantic definition."""
|
|
308
|
-
assert node.parent_scope is not None
|
|
309
|
-
node.parent_scope.def_insert(node, single_decl="sem")
|
|
310
|
-
|
|
311
|
-
def enter_enum(self, node: uni.Enum) -> None:
|
|
312
|
-
"""Enter enum node."""
|
|
313
|
-
assert node.parent_scope is not None
|
|
314
|
-
node.parent_scope.def_insert(node, access_spec=node, single_decl="enum")
|
|
315
|
-
|
|
316
|
-
def enter_param_var(self, node: uni.ParamVar) -> None:
|
|
317
|
-
"""Enter parameter variable."""
|
|
318
|
-
self.cur_scope.def_insert(node)
|
|
319
|
-
|
|
320
|
-
def enter_has_var(self, node: uni.HasVar) -> None:
|
|
321
|
-
"""Enter has variable."""
|
|
322
|
-
if isinstance(node.parent, uni.ArchHas):
|
|
323
|
-
self.cur_scope.def_insert(
|
|
324
|
-
node, single_decl="has var", access_spec=node.parent
|
|
325
|
-
)
|
|
326
|
-
else:
|
|
327
|
-
self.ice("Inconsistency in AST, has var should be under arch has")
|
|
328
|
-
|
|
329
|
-
def enter_in_for_stmt(self, node: uni.InForStmt) -> None:
|
|
330
|
-
"""Enter for-in statement."""
|
|
331
|
-
self._process_assignment_target(node.target)
|
|
332
|
-
|
|
333
|
-
def enter_func_call(self, node: uni.FuncCall) -> None:
|
|
334
|
-
"""Enter function call node."""
|
|
335
|
-
if isinstance(node.target, uni.AtomTrailer):
|
|
336
|
-
self.handle_symbol_chain(node.target, "use")
|
|
337
|
-
elif isinstance(node.target, uni.AstSymbolNode):
|
|
338
|
-
if self._handle_builtin_symbol(node.target.sym_name, node.target):
|
|
339
|
-
return
|
|
340
|
-
|
|
341
|
-
self.handle_simple_symbol(node.target, "use")
|
|
342
|
-
else:
|
|
343
|
-
pass
|
|
344
|
-
# TODO
|
|
345
|
-
# self.log_error("Function call target not valid")
|
|
346
|
-
|
|
347
|
-
##################################
|
|
348
|
-
## Comprehensions support ##
|
|
349
|
-
##################################
|
|
350
|
-
def enter_list_compr(self, node: uni.ListCompr) -> None:
|
|
351
|
-
"""Enter list comprehension with correct traversal order."""
|
|
352
|
-
self.prune()
|
|
353
|
-
for compr in node.compr:
|
|
354
|
-
self.traverse(compr)
|
|
355
|
-
self.traverse(node.out_expr)
|
|
356
|
-
|
|
357
|
-
def enter_gen_compr(self, node: uni.GenCompr) -> None:
|
|
358
|
-
"""Enter generator comprehension."""
|
|
359
|
-
self.enter_list_compr(node)
|
|
360
|
-
|
|
361
|
-
def enter_set_compr(self, node: uni.SetCompr) -> None:
|
|
362
|
-
"""Enter set comprehension."""
|
|
363
|
-
self.enter_list_compr(node)
|
|
364
|
-
|
|
365
|
-
def enter_dict_compr(self, node: uni.DictCompr) -> None:
|
|
366
|
-
"""Enter dictionary comprehension."""
|
|
367
|
-
self.prune()
|
|
368
|
-
for compr in node.compr:
|
|
369
|
-
self.traverse(compr)
|
|
370
|
-
self.traverse(node.kv_pair)
|
|
371
|
-
|
|
372
|
-
def enter_inner_compr(self, node: uni.InnerCompr) -> None:
|
|
373
|
-
"""Enter inner comprehension."""
|
|
374
|
-
if isinstance(node.target, uni.AtomTrailer):
|
|
375
|
-
self.cur_scope.chain_def_insert(node.target.as_attr_list)
|
|
376
|
-
elif isinstance(node.target, uni.AstSymbolNode):
|
|
377
|
-
self.cur_scope.def_insert(node.target)
|
|
378
|
-
else:
|
|
379
|
-
pass
|
|
380
|
-
# TODO
|
|
381
|
-
# self.log_error("Named target not valid")
|
|
382
|
-
|
|
383
|
-
#####################
|
|
384
|
-
## Collecting uses ##
|
|
385
|
-
#####################
|
|
386
|
-
def exit_name(self, node: uni.Name) -> None:
|
|
387
|
-
"""Exit name node and record usage."""
|
|
388
|
-
if isinstance(node.parent, uni.AtomTrailer):
|
|
389
|
-
return
|
|
390
|
-
|
|
391
|
-
# Check if this is a builtin symbol first
|
|
392
|
-
if self._handle_builtin_symbol(node.value, node):
|
|
393
|
-
return
|
|
394
|
-
|
|
395
|
-
glob_sym = self.check_global(node.value)
|
|
396
|
-
if glob_sym:
|
|
397
|
-
if not node.sym:
|
|
398
|
-
glob_sym.add_use(node)
|
|
399
|
-
else:
|
|
400
|
-
self.cur_scope.use_lookup(node, sym_table=self.cur_scope)
|
|
401
|
-
|
|
402
|
-
def enter_builtin_type(self, node: uni.BuiltinType) -> None:
|
|
403
|
-
"""Enter builtins node like str, int, list, etc."""
|
|
404
|
-
self._handle_builtin_symbol(node.value, node)
|
|
405
|
-
|
|
406
|
-
def enter_expr_as_item(self, node: uni.ExprAsItem) -> None:
|
|
407
|
-
"""Enter expression as item (for with statements)."""
|
|
408
|
-
if node.alias:
|
|
409
|
-
self._process_assignment_target(node.alias)
|
|
410
|
-
|
|
411
|
-
############################
|
|
412
|
-
## Import Resolution Logic ##
|
|
413
|
-
############################
|
|
414
|
-
def resolve_import(self, node: uni.UniNode) -> None:
|
|
415
|
-
"""Resolve imports for atom trailers like 'apple.color.bla.blah'."""
|
|
416
|
-
if isinstance(node, uni.AtomTrailer):
|
|
417
|
-
self._resolve_atom_trailer_import(node)
|
|
418
|
-
else:
|
|
419
|
-
self.log_warning(
|
|
420
|
-
f"Import resolution not implemented for {type(node).__name__}"
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
def _resolve_assignment_imports(self, node: uni.Assignment) -> None:
|
|
424
|
-
"""Handle import resolution for assignment statements."""
|
|
425
|
-
for target in node.target:
|
|
426
|
-
if isinstance(target, uni.AtomTrailer):
|
|
427
|
-
self._resolve_atom_trailer_import(target)
|
|
428
|
-
|
|
429
|
-
def _resolve_for_loop_imports(self, node: uni.InForStmt) -> None:
|
|
430
|
-
"""Handle import resolution for for-loop statements."""
|
|
431
|
-
if isinstance(node.target, uni.AtomTrailer):
|
|
432
|
-
self._resolve_atom_trailer_import(node.target)
|
|
433
|
-
|
|
434
|
-
def _resolve_atom_trailer_import(self, atom_trailer: uni.AtomTrailer) -> None:
|
|
435
|
-
"""Resolve imports for atom trailer chains."""
|
|
436
|
-
attr_list = atom_trailer.as_attr_list
|
|
437
|
-
if not attr_list:
|
|
438
|
-
raise ValueError("Atom trailer must have at least one attribute")
|
|
439
|
-
|
|
440
|
-
first_obj = attr_list[0]
|
|
441
|
-
first_obj_sym = self.cur_scope.lookup(first_obj.sym_name)
|
|
442
|
-
if not first_obj_sym or not first_obj_sym.imported:
|
|
443
|
-
return
|
|
444
|
-
|
|
445
|
-
import_node = self._find_import_for_symbol(first_obj_sym)
|
|
446
|
-
if not import_node:
|
|
447
|
-
# TODO
|
|
448
|
-
# self.log_error(
|
|
449
|
-
# f"Could not find import statement for symbol '{first_obj_sym.sym_name}'"
|
|
450
|
-
# )
|
|
451
|
-
return
|
|
452
|
-
|
|
453
|
-
module_path = self._get_module_path_from_symbol(first_obj_sym)
|
|
454
|
-
if not module_path:
|
|
455
|
-
# TODO
|
|
456
|
-
# self.log_error("Could not resolve module path for import")
|
|
457
|
-
return
|
|
458
|
-
|
|
459
|
-
linked_module = self._parse_and_link_module(module_path, first_obj_sym)
|
|
460
|
-
if linked_module:
|
|
461
|
-
self._link_attribute_chain(attr_list, first_obj_sym, linked_module)
|
|
462
|
-
|
|
463
|
-
def _find_import_for_symbol(self, symbol: uni.Symbol) -> Optional[uni.Import]:
|
|
464
|
-
"""Find the import statement that declares the given symbol."""
|
|
465
|
-
if not symbol.decl:
|
|
466
|
-
return None
|
|
467
|
-
|
|
468
|
-
import_node: uni.Import = symbol.decl.find_parent_of_type(uni.Import)
|
|
469
|
-
if import_node:
|
|
470
|
-
return import_node
|
|
471
|
-
self.ice(f"Symbol '{symbol.sym_name}' does not have a valid import declaration")
|
|
472
|
-
return None
|
|
473
|
-
|
|
474
|
-
# TODO: this is an important function: it should support all 7 types of imports here
|
|
475
|
-
def _get_module_path_from_symbol(self, symbol: uni.Symbol) -> Optional[str]:
|
|
476
|
-
"""Extract module path from symbol's import declaration."""
|
|
477
|
-
mod_item_node = symbol.decl.find_parent_of_type(uni.ModuleItem)
|
|
478
|
-
if mod_item_node:
|
|
479
|
-
mod_path_node = mod_item_node.find_parent_of_type(uni.Import).from_loc
|
|
480
|
-
else:
|
|
481
|
-
mod_path_node = symbol.decl.find_parent_of_type(uni.ModulePath)
|
|
482
|
-
|
|
483
|
-
return mod_path_node.resolve_relative_path() if mod_path_node else None
|
|
484
|
-
|
|
485
|
-
def _link_attribute_chain(
|
|
486
|
-
self,
|
|
487
|
-
attr_list: list[uni.AstSymbolNode],
|
|
488
|
-
first_symbol: uni.Symbol,
|
|
489
|
-
current_module: uni.Module,
|
|
490
|
-
) -> None:
|
|
491
|
-
"""Link the full attribute chain by resolving each symbol."""
|
|
492
|
-
current_symbol = first_symbol
|
|
493
|
-
current_sym_table = current_module.sym_tab
|
|
494
|
-
|
|
495
|
-
# Add use for the first symbol
|
|
496
|
-
first_obj = attr_list[0]
|
|
497
|
-
current_symbol.add_use(first_obj)
|
|
498
|
-
|
|
499
|
-
# Iterate through remaining attributes in the chain
|
|
500
|
-
for attr_node in attr_list[1:]:
|
|
501
|
-
if not current_sym_table:
|
|
502
|
-
return
|
|
503
|
-
|
|
504
|
-
attr_symbol = current_sym_table.lookup(attr_node.sym_name)
|
|
505
|
-
if not attr_symbol:
|
|
506
|
-
# self.log_error(
|
|
507
|
-
# f"Could not resolve attribute '{attr_node.sym_name}' in chain"
|
|
508
|
-
# )
|
|
509
|
-
# TODO:
|
|
510
|
-
break
|
|
511
|
-
|
|
512
|
-
attr_symbol.add_use(attr_node)
|
|
513
|
-
current_symbol = attr_symbol
|
|
514
|
-
current_sym_table = current_symbol.symbol_table
|
|
515
|
-
|
|
516
|
-
# TODO:move this to Jac Program
|
|
517
|
-
def _parse_and_link_module(
|
|
518
|
-
self, module_path: str, symbol: uni.Symbol
|
|
519
|
-
) -> Optional[uni.Module]:
|
|
520
|
-
"""Parse the module and link it to the symbol."""
|
|
521
|
-
try:
|
|
522
|
-
if module_path in self.prog.mod.hub:
|
|
523
|
-
existing_module = self.prog.mod.hub[module_path]
|
|
524
|
-
# symbol.symbol_table = existing_module.sym_tab
|
|
525
|
-
return existing_module
|
|
526
|
-
|
|
527
|
-
source_str = read_file_with_encoding(module_path)
|
|
528
|
-
|
|
529
|
-
parsed_module: uni.Module = self.prog.parse_str(
|
|
530
|
-
source_str=source_str, file_path=module_path
|
|
531
|
-
)
|
|
532
|
-
BinderPass(ir_in=parsed_module, prog=self.prog)
|
|
533
|
-
# symbol.symbol_table = parsed_module.sym_tab
|
|
534
|
-
|
|
535
|
-
return parsed_module
|
|
536
|
-
|
|
537
|
-
except Exception:
|
|
538
|
-
# TODO
|
|
539
|
-
# self.log_error(f"Failed to parse module '{module_path}': {str(e)}")
|
|
540
|
-
return None
|
|
541
|
-
|
|
542
|
-
def load_builtins(self) -> None:
|
|
543
|
-
"""Load built-in symbols from the builtins.pyi file."""
|
|
544
|
-
try:
|
|
545
|
-
builtins_path = os.path.join(
|
|
546
|
-
os.path.dirname(__file__),
|
|
547
|
-
"../../../vendor/typeshed/stdlib/builtins.pyi",
|
|
548
|
-
)
|
|
549
|
-
|
|
550
|
-
# lets keep this line until typeshed are merged with jaclang
|
|
551
|
-
if not os.path.exists(builtins_path):
|
|
552
|
-
self.log_warning(f"Builtins file not found at {builtins_path}")
|
|
553
|
-
return
|
|
554
|
-
|
|
555
|
-
file_source = read_file_with_encoding(builtins_path)
|
|
556
|
-
|
|
557
|
-
from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
|
|
558
|
-
|
|
559
|
-
mod = PyastBuildPass(
|
|
560
|
-
ir_in=uni.PythonModuleAst(
|
|
561
|
-
py_ast.parse(file_source),
|
|
562
|
-
orig_src=uni.Source(file_source, builtins_path),
|
|
563
|
-
),
|
|
564
|
-
prog=self.prog,
|
|
565
|
-
).ir_out
|
|
566
|
-
|
|
567
|
-
if mod:
|
|
568
|
-
self.prog.mod.hub["builtins"] = mod
|
|
569
|
-
BinderPass(ir_in=mod, prog=self.prog)
|
|
570
|
-
|
|
571
|
-
except Exception as e:
|
|
572
|
-
self.log_error(f"Failed to load builtins: {str(e)}")
|
|
573
|
-
|
|
574
|
-
def _is_builtin_symbol(self, symbol_name: str) -> bool:
|
|
575
|
-
"""Check if a symbol is a builtin symbol."""
|
|
576
|
-
builtins_mod = self.prog.mod.hub["builtins"]
|
|
577
|
-
return symbol_name in builtins_mod.sym_tab.names_in_scope
|
|
578
|
-
|
|
579
|
-
def _handle_builtin_symbol(
|
|
580
|
-
self, symbol_name: str, target_node: uni.AstSymbolNode
|
|
581
|
-
) -> bool:
|
|
582
|
-
"""Handle builtin symbol lookup and linking."""
|
|
583
|
-
if not self._is_builtin_symbol(symbol_name):
|
|
584
|
-
return False
|
|
585
|
-
|
|
586
|
-
builtins_mod = self.prog.mod.hub["builtins"]
|
|
587
|
-
builtin_symbol = builtins_mod.sym_tab.lookup(symbol_name)
|
|
588
|
-
|
|
589
|
-
if not builtin_symbol:
|
|
590
|
-
return False
|
|
591
|
-
|
|
592
|
-
target_node.name_spec._sym = builtin_symbol
|
|
593
|
-
builtin_symbol.add_use(target_node)
|
|
594
|
-
return True
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import M1;
|
|
2
|
-
# import M2 as m2alias;
|
|
3
|
-
# import M3, M4;
|
|
4
|
-
# import M5 as m5alias, M6 as m6alias;
|
|
5
|
-
# import from M7 {M7S1}
|
|
6
|
-
# import from M8 {M8S1 as m8s1alias, M8S2 as m8s2alias}
|
|
7
|
-
# include M9;
|
|
8
|
-
# glob a = 5, k = 9;
|
|
9
|
-
glob aa = 9;
|
|
10
|
-
with entry{
|
|
11
|
-
Y: int;
|
|
12
|
-
Y = 0;
|
|
13
|
-
# b.Person.ss = 9;
|
|
14
|
-
n = 0;
|
|
15
|
-
z = Y;
|
|
16
|
-
aa = 9;
|
|
17
|
-
}
|
|
18
|
-
with entry {
|
|
19
|
-
Y = 99;
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
def ccc() {
|
|
23
|
-
# aa = 99; #Error:name 'aa' is assigned to before global declaration
|
|
24
|
-
if (0) {
|
|
25
|
-
global aa;
|
|
26
|
-
global bb;
|
|
27
|
-
aa = 88;
|
|
28
|
-
bb = 0;
|
|
29
|
-
p = 90;
|
|
30
|
-
M1.k = 0;
|
|
31
|
-
}
|
|
32
|
-
aa = 99;
|
|
33
|
-
print(aa);
|
|
34
|
-
}
|
|
35
|
-
with entry {
|
|
36
|
-
ccc();
|
|
37
|
-
print(aa);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# import random;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# with entry{
|
|
46
|
-
# d = random.randint(1, 100);
|
|
47
|
-
# }
|