hython-lang 2.0.0__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.
- hython/__init__.py +15 -0
- hython/__main__.py +3 -0
- hython/bytecode.py +368 -0
- hython/cli.py +449 -0
- hython/compiler.py +870 -0
- hython/compiler_manager.py +227 -0
- hython/diagnostics.py +158 -0
- hython/environment.py +48 -0
- hython/exe_builder.py +330 -0
- hython/frontend.py +870 -0
- hython/hir.py +93 -0
- hython/importer.py +76 -0
- hython/package_manager.py +343 -0
- hython/phonetics.py +49 -0
- hython/runtime.py +110 -0
- hython/runtime_manager.py +83 -0
- hython/translator.py +244 -0
- hython/updater.py +93 -0
- hython/vm.py +2409 -0
- hython/vocabulary.py +132 -0
- hython_lang-2.0.0.dist-info/METADATA +327 -0
- hython_lang-2.0.0.dist-info/RECORD +26 -0
- hython_lang-2.0.0.dist-info/WHEEL +5 -0
- hython_lang-2.0.0.dist-info/entry_points.txt +2 -0
- hython_lang-2.0.0.dist-info/licenses/LICENSE +22 -0
- hython_lang-2.0.0.dist-info/top_level.txt +1 -0
hython/compiler.py
ADDED
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
"""Bootstrap compiler from Hython source into independent HBC instructions."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import io
|
|
4
|
+
import tokenize
|
|
5
|
+
from .bytecode import CodeObject
|
|
6
|
+
from .hir import HIRCode, optimize_hir
|
|
7
|
+
from .frontend import Node, parse
|
|
8
|
+
|
|
9
|
+
class CompileError(SyntaxError):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def _target_names(node:Node) -> set[str]:
|
|
13
|
+
if node.kind=="name": return {node.value}
|
|
14
|
+
if node.kind=="starred": return _target_names(node.children[0])
|
|
15
|
+
if node.kind in ("tuple","list"):
|
|
16
|
+
result=set()
|
|
17
|
+
for child in node.children: result.update(_target_names(child))
|
|
18
|
+
return result
|
|
19
|
+
return set()
|
|
20
|
+
|
|
21
|
+
def _find_nodes(node:Node,kinds:set[str]) -> list[Node]:
|
|
22
|
+
found=[node] if node.kind in kinds else []
|
|
23
|
+
if node.kind in ("def","class","lambda"): return found
|
|
24
|
+
for child in node.children: found.extend(_find_nodes(child,kinds))
|
|
25
|
+
return found
|
|
26
|
+
|
|
27
|
+
def _find_nodes_deep(node:Node,kinds:set[str]) -> list[Node]:
|
|
28
|
+
"""Find syntax even across nested scope nodes when the grammar rule is lexical."""
|
|
29
|
+
found=[node] if node.kind in kinds else []
|
|
30
|
+
for child in node.children: found.extend(_find_nodes_deep(child,kinds))
|
|
31
|
+
return found
|
|
32
|
+
|
|
33
|
+
def _scope_bindings(nodes:list[Node]) -> set[str]:
|
|
34
|
+
result=set()
|
|
35
|
+
for node in nodes:
|
|
36
|
+
if node.kind in ("def","class"):
|
|
37
|
+
result.add(node.value[0]); continue
|
|
38
|
+
if node.kind=="assign": result.update(_target_names(node.children[0]))
|
|
39
|
+
elif node.kind=="annassign": result.update(_target_names(node.children[0]))
|
|
40
|
+
elif node.kind=="augassign": result.update(_target_names(node.children[0]))
|
|
41
|
+
elif node.kind=="assign_chain":
|
|
42
|
+
for target in node.children[:-1]: result.update(_target_names(target))
|
|
43
|
+
elif node.kind in ("del","dels"):
|
|
44
|
+
for target in (node.children if node.kind=="dels" else node.children[:1]): result.update(_target_names(target))
|
|
45
|
+
elif node.kind in ("for","async_for"): result.update(_target_names(node.value))
|
|
46
|
+
elif node.kind in ("with","async_with"):
|
|
47
|
+
for item in node.children[0].children:
|
|
48
|
+
if len(item.children)>1: result.update(_target_names(item.children[1]))
|
|
49
|
+
elif node.kind=="try":
|
|
50
|
+
for handler in node.children[1].children:
|
|
51
|
+
if handler.value[1]: result.add(handler.value[1])
|
|
52
|
+
elif node.kind=="type_alias": result.add(node.value[0])
|
|
53
|
+
elif node.kind in ("pattern_capture","pattern_star") and node.value!="_": result.add(node.value)
|
|
54
|
+
elif node.kind in ("import","imports"):
|
|
55
|
+
imports=[node.value] if node.kind=="import" else node.value
|
|
56
|
+
result.update(alias for _,alias in imports)
|
|
57
|
+
elif node.kind=="fromimport": result.update(alias for name,alias in node.value[1] if name!="*")
|
|
58
|
+
elif node.kind=="namedexpr": result.add(node.value)
|
|
59
|
+
for child in node.children: result.update(_scope_bindings([child]))
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
def _scope_declarations(nodes:list[Node]):
|
|
63
|
+
globals_=set(); nonlocals=set()
|
|
64
|
+
def visit(node):
|
|
65
|
+
if node.kind in ("def","class","lambda"): return
|
|
66
|
+
if node.kind=="global": globals_.update(node.value); return
|
|
67
|
+
if node.kind=="nonlocal": nonlocals.update(node.value); return
|
|
68
|
+
for child in node.children: visit(child)
|
|
69
|
+
for node in nodes: visit(node)
|
|
70
|
+
return globals_,nonlocals
|
|
71
|
+
|
|
72
|
+
def _validate_declarations(nodes:list[Node],parameters=frozenset()):
|
|
73
|
+
globals_=set(); nonlocals=set(); seen={}
|
|
74
|
+
def mark(name,line,kind): seen.setdefault(name,(line,kind))
|
|
75
|
+
def target(node,line):
|
|
76
|
+
if node.kind=="name": mark(node.value,line,"대입"); return
|
|
77
|
+
if node.kind=="starred": target(node.children[0],line); return
|
|
78
|
+
if node.kind in ("tuple","list"):
|
|
79
|
+
for child in node.children: target(child,line)
|
|
80
|
+
return
|
|
81
|
+
for child in node.children: visit(child)
|
|
82
|
+
def definition_inputs(node):
|
|
83
|
+
if node.kind=="def":
|
|
84
|
+
for value in node.value[2].values(): visit(value)
|
|
85
|
+
elif node.kind=="class":
|
|
86
|
+
descriptors=node.value[4] if len(node.value)>4 else []
|
|
87
|
+
if descriptors:
|
|
88
|
+
for descriptor in descriptors: visit(descriptor[2])
|
|
89
|
+
else:
|
|
90
|
+
for base in node.value[1]: visit(base)
|
|
91
|
+
def visit(node):
|
|
92
|
+
if node.kind=="global":
|
|
93
|
+
for name in node.value:
|
|
94
|
+
if name in parameters: raise CompileError(f"매개변수와 글로벌 선언 충돌: {name} (줄 {node.line})")
|
|
95
|
+
if name in nonlocals: raise CompileError(f"글로벌과 논로컬 선언 충돌: {name} (줄 {node.line})")
|
|
96
|
+
if name in seen: raise CompileError(f"{seen[name][1]} 뒤의 글로벌 선언: {name} (줄 {node.line})")
|
|
97
|
+
globals_.add(name)
|
|
98
|
+
return
|
|
99
|
+
if node.kind=="nonlocal":
|
|
100
|
+
for name in node.value:
|
|
101
|
+
if name in parameters: raise CompileError(f"매개변수와 논로컬 선언 충돌: {name} (줄 {node.line})")
|
|
102
|
+
if name in globals_: raise CompileError(f"글로벌과 논로컬 선언 충돌: {name} (줄 {node.line})")
|
|
103
|
+
if name in seen: raise CompileError(f"{seen[name][1]} 뒤의 논로컬 선언: {name} (줄 {node.line})")
|
|
104
|
+
nonlocals.add(name)
|
|
105
|
+
return
|
|
106
|
+
if node.kind in ("def","class"):
|
|
107
|
+
definition_inputs(node)
|
|
108
|
+
mark(node.value[0],node.line,"대입"); return
|
|
109
|
+
if node.kind=="decorated":
|
|
110
|
+
for decorator in node.children[:-1]: visit(decorator)
|
|
111
|
+
target_node=node.children[-1]; definition_inputs(target_node); mark(target_node.value[0],target_node.line,"대입"); return
|
|
112
|
+
if node.kind=="assign": visit(node.children[1]); target(node.children[0],node.line); return
|
|
113
|
+
if node.kind=="assign_chain":
|
|
114
|
+
visit(node.children[-1])
|
|
115
|
+
for item in node.children[:-1]: target(item,node.line)
|
|
116
|
+
return
|
|
117
|
+
if node.kind=="augassign": visit(node.children[0]); visit(node.children[1]); target(node.children[0],node.line); return
|
|
118
|
+
if node.kind in ("for","async_for"):
|
|
119
|
+
visit(node.children[0]); target(node.value,node.line)
|
|
120
|
+
for child in node.children[1:]: visit(child)
|
|
121
|
+
return
|
|
122
|
+
if node.kind=="name": mark(node.value,node.line,"사용"); return
|
|
123
|
+
for child in node.children: visit(child)
|
|
124
|
+
for node in nodes: visit(node)
|
|
125
|
+
|
|
126
|
+
def _validate_future_imports(nodes:list[Node]) -> None:
|
|
127
|
+
import __future__
|
|
128
|
+
known=set(__future__.all_feature_names)
|
|
129
|
+
future_zone=True
|
|
130
|
+
for index,node in enumerate(nodes):
|
|
131
|
+
is_future=node.kind=="fromimport" and node.value[0]=="__future__"
|
|
132
|
+
if is_future:
|
|
133
|
+
if not future_zone: raise CompileError(f"__future__ import는 파일 시작 부분에 있어야 합니다 (줄 {node.line})")
|
|
134
|
+
for name,_ in node.value[1]:
|
|
135
|
+
if name=="braces": raise CompileError(f"future 기능 braces는 지원될 가능성이 없습니다 (줄 {node.line})")
|
|
136
|
+
if name not in known: raise CompileError(f"정의되지 않은 future 기능: {name} (줄 {node.line})")
|
|
137
|
+
continue
|
|
138
|
+
is_docstring=index==0 and node.kind=="expr" and node.children and node.children[0].kind=="constant" and isinstance(node.children[0].value,str)
|
|
139
|
+
if not is_docstring: future_zone=False
|
|
140
|
+
def reject_nested(current):
|
|
141
|
+
if current.kind=="fromimport" and current.value[0]=="__future__": raise CompileError(f"__future__ import는 파일 시작 부분에 있어야 합니다 (줄 {current.line})")
|
|
142
|
+
for child in current.children: reject_nested(child)
|
|
143
|
+
reject_nested(node)
|
|
144
|
+
|
|
145
|
+
def _validate_context(nodes:list[Node],in_function=False,in_async=False,enclosing=(),current_scope=frozenset(),in_class=False,in_except_star=False,in_async_generator=False,loop_depth=0):
|
|
146
|
+
for node in nodes:
|
|
147
|
+
if node.kind=="return" and not in_function: raise CompileError(f"함수 밖의 리턴 (줄 {node.line})")
|
|
148
|
+
if node.kind=="return" and in_async_generator and bool(node.value): raise CompileError(f"비동기 제너레이터는 값을 리턴할 수 없습니다 (줄 {node.line})")
|
|
149
|
+
if in_except_star and node.kind in ("return","break","continue"): raise CompileError(f"익셉트* 안의 {node.kind}는 허용되지 않습니다 (줄 {node.line})")
|
|
150
|
+
if node.kind in ("yield","yield_from","yield_expr","yield_from_expr") and not in_function: raise CompileError(f"함수 밖의 일드 (줄 {node.line})")
|
|
151
|
+
if in_async and node.kind in ("yield_from","yield_from_expr"): raise CompileError(f"어싱크 함수 안의 yield from은 허용되지 않습니다 (줄 {node.line})")
|
|
152
|
+
if node.kind in ("break","continue") and loop_depth==0: raise CompileError(f"루프 밖의 {node.kind} (줄 {node.line})")
|
|
153
|
+
if node.kind=="fromimport" and (in_function or in_class) and any(name=="*" for name,_ in node.value[1]): raise CompileError(f"모듈 범위 밖의 import *는 허용되지 않습니다 (줄 {node.line})")
|
|
154
|
+
if node.kind=="await" and not in_async: raise CompileError(f"어싱크 함수 밖의 어웨이트 (줄 {node.line})")
|
|
155
|
+
if node.kind in ("async_for","async_with") and not in_async: raise CompileError(f"어싱크 함수 밖의 {node.kind} (줄 {node.line})")
|
|
156
|
+
if node.kind in ("listcomp","setcomp","dictcomp") and not in_async and any(clause.value[1] for clause in node.children[1:] if clause.kind=="comp_clause"):
|
|
157
|
+
raise CompileError(f"어싱크 함수 밖의 비동기 컴프리헨션 (줄 {node.line})")
|
|
158
|
+
if node.kind in ("listcomp","setcomp","dictcomp","generatorexpr"):
|
|
159
|
+
clauses=[clause for clause in node.children[1:] if clause.kind=="comp_clause"]
|
|
160
|
+
iteration_names=set()
|
|
161
|
+
for clause in clauses: iteration_names.update(_target_names(clause.value[0]))
|
|
162
|
+
named=_find_nodes(node,{"namedexpr"}); named_names={item.value for item in named}
|
|
163
|
+
if iteration_names & named_names: raise CompileError(f"컴프리헨션 반복 변수는 :=로 다시 바인딩할 수 없습니다 (줄 {node.line})")
|
|
164
|
+
if any(_find_nodes_deep(clause.children[0],{"namedexpr"}) for clause in clauses): raise CompileError(f"컴프리헨션 iterable 안의 :=는 허용되지 않습니다 (줄 {node.line})")
|
|
165
|
+
if _find_nodes(node,{"yield","yield_from","yield_expr","yield_from_expr"}): raise CompileError(f"컴프리헨션 안의 일드는 허용되지 않습니다 (줄 {node.line})")
|
|
166
|
+
if in_class and named: raise CompileError(f"클래스 컴프리헨션 안의 :=는 허용되지 않습니다 (줄 {node.line})")
|
|
167
|
+
if node.kind=="nonlocal":
|
|
168
|
+
for name in node.value:
|
|
169
|
+
if not any(name in scope for scope in enclosing): raise CompileError(f"바인딩되지 않은 논로컬 이름: {name} (줄 {node.line})")
|
|
170
|
+
if node.kind=="def":
|
|
171
|
+
params=node.value[1]; vararg=node.value[3]; kwarg=node.value[4]; kwonly=node.value[5]
|
|
172
|
+
bindings=_scope_bindings(node.children)|set(params)|set(kwonly)
|
|
173
|
+
if vararg: bindings.add(vararg)
|
|
174
|
+
if kwarg: bindings.add(kwarg)
|
|
175
|
+
_validate_declarations(node.children,frozenset(set(params)|set(kwonly)|({vararg} if vararg else set())|({kwarg} if kwarg else set())))
|
|
176
|
+
outer=(*enclosing,current_scope) if in_function else enclosing
|
|
177
|
+
is_async_generator=node.value[6] and any(_find_nodes(item,{"yield","yield_from","yield_expr","yield_from_expr"}) for item in node.children)
|
|
178
|
+
_validate_context(node.children,True,node.value[6],outer,frozenset(bindings),False,False,is_async_generator,0); continue
|
|
179
|
+
if node.kind=="class":
|
|
180
|
+
_validate_declarations(node.children)
|
|
181
|
+
outer=(*enclosing,current_scope) if in_function else enclosing
|
|
182
|
+
_validate_context(node.children,False,False,outer,frozenset(),True,False,False,0); continue
|
|
183
|
+
if node.kind=="lambda":
|
|
184
|
+
outer=(*enclosing,current_scope) if in_function else enclosing
|
|
185
|
+
_validate_context(node.children,True,False,outer,frozenset(),False,False,False,0); continue
|
|
186
|
+
if node.kind=="except":
|
|
187
|
+
_validate_context(node.children,in_function,in_async,enclosing,current_scope,in_class,in_except_star or node.value[2],in_async_generator,loop_depth); continue
|
|
188
|
+
if node.kind in ("for","async_for","while"):
|
|
189
|
+
_validate_context(node.children[:1],in_function,in_async,enclosing,current_scope,in_class,in_except_star,in_async_generator,loop_depth)
|
|
190
|
+
_validate_context(node.children[1:2],in_function,in_async,enclosing,current_scope,in_class,in_except_star,in_async_generator,loop_depth+1)
|
|
191
|
+
_validate_context(node.children[2:],in_function,in_async,enclosing,current_scope,in_class,in_except_star,in_async_generator,loop_depth)
|
|
192
|
+
continue
|
|
193
|
+
_validate_context(node.children,in_function,in_async,enclosing,current_scope,in_class,in_except_star,in_async_generator,loop_depth)
|
|
194
|
+
|
|
195
|
+
class Compiler:
|
|
196
|
+
def __init__(self, name: str = "<모듈>", parameters: list[str] | None = None, signal_returns: bool = False,
|
|
197
|
+
evaluate_annotations: bool = True, private_class: str | None = None):
|
|
198
|
+
self.private_class=private_class
|
|
199
|
+
self.code = HIRCode(name, [self.mangle(item) for item in (parameters or [])], [], [])
|
|
200
|
+
self.loops: list[tuple[int,list[int],bool]] = []
|
|
201
|
+
self.global_names: set[str] = set()
|
|
202
|
+
self.nonlocal_names: set[str] = set()
|
|
203
|
+
self.temp_counter=0
|
|
204
|
+
self.signal_returns=signal_returns
|
|
205
|
+
self.evaluate_annotations=evaluate_annotations
|
|
206
|
+
self.current_line=0
|
|
207
|
+
self.defer_definition_store=False
|
|
208
|
+
self.definition_firstlineno=None
|
|
209
|
+
|
|
210
|
+
def mangle(self,name:str) -> str:
|
|
211
|
+
if not self.private_class or not isinstance(name,str) or not name.startswith("__") or name.endswith("__") or "." in name: return name
|
|
212
|
+
class_name=self.private_class.lstrip("_")
|
|
213
|
+
return f"_{class_name}{name}" if class_name else name
|
|
214
|
+
|
|
215
|
+
def mangle_path(self,path:str) -> str:
|
|
216
|
+
return ".".join(self.mangle(part) for part in path.split("."))
|
|
217
|
+
|
|
218
|
+
def emit(self, op: str, arg=None) -> int:
|
|
219
|
+
instruction = [op] if arg is None else [op, arg]
|
|
220
|
+
self.code.instructions.append(instruction)
|
|
221
|
+
self.code.lines.append(self.current_line)
|
|
222
|
+
return len(self.code.instructions) - 1
|
|
223
|
+
|
|
224
|
+
def patch(self, index: int, target: int) -> None:
|
|
225
|
+
self.code.instructions[index][1] = target
|
|
226
|
+
|
|
227
|
+
def name_scope(self,name:str) -> str:
|
|
228
|
+
name=self.mangle(name)
|
|
229
|
+
return "global" if name in self.global_names else "nonlocal" if name in self.nonlocal_names else "local"
|
|
230
|
+
|
|
231
|
+
def store_name(self,name:str) -> None:
|
|
232
|
+
name=self.mangle(name)
|
|
233
|
+
self.emit("STORE_GLOBAL" if name in self.global_names else "STORE_NONLOCAL" if name in self.nonlocal_names else "STORE",name)
|
|
234
|
+
|
|
235
|
+
def delete_target(self,target:Node) -> None:
|
|
236
|
+
if target.kind in ("tuple","list"):
|
|
237
|
+
for child in target.children: self.delete_target(child)
|
|
238
|
+
elif target.kind=="name":
|
|
239
|
+
name=self.mangle(target.value); self.emit("DELETE_GLOBAL" if name in self.global_names else "DELETE_NONLOCAL" if name in self.nonlocal_names else "DELETE",name)
|
|
240
|
+
elif target.kind=="attribute": self.expression(target.children[0]); self.emit("DELETE_ATTR",self.mangle(target.value))
|
|
241
|
+
elif target.kind=="subscript": self.expression(target.children[0]); self.expression(target.children[1]); self.emit("DELETE_ITEM")
|
|
242
|
+
else: self.unsupported(target)
|
|
243
|
+
|
|
244
|
+
def constant(self, value) -> int:
|
|
245
|
+
self.code.constants.append(value)
|
|
246
|
+
return len(self.code.constants) - 1
|
|
247
|
+
|
|
248
|
+
@staticmethod
|
|
249
|
+
def docstring(nodes:list[Node]):
|
|
250
|
+
if nodes and nodes[0].kind=="expr" and nodes[0].children and nodes[0].children[0].kind=="constant" and isinstance(nodes[0].children[0].value,str):
|
|
251
|
+
return nodes[0].children[0].value
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def annotation_node(value): return value[0] if isinstance(value,tuple) else value
|
|
256
|
+
def annotation_text(self,value):
|
|
257
|
+
text=value[1] if isinstance(value,tuple) else ""
|
|
258
|
+
if not self.private_class or "__" not in text: return text
|
|
259
|
+
replacements=[]
|
|
260
|
+
try:
|
|
261
|
+
tokens=tokenize.generate_tokens(io.StringIO(text).readline)
|
|
262
|
+
for token in tokens:
|
|
263
|
+
if token.type==tokenize.NAME:
|
|
264
|
+
mangled=self.mangle(token.string)
|
|
265
|
+
if mangled!=token.string: replacements.append((token.start[1],token.end[1],mangled))
|
|
266
|
+
except (IndentationError,tokenize.TokenError):
|
|
267
|
+
return text
|
|
268
|
+
for start,end,replacement in reversed(replacements): text=text[:start]+replacement+text[end:]
|
|
269
|
+
return text
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def static_attributes(nodes:list[Node]) -> list[str]:
|
|
273
|
+
names=set()
|
|
274
|
+
def target(node):
|
|
275
|
+
if node.kind=="attribute" and node.children and node.children[0].kind=="name" and node.children[0].value=="self": names.add(node.value)
|
|
276
|
+
elif node.kind=="starred": target(node.children[0])
|
|
277
|
+
elif node.kind in ("tuple","list"):
|
|
278
|
+
for child in node.children: target(child)
|
|
279
|
+
def visit(node,inside_function=False):
|
|
280
|
+
if node.kind=="class": return
|
|
281
|
+
if node.kind=="decorated":
|
|
282
|
+
visit(node.children[-1],inside_function); return
|
|
283
|
+
if node.kind in ("def","lambda"):
|
|
284
|
+
for child in node.children: visit(child,True)
|
|
285
|
+
return
|
|
286
|
+
if not inside_function: return
|
|
287
|
+
if node.kind in ("assign","annassign","augassign") and (node.kind!="annassign" or len(node.children)>2): target(node.children[0])
|
|
288
|
+
elif node.kind=="assign_chain":
|
|
289
|
+
for item in node.children[:-1]: target(item)
|
|
290
|
+
elif node.kind in ("for","async_for"): target(node.value)
|
|
291
|
+
elif node.kind in ("with","async_with"):
|
|
292
|
+
for item in node.children[0].children:
|
|
293
|
+
if len(item.children)>1: target(item.children[1])
|
|
294
|
+
for child in node.children: visit(child,inside_function)
|
|
295
|
+
for node in nodes: visit(node)
|
|
296
|
+
return sorted(names)
|
|
297
|
+
|
|
298
|
+
def expression_code(self,node:Node,label:str) -> HIRCode:
|
|
299
|
+
child=self.scope_child(f"{self.code.name}:{label}")
|
|
300
|
+
child.expression(node); child.emit("RETURN")
|
|
301
|
+
return child.code
|
|
302
|
+
|
|
303
|
+
def scope_child(self,name:str,signal_returns:bool=False) -> "Compiler":
|
|
304
|
+
child=Compiler(name,[],signal_returns,evaluate_annotations=self.evaluate_annotations,private_class=self.private_class)
|
|
305
|
+
child.global_names=set(self.global_names)
|
|
306
|
+
child.nonlocal_names=set(self.nonlocal_names)
|
|
307
|
+
return child
|
|
308
|
+
|
|
309
|
+
@staticmethod
|
|
310
|
+
def has_yield(nodes:list[Node]) -> bool:
|
|
311
|
+
for node in nodes:
|
|
312
|
+
if node.kind in ("yield","yield_from","yield_expr","yield_from_expr"): return True
|
|
313
|
+
if node.kind not in ("def","class","lambda") and Compiler.has_yield(node.children): return True
|
|
314
|
+
return False
|
|
315
|
+
|
|
316
|
+
@staticmethod
|
|
317
|
+
def has_await(nodes:list[Node]) -> bool:
|
|
318
|
+
for node in nodes:
|
|
319
|
+
if node.kind=="await": return True
|
|
320
|
+
if node.kind not in ("def","class","lambda") and Compiler.has_await(node.children): return True
|
|
321
|
+
return False
|
|
322
|
+
|
|
323
|
+
@staticmethod
|
|
324
|
+
def named_expression_targets(node:Node) -> set[str]:
|
|
325
|
+
if node.kind=="namedexpr": return {node.value} | Compiler.named_expression_targets(node.children[0])
|
|
326
|
+
if node.kind in ("lambda","def","class"): return set()
|
|
327
|
+
result=set()
|
|
328
|
+
for child in node.children: result.update(Compiler.named_expression_targets(child))
|
|
329
|
+
return result
|
|
330
|
+
|
|
331
|
+
def pattern_spec(self,node:Node):
|
|
332
|
+
if node.kind=="pattern_wildcard": return {"kind":"wildcard"}
|
|
333
|
+
if node.kind=="pattern_capture": return {"kind":"capture","name":self.mangle(node.value),"scope":self.name_scope(node.value)}
|
|
334
|
+
if node.kind=="pattern_literal":
|
|
335
|
+
value=node.children[0]
|
|
336
|
+
if value.kind!="constant": self.unsupported(value)
|
|
337
|
+
return {"kind":"singleton" if value.value is None or type(value.value) is bool else "literal","value":value.value}
|
|
338
|
+
if node.kind=="pattern_or": return {"kind":"or","items":[self.pattern_spec(item) for item in node.children]}
|
|
339
|
+
if node.kind=="pattern_as": return {"kind":"as","name":self.mangle(node.value),"scope":self.name_scope(node.value),"pattern":self.pattern_spec(node.children[0])}
|
|
340
|
+
if node.kind=="pattern_value": return {"kind":"value","path":self.mangle_path(node.value)}
|
|
341
|
+
if node.kind=="pattern_sequence": return {"kind":"sequence","items":[self.pattern_spec(item) for item in node.children]}
|
|
342
|
+
if node.kind=="pattern_star": return {"kind":"star","name":self.mangle(node.value),"scope":self.name_scope(node.value)}
|
|
343
|
+
if node.kind=="pattern_mapping":
|
|
344
|
+
pairs=[]
|
|
345
|
+
for pair in node.children:
|
|
346
|
+
key=pair.children[0]
|
|
347
|
+
literal=None; is_literal=False
|
|
348
|
+
if key.kind=="constant": literal=key.value; is_literal=True
|
|
349
|
+
elif key.kind=="unary" and key.value in ("+","-") and key.children[0].kind=="constant" and isinstance(key.children[0].value,(int,float,complex)):
|
|
350
|
+
literal=key.children[0].value if key.value=="+" else -key.children[0].value; is_literal=True
|
|
351
|
+
elif key.kind=="binary" and key.value in ("+","-") and all(child.kind=="constant" for child in key.children):
|
|
352
|
+
left,right=(child.value for child in key.children)
|
|
353
|
+
if isinstance(left,(int,float)) and isinstance(right,complex) and right.real==0:
|
|
354
|
+
literal=left+right if key.value=="+" else left-right; is_literal=True
|
|
355
|
+
if is_literal: key_spec={"kind":"literal","value":literal}
|
|
356
|
+
else:
|
|
357
|
+
parts=[]; current=key
|
|
358
|
+
while current.kind=="attribute": parts.append(current.value); current=current.children[0]
|
|
359
|
+
if current.kind!="name" or not parts: self.unsupported(key)
|
|
360
|
+
key_spec={"kind":"value","path":self.mangle_path(".".join([current.value,*reversed(parts)]))}
|
|
361
|
+
pairs.append({"key":key_spec,"pattern":self.pattern_spec(pair.children[1])})
|
|
362
|
+
literal_keys=[item["key"]["value"] for item in pairs if item["key"]["kind"]=="literal"]
|
|
363
|
+
if len(literal_keys)!=len(set(literal_keys)): raise CompileError(f"매핑 패턴 키 중복 (줄 {node.line})")
|
|
364
|
+
return {"kind":"mapping","pairs":pairs,"rest":self.mangle(node.value) if node.value else node.value,"rest_scope":self.name_scope(node.value) if node.value else "local"}
|
|
365
|
+
if node.kind=="pattern_class":
|
|
366
|
+
positional=[]; keywords=[]
|
|
367
|
+
for item in node.children:
|
|
368
|
+
if item.kind=="pattern_keyword": keywords.append({"name":item.value,"pattern":self.pattern_spec(item.children[0])})
|
|
369
|
+
else: positional.append(self.pattern_spec(item))
|
|
370
|
+
return {"kind":"class","name":self.mangle_path(node.value),"positional":positional,"keywords":keywords}
|
|
371
|
+
self.unsupported(node)
|
|
372
|
+
|
|
373
|
+
def validate_pattern(self,node:Node) -> set[str]:
|
|
374
|
+
if node.kind in ("pattern_wildcard","pattern_literal","pattern_value"): return set()
|
|
375
|
+
if node.kind in ("pattern_capture","pattern_star"):
|
|
376
|
+
return set() if node.value=="_" else {node.value}
|
|
377
|
+
if node.kind=="pattern_as":
|
|
378
|
+
if node.value=="_": raise CompileError(f"AS 패턴의 대상은 _일 수 없습니다 (줄 {node.line})")
|
|
379
|
+
names=self.validate_pattern(node.children[0])
|
|
380
|
+
if node.value!="_":
|
|
381
|
+
if node.value in names: raise CompileError(f"패턴 이름 중복: {node.value} (줄 {node.line})")
|
|
382
|
+
names.add(node.value)
|
|
383
|
+
return names
|
|
384
|
+
if node.kind=="pattern_or":
|
|
385
|
+
alternatives=[self.validate_pattern(item) for item in node.children]
|
|
386
|
+
if any(names!=alternatives[0] for names in alternatives[1:]): raise CompileError(f"OR 패턴의 이름 바인딩이 일치하지 않습니다 (줄 {node.line})")
|
|
387
|
+
if any(self.irrefutable_pattern(item) for item in node.children[:-1]): raise CompileError(f"OR 패턴의 모든 값을 잡는 대안은 마지막이어야 합니다 (줄 {node.line})")
|
|
388
|
+
return alternatives[0]
|
|
389
|
+
names=set()
|
|
390
|
+
children=node.children
|
|
391
|
+
if node.kind=="pattern_sequence" and sum(child.kind=="pattern_star" for child in children)>1: raise CompileError(f"시퀀스 패턴에는 별표가 하나만 허용됩니다 (줄 {node.line})")
|
|
392
|
+
if node.kind=="pattern_mapping":
|
|
393
|
+
keys=[pair.children[0].value for pair in children if pair.children[0].kind=="constant"]
|
|
394
|
+
if len(keys)!=len(set(keys)): raise CompileError(f"매핑 패턴 키 중복 (줄 {node.line})")
|
|
395
|
+
if node.kind=="pattern_class":
|
|
396
|
+
keywords=[child.value for child in children if child.kind=="pattern_keyword"]
|
|
397
|
+
if len(keywords)!=len(set(keywords)): raise CompileError(f"클래스 패턴 키워드 중복 (줄 {node.line})")
|
|
398
|
+
if node.kind=="pattern_mapping" and node.value:
|
|
399
|
+
if node.value!="_": names.add(node.value)
|
|
400
|
+
for child in children:
|
|
401
|
+
if child.kind=="pattern_pair": child=child.children[1]
|
|
402
|
+
elif child.kind=="pattern_keyword": child=child.children[0]
|
|
403
|
+
child_names=self.validate_pattern(child)
|
|
404
|
+
duplicate=names & child_names
|
|
405
|
+
if duplicate: raise CompileError(f"패턴 이름 중복: {next(iter(duplicate))} (줄 {node.line})")
|
|
406
|
+
names.update(child_names)
|
|
407
|
+
return names
|
|
408
|
+
|
|
409
|
+
@staticmethod
|
|
410
|
+
def irrefutable_pattern(node:Node) -> bool:
|
|
411
|
+
if node.kind in ("pattern_wildcard","pattern_capture"): return True
|
|
412
|
+
if node.kind=="pattern_as": return Compiler.irrefutable_pattern(node.children[0])
|
|
413
|
+
if node.kind=="pattern_or": return any(Compiler.irrefutable_pattern(item) for item in node.children)
|
|
414
|
+
return False
|
|
415
|
+
|
|
416
|
+
def target_spec(self,node:Node):
|
|
417
|
+
if node.kind=="name": return {"kind":"name","name":self.mangle(node.value),"scope":self.name_scope(node.value)}
|
|
418
|
+
if node.kind=="starred": return {"kind":"starred","target":self.target_spec(node.children[0])}
|
|
419
|
+
if node.kind in ("tuple","list"): return {"kind":"sequence","items":[self.target_spec(item) for item in node.children]}
|
|
420
|
+
if node.kind=="attribute": return {"kind":"attribute","name":self.mangle(node.value),"object":self.expression_code(node.children[0],"target-object").to_dict()}
|
|
421
|
+
if node.kind=="subscript": return {"kind":"subscript","object":self.expression_code(node.children[0],"target-object").to_dict(),"index":self.expression_code(node.children[1],"target-index").to_dict()}
|
|
422
|
+
self.unsupported(node)
|
|
423
|
+
|
|
424
|
+
def type_parameter_payload(self,item):
|
|
425
|
+
if isinstance(item,(list,tuple)): kind,name=item; return {"kind":kind,"name":name,"bound":None,"default":None}
|
|
426
|
+
return {"kind":item["kind"],"name":item["name"],
|
|
427
|
+
"bound":self.expression_code(item["bound"],"type-bound").to_dict() if item["bound"] and item.get("bound_text") is None else None,
|
|
428
|
+
"default":self.expression_code(item["default"],"type-default").to_dict() if item["default"] and item.get("default_text") is None else None,
|
|
429
|
+
"bound_text":item.get("bound_text"),"default_text":item.get("default_text")}
|
|
430
|
+
|
|
431
|
+
def compile_body(self, body: list[Node]) -> HIRCode:
|
|
432
|
+
globals_,nonlocals=_scope_declarations(body)
|
|
433
|
+
self.global_names.update(globals_); self.nonlocal_names.update(nonlocals)
|
|
434
|
+
for node in body:
|
|
435
|
+
self.statement(node)
|
|
436
|
+
self.emit("CONST", self.constant(None))
|
|
437
|
+
self.emit("RETURN")
|
|
438
|
+
return self.code
|
|
439
|
+
|
|
440
|
+
def statement(self, node: Node) -> None:
|
|
441
|
+
self.current_line=node.line
|
|
442
|
+
if node.kind == "expr":
|
|
443
|
+
self.expression(node.children[0]); self.emit("POP")
|
|
444
|
+
elif node.kind in ("import","imports"):
|
|
445
|
+
imports=[node.value] if node.kind=="import" else node.value
|
|
446
|
+
for module,alias in imports:
|
|
447
|
+
self.emit("IMPORT",module)
|
|
448
|
+
if "." in module and alias==module.split(".")[0]:
|
|
449
|
+
self.emit("POP"); self.emit("IMPORT",module.split(".")[0])
|
|
450
|
+
self.store_name(alias)
|
|
451
|
+
elif node.kind == "fromimport":
|
|
452
|
+
module,names=node.value
|
|
453
|
+
for name,alias in names:
|
|
454
|
+
if name=="*": self.emit("IMPORT",module); self.emit("IMPORT_STAR")
|
|
455
|
+
else: self.emit("IMPORT_FROM",{"module":module,"name":name}); self.store_name(alias)
|
|
456
|
+
elif node.kind == "global": self.global_names.update(self.mangle(name) for name in node.value)
|
|
457
|
+
elif node.kind == "nonlocal": self.nonlocal_names.update(self.mangle(name) for name in node.value)
|
|
458
|
+
elif node.kind in ("del","dels"):
|
|
459
|
+
targets=node.children if node.kind=="dels" else [node.children[0]]
|
|
460
|
+
for target in targets: self.delete_target(target)
|
|
461
|
+
elif node.kind == "assert":
|
|
462
|
+
self.expression(node.children[0]); failure=self.emit("JUMP_FALSE",-1); end=self.emit("JUMP",-1)
|
|
463
|
+
self.patch(failure,len(self.code.instructions)); self.emit("CONST",self.constant(False)); self.expression(node.children[1]); self.emit("ASSERT")
|
|
464
|
+
self.patch(end,len(self.code.instructions))
|
|
465
|
+
elif node.kind == "type_alias":
|
|
466
|
+
name,parameters,*text=node.value
|
|
467
|
+
self.emit("MAKE_TYPE_ALIAS",{"name":name,"parameters":[self.type_parameter_payload(item) for item in parameters],"value":self.expression_code(node.children[0],"type-alias").to_dict(),"value_text":text[0] if text else None}); self.store_name(name)
|
|
468
|
+
elif node.kind == "assign":
|
|
469
|
+
target, value = node.children
|
|
470
|
+
self.expression(value); self.store_target(target)
|
|
471
|
+
elif node.kind == "assign_chain":
|
|
472
|
+
targets=node.children[:-1]; self.expression(node.children[-1])
|
|
473
|
+
for index,target in enumerate(targets):
|
|
474
|
+
if index<len(targets)-1: self.emit("DUP")
|
|
475
|
+
self.store_target(target)
|
|
476
|
+
elif node.kind == "annassign":
|
|
477
|
+
target,annotation=node.children[:2]
|
|
478
|
+
if len(node.children)>2:
|
|
479
|
+
value=node.children[2]
|
|
480
|
+
self.expression(value); self.store_target(target)
|
|
481
|
+
elif target.kind=="attribute":
|
|
482
|
+
self.expression(target.children[0]); self.emit("POP")
|
|
483
|
+
elif target.kind=="subscript":
|
|
484
|
+
self.expression(target.children[0]); self.emit("POP")
|
|
485
|
+
self.expression(target.children[1]); self.emit("POP")
|
|
486
|
+
if target.kind=="name" and self.evaluate_annotations:
|
|
487
|
+
annotation_name=self.mangle(target.value)
|
|
488
|
+
self.emit("ANNOTATE_LAZY",{"name":annotation_name,"text":node.value or "","code":self.expression_code(annotation,f"annotation-{annotation_name}").to_dict()})
|
|
489
|
+
elif node.kind == "augassign":
|
|
490
|
+
operator=node.value; target,value=node.children
|
|
491
|
+
opcode={"+":"IADD","-":"ISUB","*":"IMUL","/":"IDIV","//":"IFLOORDIV","%":"IMOD","**":"IPOW","|":"IBIT_OR","&":"IBIT_AND","^":"IBIT_XOR","<<":"ILSHIFT",">>":"IRSHIFT","@":"IMATMUL"}.get(operator)
|
|
492
|
+
if not opcode: self.unsupported(node)
|
|
493
|
+
if target.kind=="name":
|
|
494
|
+
name=self.mangle(target.value); self.emit("LOAD",name); self.expression(value); self.emit(opcode)
|
|
495
|
+
self.emit("STORE_GLOBAL" if name in self.global_names else "STORE_NONLOCAL" if name in self.nonlocal_names else "STORE",name)
|
|
496
|
+
elif target.kind=="attribute":
|
|
497
|
+
attribute=self.mangle(target.value); self.expression(target.children[0]); self.emit("DUP"); self.emit("GET_ATTR",attribute)
|
|
498
|
+
self.expression(value); self.emit(opcode); self.emit("SET_ATTR",attribute)
|
|
499
|
+
elif target.kind=="subscript":
|
|
500
|
+
self.expression(target.children[0]); self.emit("DUP"); self.expression(target.children[1]); self.emit("DUP2")
|
|
501
|
+
self.emit("GET_ITEM"); self.expression(value); self.emit(opcode); self.emit("SET_ITEM")
|
|
502
|
+
else: self.unsupported(target)
|
|
503
|
+
elif node.kind == "if":
|
|
504
|
+
self.expression(node.children[0]); false = self.emit("JUMP_FALSE", -1)
|
|
505
|
+
for item in node.children[1].children: self.statement(item)
|
|
506
|
+
end = self.emit("JUMP", -1); self.patch(false, len(self.code.instructions))
|
|
507
|
+
for item in node.children[2].children: self.statement(item)
|
|
508
|
+
self.patch(end, len(self.code.instructions))
|
|
509
|
+
elif node.kind == "while":
|
|
510
|
+
start = len(self.code.instructions); self.expression(node.children[0])
|
|
511
|
+
end = self.emit("JUMP_FALSE", -1)
|
|
512
|
+
breaks: list[int]=[]; self.loops.append((start,breaks,False))
|
|
513
|
+
for item in node.children[1].children: self.statement(item)
|
|
514
|
+
self.loops.pop()
|
|
515
|
+
self.emit("JUMP", start); self.patch(end, len(self.code.instructions))
|
|
516
|
+
for item in node.children[2].children: self.statement(item)
|
|
517
|
+
for jump in breaks:
|
|
518
|
+
if isinstance(jump,int): self.patch(jump,len(self.code.instructions))
|
|
519
|
+
else: jump["break_target"]=len(self.code.instructions)
|
|
520
|
+
elif node.kind == "for":
|
|
521
|
+
self.expression(node.children[0]); self.emit("ITER"); start = len(self.code.instructions)
|
|
522
|
+
end = self.emit("FOR_ITER", -1); self.store_target(node.value)
|
|
523
|
+
breaks=[]; self.loops.append((start,breaks,True))
|
|
524
|
+
for item in node.children[1].children: self.statement(item)
|
|
525
|
+
self.loops.pop()
|
|
526
|
+
self.emit("JUMP", start); self.patch(end, len(self.code.instructions))
|
|
527
|
+
for item in node.children[2].children: self.statement(item)
|
|
528
|
+
for jump in breaks:
|
|
529
|
+
if isinstance(jump,int): self.patch(jump,len(self.code.instructions))
|
|
530
|
+
else: jump["break_target"]=len(self.code.instructions)
|
|
531
|
+
elif node.kind == "def":
|
|
532
|
+
name, params, defaults, vararg, kwarg, kwonly, is_async, posonly, *extra = node.value
|
|
533
|
+
annotations=extra[0] if extra else {}; type_parameters=extra[1] if len(extra)>1 else []
|
|
534
|
+
all_parameters=[*params,*kwonly,*([vararg] if vararg else []),*([kwarg] if kwarg else [])]
|
|
535
|
+
child_compiler=Compiler(name,all_parameters,evaluate_annotations=False,private_class=self.private_class)
|
|
536
|
+
child = child_compiler.compile_body(node.children)
|
|
537
|
+
for parameter in [*params,*kwonly]:
|
|
538
|
+
if parameter in defaults: self.expression(defaults[parameter])
|
|
539
|
+
type_parameter_names=[item[1] if isinstance(item,(list,tuple)) else item["name"] for item in type_parameters]
|
|
540
|
+
for type_index,item in enumerate(type_parameters):
|
|
541
|
+
payload=self.type_parameter_payload(item); payload.update({"group_names":type_parameter_names,"group_index":type_index}); type_name=payload["name"]
|
|
542
|
+
self.emit("SAVE_NAME",type_name)
|
|
543
|
+
self.emit("MAKE_TYPE_PARAMETER",payload); self.emit("DUP"); self.emit("STORE",type_name)
|
|
544
|
+
annotation_names=list(annotations)
|
|
545
|
+
declared_globals,declared_nonlocals=_scope_declarations(node.children)
|
|
546
|
+
mangled_globals={self.mangle(item) for item in declared_globals}; mangled_nonlocals={self.mangle(item) for item in declared_nonlocals}
|
|
547
|
+
local_names=sorted({self.mangle(item) for item in (_scope_bindings(node.children)|set(all_parameters))}-mangled_globals-mangled_nonlocals)
|
|
548
|
+
mangled_params=[self.mangle(item) for item in params]; mangled_kwonly=[self.mangle(item) for item in kwonly]
|
|
549
|
+
mangled_vararg=self.mangle(vararg) if vararg else None; mangled_kwarg=self.mangle(kwarg) if kwarg else None
|
|
550
|
+
self.emit("MAKE_FUNCTION", {"code":child.to_dict(),"defaults":[self.mangle(p) for p in [*params,*kwonly] if p in defaults],
|
|
551
|
+
"name":name,"doc":self.docstring(node.children),
|
|
552
|
+
"annotations":[],"annotation_codes":{self.mangle(annotation_name) if annotation_name!="return" else annotation_name:self.expression_code(self.annotation_node(annotations[annotation_name]),f"annotation-{annotation_name}").to_dict() for annotation_name in annotation_names},"annotation_strings":{self.mangle(annotation_name) if annotation_name!="return" else annotation_name:self.annotation_text(annotations[annotation_name]) for annotation_name in annotation_names},
|
|
553
|
+
"type_params":type_parameter_names,
|
|
554
|
+
"local_names":local_names,
|
|
555
|
+
"free_names":sorted(mangled_nonlocals),
|
|
556
|
+
"signature":{"positional":mangled_params,"positional_only":[self.mangle(item) for item in posonly],"keyword_only":mangled_kwonly,"vararg":mangled_vararg,"kwarg":mangled_kwarg},
|
|
557
|
+
"generator":self.has_yield(node.children),"async":is_async})
|
|
558
|
+
if not self.defer_definition_store: self.store_name(name)
|
|
559
|
+
for item in reversed(type_parameters): self.emit("RESTORE_NAME",item[1] if isinstance(item,(list,tuple)) else item["name"])
|
|
560
|
+
elif node.kind == "class":
|
|
561
|
+
if len(node.value)==2: name,bases=node.value; type_parameters=[]
|
|
562
|
+
elif len(node.value)==3: name,bases,type_parameters=node.value; keywords=[]
|
|
563
|
+
elif len(node.value)==4: name,bases,type_parameters,keywords=node.value; arguments=[]
|
|
564
|
+
else: name,bases,type_parameters,keywords,arguments=node.value
|
|
565
|
+
type_parameter_names=[item[1] if isinstance(item,(list,tuple)) else item["name"] for item in type_parameters]
|
|
566
|
+
for type_index,item in enumerate(type_parameters):
|
|
567
|
+
payload=self.type_parameter_payload(item); payload.update({"group_names":type_parameter_names,"group_index":type_index}); type_name=payload["name"]
|
|
568
|
+
self.emit("SAVE_NAME",type_name)
|
|
569
|
+
self.emit("MAKE_TYPE_PARAMETER",payload); self.emit("DUP"); self.emit("STORE",type_name)
|
|
570
|
+
if arguments:
|
|
571
|
+
self.emit("CLASS_BEGIN")
|
|
572
|
+
for kind,key,value in arguments:
|
|
573
|
+
self.expression(value); self.emit("CLASS_ARG",[kind,key])
|
|
574
|
+
else:
|
|
575
|
+
for base in bases: self.expression(base.children[0] if base.kind=="starred" else base)
|
|
576
|
+
for _,value in keywords: self.expression(value)
|
|
577
|
+
child_compiler=Compiler(name,[],private_class=name); child=child_compiler.compile_body(node.children)
|
|
578
|
+
declared_globals,declared_nonlocals=_scope_declarations(node.children)
|
|
579
|
+
class_local_names=sorted({child_compiler.mangle(item) for item in _scope_bindings(node.children)}-{child_compiler.mangle(item) for item in declared_globals}-{child_compiler.mangle(item) for item in declared_nonlocals})
|
|
580
|
+
self.emit("MAKE_CLASS",{"code":child.to_dict(),"name":name,"doc":self.docstring(node.children),"firstlineno":self.definition_firstlineno if self.definition_firstlineno is not None else node.line,"bases":len(bases),"base_starred":[base.kind=="starred" for base in bases],"keywords":[item[0] for item in keywords],"class_arguments":[[kind,key] for kind,key,_ in arguments] if arguments else None,"incremental_arguments":bool(arguments),"type_params":type_parameter_names,"local_names":class_local_names,"free_names":sorted(declared_nonlocals),"static_attributes":self.static_attributes(node.children)})
|
|
581
|
+
if not self.defer_definition_store: self.store_name(name)
|
|
582
|
+
for item in reversed(type_parameters): self.emit("RESTORE_NAME",item[1] if isinstance(item,(list,tuple)) else item["name"])
|
|
583
|
+
elif node.kind == "decorated":
|
|
584
|
+
decorators=node.children[:-1]; target=node.children[-1]
|
|
585
|
+
for decorator in decorators: self.expression(decorator)
|
|
586
|
+
previous=self.defer_definition_store; previous_line=self.definition_firstlineno
|
|
587
|
+
self.defer_definition_store=True; self.definition_firstlineno=node.line
|
|
588
|
+
try: self.statement(target)
|
|
589
|
+
finally: self.defer_definition_store=previous; self.definition_firstlineno=previous_line
|
|
590
|
+
name=target.value[0]
|
|
591
|
+
for _ in reversed(decorators): self.emit("CALL",1)
|
|
592
|
+
self.store_name(name)
|
|
593
|
+
elif node.kind == "return":
|
|
594
|
+
self.expression(node.children[0]); self.emit("SIGNAL_RETURN" if self.signal_returns else "RETURN")
|
|
595
|
+
elif node.kind == "raise":
|
|
596
|
+
self.expression(node.children[0])
|
|
597
|
+
if len(node.children)>1: self.expression(node.children[1]); self.emit("RAISE_FROM")
|
|
598
|
+
else: self.emit("RAISE")
|
|
599
|
+
elif node.kind == "reraise": self.emit("RERAISE")
|
|
600
|
+
elif node.kind in ("yield","yield_from"):
|
|
601
|
+
self.expression(node.children[0]); self.emit("YIELD_FROM" if node.kind=="yield_from" else "YIELD"); self.emit("POP")
|
|
602
|
+
elif node.kind == "try":
|
|
603
|
+
body,handlers,otherwise,final=node.children
|
|
604
|
+
payload={
|
|
605
|
+
"body": self.scope_child(f"{self.code.name}:try",True).compile_body(body.children).to_dict(),
|
|
606
|
+
"handlers": [
|
|
607
|
+
{"type":self.expression_code(handler.value[0],"except-type").to_dict() if handler.value[0] else None,"alias":handler.value[1],"alias_scope":self.name_scope(handler.value[1]) if handler.value[1] else "local","star":handler.value[2] if len(handler.value)>2 else False,
|
|
608
|
+
"code":self.scope_child(f"{self.code.name}:except",True).compile_body(handler.children).to_dict()}
|
|
609
|
+
for handler in handlers.children
|
|
610
|
+
],
|
|
611
|
+
"else": self.scope_child(f"{self.code.name}:else",True).compile_body(otherwise.children).to_dict() if otherwise.children else None,
|
|
612
|
+
"finally": self.scope_child(f"{self.code.name}:finally",True).compile_body(final.children).to_dict() if final.children else None,
|
|
613
|
+
"break_target":None,"continue_target":self.loops[-1][0] if self.loops else None,
|
|
614
|
+
}
|
|
615
|
+
self.emit("TRY",payload)
|
|
616
|
+
if self.loops: self.loops[-1][1].append(payload)
|
|
617
|
+
elif node.kind == "with":
|
|
618
|
+
managers,body=node.children
|
|
619
|
+
payload={"managers":[{"alias":self.target_spec(item.children[1]) if len(item.children)>1 else None,"code":self.expression_code(item.children[0],"with-manager").to_dict()} for item in managers.children],
|
|
620
|
+
"body":self.scope_child(f"{self.code.name}:with",True).compile_body(body.children).to_dict(),
|
|
621
|
+
"break_target":None,"continue_target":self.loops[-1][0] if self.loops else None}
|
|
622
|
+
self.emit("WITH",payload)
|
|
623
|
+
if self.loops: self.loops[-1][1].append(payload)
|
|
624
|
+
elif node.kind == "async_for":
|
|
625
|
+
payload={"target":self.target_spec(node.value),"iter":self.expression_code(node.children[0],"async-iter").to_dict(),
|
|
626
|
+
"body":self.scope_child(f"{self.code.name}:async-for",True).compile_body(node.children[1].children).to_dict(),
|
|
627
|
+
"else":self.scope_child(f"{self.code.name}:async-for-else",True).compile_body(node.children[2].children).to_dict() if len(node.children)>2 and node.children[2].children else None}
|
|
628
|
+
self.emit("ASYNC_FOR",payload)
|
|
629
|
+
elif node.kind == "async_with":
|
|
630
|
+
managers,body=node.children
|
|
631
|
+
payload={"managers":[{"alias":self.target_spec(item.children[1]) if len(item.children)>1 else None,"code":self.expression_code(item.children[0],"async-manager").to_dict()} for item in managers.children],
|
|
632
|
+
"body":self.scope_child(f"{self.code.name}:async-with",True).compile_body(body.children).to_dict(),
|
|
633
|
+
"break_target":None,"continue_target":self.loops[-1][0] if self.loops else None}
|
|
634
|
+
self.emit("ASYNC_WITH",payload)
|
|
635
|
+
if self.loops: self.loops[-1][1].append(payload)
|
|
636
|
+
elif node.kind == "match":
|
|
637
|
+
temp=f"$매치{self.temp_counter}"; self.temp_counter+=1
|
|
638
|
+
self.expression(node.children[0]); self.emit("STORE",temp); end_jumps=[]
|
|
639
|
+
for case in node.children[1:-1]:
|
|
640
|
+
if case.value is None and self.irrefutable_pattern(case.children[0]): raise CompileError(f"모든 값을 잡는 케이스는 마지막이어야 합니다 (줄 {case.line})")
|
|
641
|
+
for case in node.children[1:]:
|
|
642
|
+
pattern=case.children[0]; self.validate_pattern(pattern); failure=None
|
|
643
|
+
self.emit("LOAD",temp); self.emit("MATCH_PATTERN",self.pattern_spec(pattern)); failure=self.emit("JUMP_FALSE",-1)
|
|
644
|
+
if case.value is not None:
|
|
645
|
+
self.expression(case.value); guard_failure=self.emit("JUMP_FALSE",-1)
|
|
646
|
+
else: guard_failure=None
|
|
647
|
+
for item in case.children[1].children: self.statement(item)
|
|
648
|
+
end_jumps.append(self.emit("JUMP",-1)); next_case=len(self.code.instructions)
|
|
649
|
+
if failure is not None: self.patch(failure,next_case)
|
|
650
|
+
if guard_failure is not None: self.patch(guard_failure,next_case)
|
|
651
|
+
end=len(self.code.instructions)
|
|
652
|
+
for jump in end_jumps: self.patch(jump,end)
|
|
653
|
+
self.emit("DELETE",temp)
|
|
654
|
+
elif node.kind == "pass":
|
|
655
|
+
self.emit("NOP")
|
|
656
|
+
elif node.kind == "break":
|
|
657
|
+
if not self.loops:
|
|
658
|
+
if self.signal_returns: self.emit("SIGNAL_BREAK"); return
|
|
659
|
+
raise CompileError(f"루프 밖의 브레이크 (줄 {node.line})")
|
|
660
|
+
if self.loops[-1][2]: self.emit("POP")
|
|
661
|
+
self.loops[-1][1].append(self.emit("JUMP",-1))
|
|
662
|
+
elif node.kind == "continue":
|
|
663
|
+
if not self.loops:
|
|
664
|
+
if self.signal_returns: self.emit("SIGNAL_CONTINUE"); return
|
|
665
|
+
raise CompileError(f"루프 밖의 컨티뉴 (줄 {node.line})")
|
|
666
|
+
self.emit("JUMP",self.loops[-1][0])
|
|
667
|
+
else: self.unsupported(node)
|
|
668
|
+
|
|
669
|
+
def store_target(self,target:Node):
|
|
670
|
+
if target.kind=="name":
|
|
671
|
+
name=self.mangle(target.value); self.emit("STORE_GLOBAL" if name in self.global_names else "STORE_NONLOCAL" if name in self.nonlocal_names else "STORE",name)
|
|
672
|
+
elif target.kind in ("tuple","list"):
|
|
673
|
+
stars=[index for index,item in enumerate(target.children) if item.kind=="starred"]
|
|
674
|
+
if len(stars)>1: raise CompileError(f"구조 분해 별표 대상은 하나만 허용됩니다 (줄 {target.line})")
|
|
675
|
+
if stars:
|
|
676
|
+
before=stars[0]; after=len(target.children)-before-1
|
|
677
|
+
self.emit("UNPACK_EX",(before<<16)|after)
|
|
678
|
+
else: self.emit("UNPACK",len(target.children))
|
|
679
|
+
for item in target.children: self.store_target(item.children[0] if item.kind=="starred" else item)
|
|
680
|
+
elif target.kind=="attribute":
|
|
681
|
+
temp=f"$대입{self.temp_counter}"; self.temp_counter+=1
|
|
682
|
+
self.emit("STORE",temp); self.expression(target.children[0]); self.emit("LOAD",temp); self.emit("SET_ATTR",self.mangle(target.value)); self.emit("DELETE",temp)
|
|
683
|
+
elif target.kind=="subscript":
|
|
684
|
+
temp=f"$대입{self.temp_counter}"; self.temp_counter+=1
|
|
685
|
+
self.emit("STORE",temp); self.expression(target.children[0]); self.expression(target.children[1]); self.emit("LOAD",temp); self.emit("SET_ITEM"); self.emit("DELETE",temp)
|
|
686
|
+
else: self.unsupported(target)
|
|
687
|
+
|
|
688
|
+
def expression(self, node: Node) -> None:
|
|
689
|
+
self.current_line=node.line
|
|
690
|
+
if node.kind == "constant": self.emit("CONST", self.constant(node.value))
|
|
691
|
+
elif node.kind == "name": self.emit("LOAD", self.mangle(node.value))
|
|
692
|
+
elif node.kind == "binary":
|
|
693
|
+
if node.value in ("and","or"):
|
|
694
|
+
self.expression(node.children[0])
|
|
695
|
+
jump=self.emit("JUMP_IF_FALSE_OR_POP" if node.value=="and" else "JUMP_IF_TRUE_OR_POP",-1)
|
|
696
|
+
self.expression(node.children[1]); self.patch(jump,len(self.code.instructions)); return
|
|
697
|
+
self.expression(node.children[0]); self.expression(node.children[1])
|
|
698
|
+
ops = {"+":"ADD","-":"SUB","*":"MUL","/":"DIV","//":"FLOORDIV","%":"MOD","**":"POW",
|
|
699
|
+
"==":"EQ","!=":"NE","<":"LT","<=":"LE",">":"GT",">=":"GE","in":"IN","is":"IS","not in":"NOT_IN","is not":"IS_NOT"}
|
|
700
|
+
ops.update({"|":"BIT_OR","^":"BIT_XOR","&":"BIT_AND","<<":"LSHIFT",">>":"RSHIFT","@":"MATMUL"})
|
|
701
|
+
op=ops.get(node.value); self.emit(op) if op else self.unsupported(node)
|
|
702
|
+
elif node.kind == "compare_chain":
|
|
703
|
+
self.emit("CHAIN_COMPARE",{"operators":node.value,"operands":[self.expression_code(item,"compare-operand").to_dict() for item in node.children]})
|
|
704
|
+
elif node.kind == "unary":
|
|
705
|
+
self.expression(node.children[0]); op={"-":"NEG","+":"POS","not":"NOT","~":"INVERT"}.get(node.value)
|
|
706
|
+
self.emit(op) if op else self.unsupported(node)
|
|
707
|
+
elif node.kind == "call":
|
|
708
|
+
if node.children[0].kind=="name" and node.children[0].value=="super" and len(node.children)==1:
|
|
709
|
+
self.emit("SUPER",self.code.parameters[0] if self.code.parameters else ""); return
|
|
710
|
+
self.expression(node.children[0])
|
|
711
|
+
descriptors=node.value or [["positional",None] for _ in node.children[1:]]
|
|
712
|
+
if any(item[0] in ("star","kwstar") for item in descriptors):
|
|
713
|
+
self.emit("CALL_BEGIN")
|
|
714
|
+
for argument,descriptor in zip(node.children[1:],descriptors):
|
|
715
|
+
self.expression(argument); self.emit("CALL_ARG",descriptor)
|
|
716
|
+
self.emit("CALL_READY")
|
|
717
|
+
else:
|
|
718
|
+
for argument in node.children[1:]: self.expression(argument)
|
|
719
|
+
if all(item[0]=="positional" for item in descriptors): self.emit("CALL",len(descriptors))
|
|
720
|
+
else: self.emit("CALL_EX",descriptors)
|
|
721
|
+
elif node.kind == "list":
|
|
722
|
+
if any(item.kind=="starred" for item in node.children):
|
|
723
|
+
self.emit("COLLECTION_BEGIN","list")
|
|
724
|
+
for item in node.children:
|
|
725
|
+
self.expression(item.children[0] if item.kind=="starred" else item); self.emit("COLLECTION_ADD","star" if item.kind=="starred" else "item")
|
|
726
|
+
self.emit("COLLECTION_READY")
|
|
727
|
+
else:
|
|
728
|
+
for item in node.children: self.expression(item)
|
|
729
|
+
self.emit("BUILD_LIST", len(node.children))
|
|
730
|
+
elif node.kind == "tuple":
|
|
731
|
+
if any(item.kind=="starred" for item in node.children):
|
|
732
|
+
self.emit("COLLECTION_BEGIN","tuple")
|
|
733
|
+
for item in node.children:
|
|
734
|
+
self.expression(item.children[0] if item.kind=="starred" else item); self.emit("COLLECTION_ADD","star" if item.kind=="starred" else "item")
|
|
735
|
+
self.emit("COLLECTION_READY")
|
|
736
|
+
else:
|
|
737
|
+
for item in node.children: self.expression(item)
|
|
738
|
+
self.emit("BUILD_TUPLE",len(node.children))
|
|
739
|
+
elif node.kind == "set":
|
|
740
|
+
self.emit("COLLECTION_BEGIN","set")
|
|
741
|
+
for item in node.children:
|
|
742
|
+
self.expression(item.children[0] if item.kind=="starred" else item); self.emit("COLLECTION_ADD","star" if item.kind=="starred" else "item")
|
|
743
|
+
self.emit("COLLECTION_READY")
|
|
744
|
+
elif node.kind == "dict":
|
|
745
|
+
self.emit("COLLECTION_BEGIN","dict")
|
|
746
|
+
for pair in node.children:
|
|
747
|
+
if pair.kind=="dict_unpack": self.expression(pair.children[0]); self.emit("COLLECTION_ADD","unpack")
|
|
748
|
+
else: self.expression(pair.children[0]); self.expression(pair.children[1]); self.emit("COLLECTION_ADD","pair")
|
|
749
|
+
self.emit("COLLECTION_READY")
|
|
750
|
+
elif node.kind == "subscript":
|
|
751
|
+
self.expression(node.children[0]); self.expression(node.children[1]); self.emit("GET_ITEM")
|
|
752
|
+
elif node.kind == "slice":
|
|
753
|
+
for item in node.children: self.expression(item)
|
|
754
|
+
self.emit("BUILD_SLICE")
|
|
755
|
+
elif node.kind == "attribute":
|
|
756
|
+
self.expression(node.children[0]); self.emit("GET_ATTR", self.mangle(node.value))
|
|
757
|
+
elif node.kind == "format":
|
|
758
|
+
self.expression(node.children[0])
|
|
759
|
+
if len(node.children)>1: self.expression(node.children[1])
|
|
760
|
+
self.emit("FORMAT_VALUE",{"conversion":node.value,"has_spec":len(node.children)>1})
|
|
761
|
+
elif node.kind == "fstring":
|
|
762
|
+
for item in node.children: self.expression(item)
|
|
763
|
+
self.emit("BUILD_STRING",len(node.children))
|
|
764
|
+
elif node.kind == "interpolation":
|
|
765
|
+
self.expression(node.children[0]); self.emit("CONST",self.constant(node.value["expression"])); self.emit("CONST",self.constant(node.value["conversion"]))
|
|
766
|
+
if len(node.children)>1: self.expression(node.children[1])
|
|
767
|
+
else: self.emit("CONST",self.constant(""))
|
|
768
|
+
self.emit("MAKE_INTERPOLATION")
|
|
769
|
+
elif node.kind == "template":
|
|
770
|
+
for item in node.children: self.expression(item)
|
|
771
|
+
self.emit("BUILD_TEMPLATE",len(node.children))
|
|
772
|
+
elif node.kind in ("listcomp","setcomp","dictcomp","generatorexpr"):
|
|
773
|
+
element=node.children[0]
|
|
774
|
+
payload={"kind":node.kind,"clauses":[
|
|
775
|
+
{"target":self.target_spec(clause.value[0] if isinstance(clause.value,tuple) else clause.value),"async":clause.value[1] if isinstance(clause.value,tuple) else False,"iter":self.expression_code(clause.children[0],"comp-iter").to_dict(),
|
|
776
|
+
"filters":[self.expression_code(item,"comp-filter").to_dict() for item in clause.children[1:]]}
|
|
777
|
+
for clause in node.children[1:]]}
|
|
778
|
+
payload["async"]=any(clause["async"] for clause in payload["clauses"]) or self.has_await(node.children)
|
|
779
|
+
payload["bindings"]=sorted(set().union(*(self.named_expression_targets(item) for item in node.children)))
|
|
780
|
+
if node.kind=="dictcomp":
|
|
781
|
+
payload["key"]=self.expression_code(element.children[0],"comp-key").to_dict()
|
|
782
|
+
payload["value"]=self.expression_code(element.children[1],"comp-value").to_dict()
|
|
783
|
+
else: payload["element"]=self.expression_code(element,"comp-element").to_dict()
|
|
784
|
+
self.emit("COMPREHENSION",payload)
|
|
785
|
+
elif node.kind=="lambda":
|
|
786
|
+
signature=node.value if isinstance(node.value,dict) else {"params":node.value,"posonly":[],"kwonly":[],"defaults":{},"vararg":None,"kwarg":None}
|
|
787
|
+
all_parameters=[*signature["params"],*signature["kwonly"],*([signature["vararg"]] if signature["vararg"] else []),*([signature["kwarg"]] if signature["kwarg"] else [])]
|
|
788
|
+
child=Compiler("<lambda>",all_parameters,evaluate_annotations=False,private_class=self.private_class)
|
|
789
|
+
child.expression(node.children[0]); child.emit("RETURN")
|
|
790
|
+
default_names=[name for name in [*signature["params"],*signature["kwonly"]] if name in signature["defaults"]]
|
|
791
|
+
for name in default_names: self.expression(signature["defaults"][name])
|
|
792
|
+
self.emit("MAKE_FUNCTION",{"code":child.code.to_dict(),"defaults":[self.mangle(item) for item in default_names],
|
|
793
|
+
"name":"<lambda>","doc":None,
|
|
794
|
+
"annotations":[],
|
|
795
|
+
"local_names":sorted(self.mangle(item) for item in (set(all_parameters)|self.named_expression_targets(node.children[0]))),
|
|
796
|
+
"free_names":[],
|
|
797
|
+
"type_params":[],
|
|
798
|
+
"signature":{"positional":[self.mangle(item) for item in signature["params"]],"positional_only":[self.mangle(item) for item in signature["posonly"]],"keyword_only":[self.mangle(item) for item in signature["kwonly"]],"vararg":self.mangle(signature["vararg"]) if signature["vararg"] else None,"kwarg":self.mangle(signature["kwarg"]) if signature["kwarg"] else None},"generator":self.has_yield(node.children),"async":False})
|
|
799
|
+
elif node.kind=="await":
|
|
800
|
+
self.expression(node.children[0]); self.emit("AWAIT")
|
|
801
|
+
elif node.kind in ("yield_expr","yield_from_expr"):
|
|
802
|
+
self.expression(node.children[0]); self.emit("YIELD_FROM" if node.kind=="yield_from_expr" else "YIELD")
|
|
803
|
+
elif node.kind=="namedexpr":
|
|
804
|
+
self.expression(node.children[0]); self.emit("DUP"); self.store_name(node.value)
|
|
805
|
+
elif node.kind=="conditional":
|
|
806
|
+
self.expression(node.children[0]); false=self.emit("JUMP_FALSE",-1)
|
|
807
|
+
self.expression(node.children[1]); end=self.emit("JUMP",-1); self.patch(false,len(self.code.instructions))
|
|
808
|
+
self.expression(node.children[2]); self.patch(end,len(self.code.instructions))
|
|
809
|
+
else: self.unsupported(node)
|
|
810
|
+
|
|
811
|
+
def unsupported(self, node) -> None:
|
|
812
|
+
raise CompileError(f"아직 지원하지 않는 구문: {node.kind} (줄 {node.line})")
|
|
813
|
+
|
|
814
|
+
def compile_hir(source: str, filename: str = "<하이썬>", *, optimize: bool = True) -> HIRCode:
|
|
815
|
+
try:
|
|
816
|
+
tree = parse(source,filename)
|
|
817
|
+
except SyntaxError as exc:
|
|
818
|
+
if exc.filename is None: exc.filename=filename
|
|
819
|
+
raise
|
|
820
|
+
_validate_declarations(tree.children)
|
|
821
|
+
_validate_future_imports(tree.children)
|
|
822
|
+
_validate_context(tree.children)
|
|
823
|
+
hir = Compiler(filename).compile_body(tree.children)
|
|
824
|
+
return optimize_hir(hir) if optimize else hir
|
|
825
|
+
|
|
826
|
+
def _lower(hir: HIRCode) -> CodeObject:
|
|
827
|
+
instructions: list[list] = []
|
|
828
|
+
for instruction in hir.instructions:
|
|
829
|
+
lowered = list(instruction)
|
|
830
|
+
if lowered[0] in ("MAKE_FUNCTION","MAKE_CLASS"):
|
|
831
|
+
nested = lowered[1]["code"]
|
|
832
|
+
result=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
833
|
+
lowered[1]["code"]=result
|
|
834
|
+
elif lowered[0]=="TRY":
|
|
835
|
+
payload=lowered[1]
|
|
836
|
+
for key in ("body","else","finally"):
|
|
837
|
+
nested=payload.get(key)
|
|
838
|
+
if nested: payload[key]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
839
|
+
for handler in payload["handlers"]:
|
|
840
|
+
nested=handler["code"]
|
|
841
|
+
handler["code"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
842
|
+
elif lowered[0]=="COMPREHENSION":
|
|
843
|
+
payload=lowered[1]
|
|
844
|
+
for key in ("element","key","value"):
|
|
845
|
+
nested=payload.get(key)
|
|
846
|
+
if nested: payload[key]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
847
|
+
for clause in payload["clauses"]:
|
|
848
|
+
nested=clause["iter"]
|
|
849
|
+
clause["iter"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
850
|
+
clause["filters"]=[_lower(HIRCode.from_dict(n)).to_dict() for n in clause["filters"]]
|
|
851
|
+
elif lowered[0]=="WITH":
|
|
852
|
+
payload=lowered[1]; nested=payload["body"]
|
|
853
|
+
payload["body"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
854
|
+
for manager in payload["managers"]:
|
|
855
|
+
nested=manager["code"]
|
|
856
|
+
manager["code"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
857
|
+
elif lowered[0] in ("ASYNC_FOR","ASYNC_WITH"):
|
|
858
|
+
payload=lowered[1]
|
|
859
|
+
for key in ("iter","body","else"):
|
|
860
|
+
nested=payload.get(key)
|
|
861
|
+
if nested: payload[key]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
862
|
+
for manager in payload.get("managers",[]):
|
|
863
|
+
nested=manager["code"]; manager["code"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
864
|
+
elif lowered[0]=="ANNOTATE_LAZY":
|
|
865
|
+
nested=lowered[1]["code"]; lowered[1]["code"]=_lower(HIRCode.from_dict(nested)).to_dict()
|
|
866
|
+
instructions.append(lowered)
|
|
867
|
+
return CodeObject(hir.name, hir.parameters, hir.constants, instructions,list(hir.lines))
|
|
868
|
+
|
|
869
|
+
def compile_source(source: str, filename: str = "<하이썬>", *, optimize: bool = True) -> CodeObject:
|
|
870
|
+
return _lower(compile_hir(source, filename, optimize=optimize))
|