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/vm.py
ADDED
|
@@ -0,0 +1,2409 @@
|
|
|
1
|
+
"""Small stack VM for HBC v1."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import operator
|
|
4
|
+
import asyncio
|
|
5
|
+
import types
|
|
6
|
+
import builtins
|
|
7
|
+
import inspect
|
|
8
|
+
import annotationlib
|
|
9
|
+
import importlib
|
|
10
|
+
import sys
|
|
11
|
+
from string.templatelib import Template,Interpolation
|
|
12
|
+
from collections.abc import Mapping,Sequence
|
|
13
|
+
from typing import TypeAliasType,TypeVar,TypeVarTuple,ParamSpec
|
|
14
|
+
from dataclasses import dataclass,field
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from types import SimpleNamespace
|
|
17
|
+
from .bytecode import CodeObject
|
|
18
|
+
from .bytecode import read as read_hbc
|
|
19
|
+
|
|
20
|
+
class VMError(RuntimeError): pass
|
|
21
|
+
class _GeneratorReturn(Exception):
|
|
22
|
+
def __init__(self,value=None): self.value=value
|
|
23
|
+
class _AsyncGeneratorReturn(Exception): pass
|
|
24
|
+
_MISSING=object()
|
|
25
|
+
_MATCH_SELF_TYPES=(bool,bytearray,bytes,dict,float,frozenset,int,list,set,str,tuple)
|
|
26
|
+
def _exception_leaf_ids(error):
|
|
27
|
+
if isinstance(error,BaseExceptionGroup):
|
|
28
|
+
result=set()
|
|
29
|
+
for child in error.exceptions: result.update(_exception_leaf_ids(child))
|
|
30
|
+
return result
|
|
31
|
+
return {id(error)}
|
|
32
|
+
def _merge_except_star(original,reraised,raised,remaining):
|
|
33
|
+
leaf_ids=set()
|
|
34
|
+
for subgroup in reraised: leaf_ids.update(_exception_leaf_ids(subgroup))
|
|
35
|
+
if remaining is not None: leaf_ids.update(_exception_leaf_ids(remaining))
|
|
36
|
+
if leaf_ids==_exception_leaf_ids(original): propagated=original
|
|
37
|
+
else: propagated=original.subgroup(lambda error: not isinstance(error,BaseExceptionGroup) and id(error) in leaf_ids) if leaf_ids else None
|
|
38
|
+
if not raised: return propagated
|
|
39
|
+
if propagated is not None: raised.append(propagated)
|
|
40
|
+
return raised[0] if len(raised)==1 else BaseExceptionGroup("",raised)
|
|
41
|
+
def _thrown_exception(exception,args):
|
|
42
|
+
if isinstance(exception,type):
|
|
43
|
+
if not issubclass(exception,BaseException): raise TypeError("예외 형식이 필요합니다.")
|
|
44
|
+
if len(args)>2: raise TypeError("throw() 인자가 너무 많습니다.")
|
|
45
|
+
value=args[0] if args else None
|
|
46
|
+
error=value if isinstance(value,exception) else exception() if value is None else exception(value)
|
|
47
|
+
if len(args)==2:
|
|
48
|
+
traceback=args[1]
|
|
49
|
+
if traceback is not None and not isinstance(traceback,types.TracebackType): raise TypeError("traceback 객체가 필요합니다.")
|
|
50
|
+
error=error.with_traceback(traceback)
|
|
51
|
+
return error
|
|
52
|
+
if not isinstance(exception,BaseException): raise TypeError("예외 인스턴스가 필요합니다.")
|
|
53
|
+
if args: raise TypeError("예외 인스턴스 뒤에는 별도 값을 전달할 수 없습니다.")
|
|
54
|
+
return exception
|
|
55
|
+
class HythonModule(types.ModuleType):
|
|
56
|
+
"""Module object whose globals remain visible during circular imports."""
|
|
57
|
+
def __init__(self,__name__,**attributes):
|
|
58
|
+
super().__init__(__name__,attributes.pop("__doc__",None)); vars(self).update(attributes)
|
|
59
|
+
def __getattribute__(self,name):
|
|
60
|
+
if name=="__annotations__":
|
|
61
|
+
namespace=types.ModuleType.__getattribute__(self,"__dict__")
|
|
62
|
+
annotations=namespace.get(name)
|
|
63
|
+
if isinstance(annotations,LazyAnnotations): return annotations.evaluate()
|
|
64
|
+
return types.ModuleType.__getattribute__(self,name)
|
|
65
|
+
def __getattr__(self,name):
|
|
66
|
+
scope=vars(self).get("_hython_scope",{})
|
|
67
|
+
if name in scope: return scope[name]
|
|
68
|
+
raise AttributeError(name)
|
|
69
|
+
class ComprehensionScope(dict):
|
|
70
|
+
"""Isolate iteration targets while publishing assignment expressions immediately."""
|
|
71
|
+
def __init__(self,outer,bindings):
|
|
72
|
+
super().__init__(); self.outer=outer; self.bindings=set(bindings)
|
|
73
|
+
def __contains__(self,name): return dict.__contains__(self,name) or name in self.outer
|
|
74
|
+
def __getitem__(self,name):
|
|
75
|
+
if dict.__contains__(self,name): return dict.__getitem__(self,name)
|
|
76
|
+
return self.outer[name]
|
|
77
|
+
def get(self,name,default=None):
|
|
78
|
+
try: return self[name]
|
|
79
|
+
except KeyError: return default
|
|
80
|
+
def __setitem__(self,name,value):
|
|
81
|
+
dict.__setitem__(self,name,value)
|
|
82
|
+
if name in self.bindings: self.outer[name]=value
|
|
83
|
+
class TypeExpressionNamespace(dict):
|
|
84
|
+
"""Globals dictionary that resolves type-expression names against a live HBC scope."""
|
|
85
|
+
def __init__(self,scope,initial=None,globals_=None): super().__init__(initial or {}); self.scope=scope; self.globals=globals_ or {}
|
|
86
|
+
def __missing__(self,name):
|
|
87
|
+
current=self.scope; seen=set()
|
|
88
|
+
while isinstance(current,dict) and id(current) not in seen:
|
|
89
|
+
seen.add(id(current))
|
|
90
|
+
if name in current: return current[name]
|
|
91
|
+
if name in current.get("$local_names",()): raise KeyError(name)
|
|
92
|
+
current=current.get("$closure")
|
|
93
|
+
if name in self.globals: return self.globals[name]
|
|
94
|
+
raise KeyError(name)
|
|
95
|
+
def __contains__(self,name):
|
|
96
|
+
if dict.__contains__(self,name): return True
|
|
97
|
+
try: self.__missing__(name); return True
|
|
98
|
+
except KeyError: return False
|
|
99
|
+
def get(self,name,default=None):
|
|
100
|
+
try: return self[name]
|
|
101
|
+
except KeyError: return default
|
|
102
|
+
class ClassAnnotationScope(dict):
|
|
103
|
+
"""Live class namespace view retaining the lexical outer scope for lazy annotations."""
|
|
104
|
+
def __init__(self,owner,outer,type_parameters=None): super().__init__({"$closure":outer,**(type_parameters or {})}); self.owner=owner
|
|
105
|
+
def __contains__(self,name): return dict.__contains__(self,name) or name in vars(self.owner)
|
|
106
|
+
def __getitem__(self,name):
|
|
107
|
+
if name!="$closure" and name in vars(self.owner): return vars(self.owner)[name]
|
|
108
|
+
if dict.__contains__(self,name): return dict.__getitem__(self,name)
|
|
109
|
+
raise KeyError(name)
|
|
110
|
+
def get(self,name,default=None):
|
|
111
|
+
try: return self[name]
|
|
112
|
+
except KeyError: return default
|
|
113
|
+
class LazyAnnotations(dict):
|
|
114
|
+
"""Dictionary-compatible Python 3.14 annotation thunk container."""
|
|
115
|
+
def __init__(self,vm,scope,initial=None):
|
|
116
|
+
super().__init__(initial or {}); self.vm=vm; self.scope=scope; self.codes={}; self.strings={}; self.evaluated=False; self.owner=None
|
|
117
|
+
def add(self,name,code,text=""): self.codes[name]=code; self.strings[name]=text; self.evaluated=False
|
|
118
|
+
def evaluate(self,format=annotationlib.Format.VALUE,*_args,**_kwargs):
|
|
119
|
+
if format==annotationlib.Format.STRING:
|
|
120
|
+
for code in self.codes.values():
|
|
121
|
+
try: self.vm.run(CodeObject.from_dict(code),self.scope)
|
|
122
|
+
except NameError: pass
|
|
123
|
+
return dict(self.strings)
|
|
124
|
+
if format==annotationlib.Format.FORWARDREF:
|
|
125
|
+
class ForwardGlobals(dict):
|
|
126
|
+
def __missing__(inner,key): return annotationlib.ForwardRef(key,owner=self.owner)
|
|
127
|
+
environment=ForwardGlobals(self.scope)
|
|
128
|
+
return {name:eval(text,environment) for name,text in self.strings.items()}
|
|
129
|
+
if not self.evaluated:
|
|
130
|
+
pending={name:self.vm.run(CodeObject.from_dict(code),self.scope) for name,code in self.codes.items() if not dict.__contains__(self,name)}
|
|
131
|
+
dict.update(self,pending)
|
|
132
|
+
self.evaluated=True
|
|
133
|
+
return self
|
|
134
|
+
def __getitem__(self,key): self.evaluate(); return dict.__getitem__(self,key)
|
|
135
|
+
def __iter__(self): self.evaluate(); return dict.__iter__(self)
|
|
136
|
+
def __len__(self): self.evaluate(); return dict.__len__(self)
|
|
137
|
+
def __repr__(self): self.evaluate(); return dict.__repr__(self)
|
|
138
|
+
def __eq__(self,other): self.evaluate(); return dict.__eq__(self,other)
|
|
139
|
+
def items(self): self.evaluate(); return dict.items(self)
|
|
140
|
+
def keys(self): self.evaluate(); return dict.keys(self)
|
|
141
|
+
def values(self): self.evaluate(); return dict.values(self)
|
|
142
|
+
def get(self,key,default=None): self.evaluate(); return dict.get(self,key,default)
|
|
143
|
+
class HythonReturn(BaseException):
|
|
144
|
+
def __init__(self,value): self.value=value
|
|
145
|
+
class HythonBreak(BaseException): pass
|
|
146
|
+
class HythonContinue(BaseException): pass
|
|
147
|
+
class HythonAwait(BaseException):
|
|
148
|
+
def __init__(self,awaitable): self.awaitable=awaitable
|
|
149
|
+
class HythonAsyncDelegate(BaseException):
|
|
150
|
+
def __init__(self,iterator): self.iterator=iterator
|
|
151
|
+
|
|
152
|
+
@dataclass
|
|
153
|
+
class CallArguments:
|
|
154
|
+
positional: list
|
|
155
|
+
keywords: dict
|
|
156
|
+
|
|
157
|
+
@dataclass
|
|
158
|
+
class CollectionBuilder:
|
|
159
|
+
kind: str
|
|
160
|
+
value: object
|
|
161
|
+
|
|
162
|
+
@dataclass(eq=False)
|
|
163
|
+
class Function:
|
|
164
|
+
code: CodeObject
|
|
165
|
+
globals: dict
|
|
166
|
+
defaults: dict = None
|
|
167
|
+
signature: dict = None
|
|
168
|
+
closure: dict = None
|
|
169
|
+
generator: bool = False
|
|
170
|
+
asynchronous: bool = False
|
|
171
|
+
annotations: dict = None
|
|
172
|
+
type_parameters: dict = None
|
|
173
|
+
class_owner: type = None
|
|
174
|
+
function_name: str = None
|
|
175
|
+
qualname: str = None
|
|
176
|
+
module_name: str = None
|
|
177
|
+
docstring: str = None
|
|
178
|
+
annotation_codes: dict = None
|
|
179
|
+
annotations_evaluated: bool = False
|
|
180
|
+
annotation_strings: dict = None
|
|
181
|
+
runtime_vm: object = None
|
|
182
|
+
local_names: set = None
|
|
183
|
+
free_names: set = None
|
|
184
|
+
class_cell: object = None
|
|
185
|
+
positional_defaults: object = _MISSING
|
|
186
|
+
keyword_defaults: object = _MISSING
|
|
187
|
+
annotation_callable: object = _MISSING
|
|
188
|
+
raw_type_parameters: object = _MISSING
|
|
189
|
+
user_attributes: dict = field(default_factory=dict)
|
|
190
|
+
builtins_namespace: object = _MISSING
|
|
191
|
+
def __getattribute__(self,name):
|
|
192
|
+
if name=="__dict__": return object.__getattribute__(self,"user_attributes")
|
|
193
|
+
if name=="__builtins__":
|
|
194
|
+
value=object.__getattribute__(self,"builtins_namespace")
|
|
195
|
+
if value is _MISSING: value=object.__getattribute__(self,"globals").get("__builtins__",builtins.__dict__)
|
|
196
|
+
return value.__dict__ if isinstance(value,types.ModuleType) else value
|
|
197
|
+
if name=="__annotations__": return object.__getattribute__(self,"_evaluate_annotations")()
|
|
198
|
+
if name=="__annotate__":
|
|
199
|
+
custom=object.__getattribute__(self,"annotation_callable")
|
|
200
|
+
if custom is not _MISSING: return custom
|
|
201
|
+
return object.__getattribute__(self,"_evaluate_annotations") if object.__getattribute__(self,"annotation_codes") else None
|
|
202
|
+
if name=="__type_params__":
|
|
203
|
+
raw=object.__getattribute__(self,"raw_type_parameters")
|
|
204
|
+
return raw if raw is not _MISSING else tuple((object.__getattribute__(self,"type_parameters") or {}).values())
|
|
205
|
+
if name=="__name__": return object.__getattribute__(self,"function_name") or object.__getattribute__(self,"code").name
|
|
206
|
+
if name=="__qualname__": return object.__getattribute__(self,"qualname") or self.__name__
|
|
207
|
+
if name=="__module__": return object.__getattribute__(self,"module_name")
|
|
208
|
+
if name=="__doc__": return object.__getattribute__(self,"docstring")
|
|
209
|
+
if name=="__code__": return object.__getattribute__(self,"code")
|
|
210
|
+
if name=="__globals__": return object.__getattribute__(self,"globals")
|
|
211
|
+
if name=="__closure__": return object.__getattribute__(self,"closure")
|
|
212
|
+
if name=="__signature__": return object.__getattribute__(self,"_inspect_signature")()
|
|
213
|
+
if name=="__defaults__":
|
|
214
|
+
raw=object.__getattribute__(self,"positional_defaults")
|
|
215
|
+
if raw is not _MISSING: return raw
|
|
216
|
+
signature=object.__getattribute__(self,"signature") or {}; defaults=object.__getattribute__(self,"defaults") or {}
|
|
217
|
+
values=[defaults[item] for item in signature.get("positional",[]) if item in defaults]
|
|
218
|
+
return tuple(values) if values else None
|
|
219
|
+
if name=="__kwdefaults__":
|
|
220
|
+
raw=object.__getattribute__(self,"keyword_defaults")
|
|
221
|
+
if raw is not _MISSING: return raw
|
|
222
|
+
signature=object.__getattribute__(self,"signature") or {}; defaults=object.__getattribute__(self,"defaults") or {}
|
|
223
|
+
values={item:defaults[item] for item in signature.get("keyword_only",[]) if item in defaults}
|
|
224
|
+
return values or None
|
|
225
|
+
try: return object.__getattribute__(self,name)
|
|
226
|
+
except AttributeError:
|
|
227
|
+
attributes=object.__getattribute__(self,"user_attributes")
|
|
228
|
+
if name in attributes: return attributes[name]
|
|
229
|
+
raise
|
|
230
|
+
def __setattr__(self,name,value):
|
|
231
|
+
if name=="__dict__":
|
|
232
|
+
if not isinstance(value,dict): raise TypeError("__dict__ must be set to a dictionary")
|
|
233
|
+
object.__setattr__(self,"user_attributes",value); return
|
|
234
|
+
if name=="__builtins__": raise AttributeError("readonly attribute")
|
|
235
|
+
if name in ("__globals__","__closure__"): raise AttributeError("readonly attribute")
|
|
236
|
+
if name=="__code__":
|
|
237
|
+
if not isinstance(value,CodeObject): raise TypeError("__code__ must be set to a Hython code object")
|
|
238
|
+
object.__setattr__(self,"code",value); return
|
|
239
|
+
if name=="__annotations__":
|
|
240
|
+
if value is not None and not isinstance(value,dict): raise TypeError("__annotations__ must be set to a dict object")
|
|
241
|
+
object.__setattr__(self,"annotations",{} if value is None else value)
|
|
242
|
+
object.__setattr__(self,"annotations_evaluated",True); object.__setattr__(self,"annotation_codes",{})
|
|
243
|
+
object.__setattr__(self,"annotation_strings",{}); object.__setattr__(self,"annotation_callable",None); return
|
|
244
|
+
if name=="__annotate__":
|
|
245
|
+
if value is not None and not callable(value): raise TypeError("__annotate__ must be callable or None")
|
|
246
|
+
object.__setattr__(self,"annotation_callable",value)
|
|
247
|
+
if value is not None: object.__setattr__(self,"annotations_evaluated",False)
|
|
248
|
+
return
|
|
249
|
+
if name=="__name__":
|
|
250
|
+
if not isinstance(value,str): raise TypeError("__name__ must be set to a string object")
|
|
251
|
+
object.__setattr__(self,"function_name",value); return
|
|
252
|
+
if name=="__qualname__":
|
|
253
|
+
if not isinstance(value,str): raise TypeError("__qualname__ must be set to a string object")
|
|
254
|
+
object.__setattr__(self,"qualname",value); return
|
|
255
|
+
if name=="__type_params__":
|
|
256
|
+
if not isinstance(value,tuple): raise TypeError("__type_params__ must be set to a tuple")
|
|
257
|
+
object.__setattr__(self,"raw_type_parameters",value); return
|
|
258
|
+
if name=="__module__": object.__setattr__(self,"module_name",value); return
|
|
259
|
+
if name=="__doc__": object.__setattr__(self,"docstring",value); return
|
|
260
|
+
if name=="__defaults__":
|
|
261
|
+
if value is not None and not isinstance(value,tuple): raise TypeError("__defaults__ must be set to a tuple object")
|
|
262
|
+
signature=object.__getattribute__(self,"signature") or {}; positional=signature.get("positional",[])
|
|
263
|
+
defaults=dict(object.__getattribute__(self,"defaults") or {})
|
|
264
|
+
for parameter in positional: defaults.pop(parameter,None)
|
|
265
|
+
if value:
|
|
266
|
+
usable=value[-len(positional):] if positional else ()
|
|
267
|
+
defaults.update(zip(positional[-len(usable):],usable))
|
|
268
|
+
object.__setattr__(self,"defaults",defaults); object.__setattr__(self,"positional_defaults",value); return
|
|
269
|
+
if name=="__kwdefaults__":
|
|
270
|
+
if value is not None and not isinstance(value,dict): raise TypeError("__kwdefaults__ must be set to a dict object")
|
|
271
|
+
signature=object.__getattribute__(self,"signature") or {}; keyword_only=signature.get("keyword_only",[])
|
|
272
|
+
defaults=dict(object.__getattribute__(self,"defaults") or {})
|
|
273
|
+
for parameter in keyword_only: defaults.pop(parameter,None)
|
|
274
|
+
if value: defaults.update({key:item for key,item in value.items() if key in keyword_only})
|
|
275
|
+
object.__setattr__(self,"defaults",defaults); object.__setattr__(self,"keyword_defaults",value); return
|
|
276
|
+
fields=getattr(type(self),"__dataclass_fields__",{})
|
|
277
|
+
if name in fields or name.startswith("_") or "user_attributes" not in object.__getattribute__(self,"__dict__"):
|
|
278
|
+
object.__setattr__(self,name,value); return
|
|
279
|
+
object.__getattribute__(self,"user_attributes")[name]=value
|
|
280
|
+
def __delattr__(self,name):
|
|
281
|
+
if name=="__dict__": raise TypeError("cannot delete __dict__")
|
|
282
|
+
attributes=object.__getattribute__(self,"user_attributes")
|
|
283
|
+
if name in attributes: del attributes[name]; return
|
|
284
|
+
object.__delattr__(self,name)
|
|
285
|
+
def _evaluate_annotations(self,format=annotationlib.Format.VALUE,*_args,**_kwargs):
|
|
286
|
+
custom=self.annotation_callable
|
|
287
|
+
if custom is not _MISSING and custom is not None:
|
|
288
|
+
if format!=annotationlib.Format.VALUE: return custom(format)
|
|
289
|
+
if not self.annotations_evaluated:
|
|
290
|
+
result=custom(format)
|
|
291
|
+
if not isinstance(result,dict): raise TypeError("__annotate__ returned a non-dict")
|
|
292
|
+
self.annotations=result; self.annotations_evaluated=True
|
|
293
|
+
return self.annotations or {}
|
|
294
|
+
codes=self.annotation_codes or {}
|
|
295
|
+
if format==annotationlib.Format.STRING:
|
|
296
|
+
scope=self._annotation_scope()
|
|
297
|
+
vm=VM(); vm.globals=self.globals
|
|
298
|
+
for code in codes.values():
|
|
299
|
+
try: vm.run(CodeObject.from_dict(code),scope)
|
|
300
|
+
except NameError: pass
|
|
301
|
+
return dict(self.annotation_strings or {})
|
|
302
|
+
if format==annotationlib.Format.FORWARDREF:
|
|
303
|
+
owner=self
|
|
304
|
+
class ForwardGlobals(dict):
|
|
305
|
+
def __missing__(inner,key): return annotationlib.ForwardRef(key,owner=owner)
|
|
306
|
+
environment=ForwardGlobals(self._annotation_values())
|
|
307
|
+
return {name:eval(text,environment) for name,text in (self.annotation_strings or {}).items()}
|
|
308
|
+
if codes and not self.annotations_evaluated:
|
|
309
|
+
vm=VM(); vm.globals=self.globals
|
|
310
|
+
scope=self._annotation_scope()
|
|
311
|
+
self.annotations={name:vm.run(CodeObject.from_dict(code),scope) for name,code in codes.items()}
|
|
312
|
+
self.annotations_evaluated=True
|
|
313
|
+
return self.annotations or {}
|
|
314
|
+
def _annotation_values(self):
|
|
315
|
+
values={**self.globals}
|
|
316
|
+
values.update({name:value for name,value in (self.closure or {}).items() if not name.startswith("$")})
|
|
317
|
+
if self.class_owner is not None:
|
|
318
|
+
values.update({parameter.__name__:parameter for parameter in getattr(self.class_owner,"__type_params__",())})
|
|
319
|
+
values.update(vars(self.class_owner))
|
|
320
|
+
values.update(self.type_parameters or {})
|
|
321
|
+
return values
|
|
322
|
+
def _annotation_scope(self):
|
|
323
|
+
outer=self.closure or {}
|
|
324
|
+
if self.class_owner is not None:
|
|
325
|
+
class_parameters={parameter.__name__:parameter for parameter in getattr(self.class_owner,"__type_params__",())}
|
|
326
|
+
outer=ClassAnnotationScope(self.class_owner,outer,class_parameters)
|
|
327
|
+
return TypeExpressionNamespace(outer,self.type_parameters or {},self.globals)
|
|
328
|
+
def _inspect_signature(self):
|
|
329
|
+
specification=self.signature or {"positional":self.code.parameters,"positional_only":[],"keyword_only":[],"vararg":None,"kwarg":None}
|
|
330
|
+
defaults=self.defaults or {}; annotations=self.__annotations__; parameters=[]; positional_only=set(specification.get("positional_only",[]))
|
|
331
|
+
for name in specification.get("positional",[]):
|
|
332
|
+
parameters.append(inspect.Parameter(name,inspect.Parameter.POSITIONAL_ONLY if name in positional_only else inspect.Parameter.POSITIONAL_OR_KEYWORD,default=defaults.get(name,inspect.Parameter.empty),annotation=annotations.get(name,inspect.Parameter.empty)))
|
|
333
|
+
if specification.get("vararg"):
|
|
334
|
+
name=specification["vararg"]; parameters.append(inspect.Parameter(name,inspect.Parameter.VAR_POSITIONAL,annotation=annotations.get(name,inspect.Parameter.empty)))
|
|
335
|
+
for name in specification.get("keyword_only",[]):
|
|
336
|
+
parameters.append(inspect.Parameter(name,inspect.Parameter.KEYWORD_ONLY,default=defaults.get(name,inspect.Parameter.empty),annotation=annotations.get(name,inspect.Parameter.empty)))
|
|
337
|
+
if specification.get("kwarg"):
|
|
338
|
+
name=specification["kwarg"]; parameters.append(inspect.Parameter(name,inspect.Parameter.VAR_KEYWORD,annotation=annotations.get(name,inspect.Parameter.empty)))
|
|
339
|
+
return inspect.Signature(parameters,return_annotation=annotations.get("return",inspect.Signature.empty))
|
|
340
|
+
def __get__(self, instance, owner=None):
|
|
341
|
+
if instance is None: return self
|
|
342
|
+
return BoundFunction(self,instance)
|
|
343
|
+
def __call__(self,*args,**kwargs):
|
|
344
|
+
vm=self.runtime_vm or VM(); vm.globals=self.globals
|
|
345
|
+
scope={**(self.type_parameters or {}),**vm.bind(self,args,kwargs),"$closure":self.closure or {},"$local_names":set(self.local_names or self.code.parameters),"$free_names":set(self.free_names or ()),"$qualname_prefix":f"{self.__qualname__}.<locals>"}
|
|
346
|
+
if self.class_cell is not None:
|
|
347
|
+
try: scope["__class__"]=self.class_cell.cell_contents
|
|
348
|
+
except ValueError: pass
|
|
349
|
+
scope["$has_class_cell"]=True
|
|
350
|
+
if self.class_cell is not None: scope["$class_cell"]=self.class_cell
|
|
351
|
+
if self.generator and self.asynchronous: return HythonAsyncGenerator(HythonGenerator(vm,self.code,scope,self.__name__,self.__qualname__))
|
|
352
|
+
if self.generator: return HythonGenerator(vm,self.code,scope,self.__name__,self.__qualname__)
|
|
353
|
+
if self.asynchronous: return HythonCoroutine(vm,self.code,scope,self.__name__,self.__qualname__)
|
|
354
|
+
active_exception=sys.exception()
|
|
355
|
+
if active_exception is not None: scope["$active_exception"]=active_exception
|
|
356
|
+
try: return vm.run(self.code,scope)
|
|
357
|
+
except HythonReturn as signal: return signal.value
|
|
358
|
+
|
|
359
|
+
@dataclass(frozen=True)
|
|
360
|
+
class BoundFunction:
|
|
361
|
+
function: Function
|
|
362
|
+
instance: object
|
|
363
|
+
def __call__(self,*args,**kwargs): return self.function(self.instance,*args,**kwargs)
|
|
364
|
+
def __getattr__(self,name):
|
|
365
|
+
if name=="__signature__":
|
|
366
|
+
signature=self.function.__signature__; parameters=list(signature.parameters.values())
|
|
367
|
+
return signature.replace(parameters=parameters[1:] if parameters else [])
|
|
368
|
+
return getattr(self.function,name)
|
|
369
|
+
@property
|
|
370
|
+
def __self__(self): return self.instance
|
|
371
|
+
@property
|
|
372
|
+
def __func__(self): return self.function
|
|
373
|
+
@property
|
|
374
|
+
def __func__(self): return self.function
|
|
375
|
+
|
|
376
|
+
class HythonGenerator:
|
|
377
|
+
"""Resumable HBC frame implementing lazy yield/yield-from."""
|
|
378
|
+
def __init__(self,vm,code,local,function_name=None,qualname=None):
|
|
379
|
+
self.vm=vm; self.code=code; self.local=local; self.function_name=function_name or code.name; self.qualname=qualname or self.function_name; self.stack=[]; self.ip=0; self.delegate=None; self.delegate_push_result=True; self.delegate_control=None; self.done=False; self.started=False; self.suspended=False; self._running=False
|
|
380
|
+
@property
|
|
381
|
+
def gi_code(self): return self.code
|
|
382
|
+
@property
|
|
383
|
+
def gi_frame(self): return None if self.done else SimpleNamespace(f_code=self.code,f_locals=self.local,f_lasti=self.ip-1)
|
|
384
|
+
@property
|
|
385
|
+
def gi_running(self): return self._running
|
|
386
|
+
@property
|
|
387
|
+
def gi_suspended(self): return self.suspended and not self._running and not self.done
|
|
388
|
+
@property
|
|
389
|
+
def gi_yieldfrom(self): return self.delegate
|
|
390
|
+
def __getattribute__(self,name):
|
|
391
|
+
if name=="__name__": return object.__getattribute__(self,"function_name")
|
|
392
|
+
if name=="__qualname__": return object.__getattribute__(self,"qualname")
|
|
393
|
+
return object.__getattribute__(self,name)
|
|
394
|
+
def __iter__(self): return self
|
|
395
|
+
def __next__(self): return self.send(None)
|
|
396
|
+
def send(self,value):
|
|
397
|
+
if self._running: raise ValueError("generator already executing")
|
|
398
|
+
if self.done: raise StopIteration
|
|
399
|
+
active_exception=sys.exception()
|
|
400
|
+
if active_exception is not None and "$active_exception" not in self.local:
|
|
401
|
+
self.local["$active_exception"]=active_exception
|
|
402
|
+
self.local["$inherited_active_exception"]=active_exception
|
|
403
|
+
self._running=True
|
|
404
|
+
try: return self._send(value)
|
|
405
|
+
except _GeneratorReturn as signal: raise StopIteration(signal.value) from None
|
|
406
|
+
except StopIteration as exc:
|
|
407
|
+
self.done=True
|
|
408
|
+
raise RuntimeError("generator raised StopIteration") from exc
|
|
409
|
+
except (HythonReturn,HythonBreak,HythonContinue): raise
|
|
410
|
+
except BaseException as exc:
|
|
411
|
+
self.vm.restore_saved_names(self.local)
|
|
412
|
+
index=max(0,self.ip-1); line=self.code.lines[index] if self.code.lines and index<len(self.code.lines) else 0
|
|
413
|
+
frames=getattr(exc,"__hython_frames__",None)
|
|
414
|
+
if frames is None: frames=[]; setattr(exc,"__hython_frames__",frames)
|
|
415
|
+
frame=(self.code.name,line,index)
|
|
416
|
+
if not frames or frames[-1]!=frame:
|
|
417
|
+
frames.append(frame); exc.add_note(f"하이썬 위치: {self.code.name}:{line}" if line else f"하이썬 위치: {self.code.name}")
|
|
418
|
+
raise
|
|
419
|
+
finally:
|
|
420
|
+
inherited=self.local.pop("$inherited_active_exception",_MISSING)
|
|
421
|
+
if inherited is not _MISSING and self.local.get("$active_exception") is inherited:
|
|
422
|
+
self.local.pop("$active_exception",None)
|
|
423
|
+
self._running=False
|
|
424
|
+
def _send(self,value):
|
|
425
|
+
if self.done: raise StopIteration
|
|
426
|
+
if not self.started and value is not None: raise TypeError("시작 전 제너레이터에는 None만 보낼 수 있습니다.")
|
|
427
|
+
if self.suspended:
|
|
428
|
+
if self.delegate is None: self.stack.append(value)
|
|
429
|
+
self.suspended=False
|
|
430
|
+
self.started=True
|
|
431
|
+
if self.delegate is not None:
|
|
432
|
+
try:
|
|
433
|
+
return next(self.delegate) if value is None else self.delegate.send(value)
|
|
434
|
+
except HythonReturn as signal:
|
|
435
|
+
self.done=True; self.delegate=None; self.stack.clear()
|
|
436
|
+
raise _GeneratorReturn(signal.value)
|
|
437
|
+
except (HythonBreak,HythonContinue) as signal:
|
|
438
|
+
control=self.delegate_control; self.delegate=None; self.delegate_control=None
|
|
439
|
+
target=control["break_target"] if isinstance(signal,HythonBreak) else control["continue_target"]
|
|
440
|
+
if target is None: raise
|
|
441
|
+
self.ip=target; self.suspended=False
|
|
442
|
+
return self._send(None)
|
|
443
|
+
except StopIteration as stop:
|
|
444
|
+
self.delegate=None
|
|
445
|
+
if self.delegate_push_result: self.stack.append(stop.value)
|
|
446
|
+
self.delegate_push_result=True
|
|
447
|
+
insns=self.code.instructions; stack=self.stack
|
|
448
|
+
binary={"ADD":operator.add,"SUB":operator.sub,"MUL":operator.mul,"DIV":operator.truediv,"FLOORDIV":operator.floordiv,"MOD":operator.mod,"POW":operator.pow,
|
|
449
|
+
"EQ":operator.eq,"NE":operator.ne,"LT":operator.lt,"LE":operator.le,"GT":operator.gt,"GE":operator.ge,"IN":lambda a,b:a in b,"IS":operator.is_,"NOT_IN":lambda a,b:a not in b,"IS_NOT":operator.is_not}
|
|
450
|
+
binary.update({"BIT_OR":operator.or_,"BIT_XOR":operator.xor,"BIT_AND":operator.and_,"LSHIFT":operator.lshift,"RSHIFT":operator.rshift,"MATMUL":operator.matmul})
|
|
451
|
+
binary.update({"IADD":operator.iadd,"ISUB":operator.isub,"IMUL":operator.imul,"IDIV":operator.itruediv,"IFLOORDIV":operator.ifloordiv,"IMOD":operator.imod,"IPOW":operator.ipow,"IBIT_OR":operator.ior,"IBIT_XOR":operator.ixor,"IBIT_AND":operator.iand,"ILSHIFT":operator.ilshift,"IRSHIFT":operator.irshift,"IMATMUL":operator.imatmul})
|
|
452
|
+
while self.ip<len(insns):
|
|
453
|
+
ins=insns[self.ip]; op=ins[0]; arg=ins[1] if len(ins)>1 else None; self.ip+=1
|
|
454
|
+
if op=="CONST": stack.append(self.code.constants[arg])
|
|
455
|
+
elif op=="LOAD":
|
|
456
|
+
if arg in self.local: stack.append(self.local[arg])
|
|
457
|
+
elif arg in self.local.get("$local_names",()): raise UnboundLocalError(f"local variable '{arg}' referenced before assignment")
|
|
458
|
+
elif arg in self.local.get("$free_names",()):
|
|
459
|
+
closure=self.vm.nonlocal_scope(self.local,arg)
|
|
460
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
461
|
+
stack.append(closure[arg])
|
|
462
|
+
elif (found:=self.vm.lookup_closure(self.local,arg))[0]: stack.append(found[1])
|
|
463
|
+
elif "$class_outer" in self.local and arg not in self.local.get("$class_local_names",()) and arg in self.local["$class_outer"]: stack.append(self.local["$class_outer"][arg])
|
|
464
|
+
elif arg in self.vm.globals: stack.append(self.vm.globals[arg])
|
|
465
|
+
else: raise NameError(f"name '{arg}' is not defined")
|
|
466
|
+
elif op=="STORE": self.local[arg]=stack.pop()
|
|
467
|
+
elif op=="SAVE_NAME": self.vm.save_name(self.local,arg)
|
|
468
|
+
elif op=="RESTORE_NAME": self.vm.restore_name(self.local,arg)
|
|
469
|
+
elif op=="ANNOTATE": self.local.setdefault("__annotations__",{})[arg]=stack.pop()
|
|
470
|
+
elif op=="ANNOTATE_LAZY": self.vm.register_annotation(self.local,arg)
|
|
471
|
+
elif op=="SUPER": stack.append(self.vm.zero_argument_super(self.local,arg))
|
|
472
|
+
elif op=="MAKE_TYPE_ALIAS": stack.append(self.vm.make_type_alias(arg,self.local))
|
|
473
|
+
elif op=="MAKE_TYPE_PARAMETER": stack.append(self.vm.make_type_parameter(arg,self.local))
|
|
474
|
+
elif op=="STORE_GLOBAL": self.vm.globals[arg]=stack.pop()
|
|
475
|
+
elif op=="STORE_NONLOCAL":
|
|
476
|
+
closure=self.vm.nonlocal_scope(self.local,arg)
|
|
477
|
+
closure[arg]=stack.pop()
|
|
478
|
+
elif op=="DELETE":
|
|
479
|
+
if arg not in self.local: raise self.vm.missing_delete_error(self.local,arg)
|
|
480
|
+
del self.local[arg]
|
|
481
|
+
elif op=="DELETE_GLOBAL":
|
|
482
|
+
if arg not in self.vm.globals: raise NameError(f"name '{arg}' is not defined")
|
|
483
|
+
del self.vm.globals[arg]
|
|
484
|
+
elif op=="DELETE_NONLOCAL":
|
|
485
|
+
closure=self.vm.nonlocal_scope(self.local,arg)
|
|
486
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
487
|
+
del closure[arg]
|
|
488
|
+
elif op=="UNPACK":
|
|
489
|
+
values=self.vm.unpack_exact(stack.pop(),arg)
|
|
490
|
+
stack.extend(reversed(values))
|
|
491
|
+
elif op=="UNPACK_EX":
|
|
492
|
+
before=arg>>16; after=arg&0xFFFF
|
|
493
|
+
stack.extend(reversed(self.vm.unpack_extended(stack.pop(),before,after)))
|
|
494
|
+
elif op=="POP": stack.pop()
|
|
495
|
+
elif op=="DUP": stack.append(stack[-1])
|
|
496
|
+
elif op=="DUP2": stack.extend(stack[-2:])
|
|
497
|
+
elif op in binary: b=stack.pop(); a=stack.pop(); stack.append(binary[op](a,b))
|
|
498
|
+
elif op in ("NEG","POS","NOT","INVERT"): stack.append({"NEG":operator.neg,"POS":operator.pos,"NOT":operator.not_,"INVERT":operator.invert}[op](stack.pop()))
|
|
499
|
+
elif op=="JUMP": self.ip=arg
|
|
500
|
+
elif op=="JUMP_FALSE":
|
|
501
|
+
if not stack.pop(): self.ip=arg
|
|
502
|
+
elif op=="JUMP_IF_FALSE_OR_POP":
|
|
503
|
+
if not stack[-1]: self.ip=arg
|
|
504
|
+
else: stack.pop()
|
|
505
|
+
elif op=="JUMP_IF_TRUE_OR_POP":
|
|
506
|
+
if stack[-1]: self.ip=arg
|
|
507
|
+
else: stack.pop()
|
|
508
|
+
elif op=="ITER": stack.append(iter(stack.pop()))
|
|
509
|
+
elif op=="FOR_ITER":
|
|
510
|
+
try: stack.append(next(stack[-1]))
|
|
511
|
+
except StopIteration: stack.pop(); self.ip=arg
|
|
512
|
+
elif op in ("BUILD_LIST","BUILD_TUPLE","BUILD_SET"):
|
|
513
|
+
values=stack[-arg:] if arg else []
|
|
514
|
+
if arg: del stack[-arg:]
|
|
515
|
+
stack.append(list(values) if op=="BUILD_LIST" else tuple(values) if op=="BUILD_TUPLE" else set(values))
|
|
516
|
+
elif op=="BUILD_DICT":
|
|
517
|
+
values=stack[-arg*2:] if arg else []
|
|
518
|
+
if arg: del stack[-arg*2:]
|
|
519
|
+
stack.append(dict(zip(values[::2],values[1::2])))
|
|
520
|
+
elif op=="BUILD_UNPACK":
|
|
521
|
+
count=len(arg["starred"]); values=stack[-count:] if count else []
|
|
522
|
+
if count: del stack[-count:]
|
|
523
|
+
merged=[]
|
|
524
|
+
for value,starred in zip(values,arg["starred"]): merged.extend(value) if starred else merged.append(value)
|
|
525
|
+
stack.append(tuple(merged) if arg["kind"]=="tuple" else set(merged) if arg["kind"]=="set" else merged)
|
|
526
|
+
elif op=="BUILD_DICT_UNPACK":
|
|
527
|
+
count=sum(2 if item=="pair" else 1 for item in arg); values=stack[-count:] if count else []
|
|
528
|
+
if count: del stack[-count:]
|
|
529
|
+
result={}; index=0
|
|
530
|
+
for item in arg:
|
|
531
|
+
if item=="pair": result[values[index]]=values[index+1]; index+=2
|
|
532
|
+
else: result.update(values[index]); index+=1
|
|
533
|
+
stack.append(result)
|
|
534
|
+
elif op=="COLLECTION_BEGIN": stack.append(self.vm.collection_builder(arg))
|
|
535
|
+
elif op=="COLLECTION_ADD":
|
|
536
|
+
value=stack.pop(); key=stack.pop() if arg=="pair" else None
|
|
537
|
+
self.vm.add_collection_item(stack[-1],arg,value,key)
|
|
538
|
+
elif op=="COLLECTION_READY": stack.append(self.vm.finish_collection(stack.pop()))
|
|
539
|
+
elif op=="BUILD_SLICE":
|
|
540
|
+
step=stack.pop(); stop=stack.pop(); start=stack.pop(); stack.append(slice(start,stop,step))
|
|
541
|
+
elif op=="GET_ATTR": stack.append(getattr(stack.pop(),arg))
|
|
542
|
+
elif op=="SET_ATTR":
|
|
543
|
+
value=stack.pop(); target=stack.pop(); setattr(target,arg,value)
|
|
544
|
+
elif op=="GET_ITEM": index=stack.pop(); stack.append(stack.pop()[index])
|
|
545
|
+
elif op=="SET_ITEM":
|
|
546
|
+
value=stack.pop(); index=stack.pop(); stack.pop()[index]=value
|
|
547
|
+
elif op=="DELETE_ITEM":
|
|
548
|
+
index=stack.pop(); del stack.pop()[index]
|
|
549
|
+
elif op=="DELETE_ATTR": delattr(stack.pop(),arg)
|
|
550
|
+
elif op=="IMPORT": stack.append(self.vm.import_module(arg,self.code))
|
|
551
|
+
elif op=="IMPORT_FROM": stack.append(self.vm.import_from(arg["module"],arg["name"],self.code))
|
|
552
|
+
elif op=="IMPORT_STAR": self.vm.import_star(self.local,stack.pop())
|
|
553
|
+
elif op=="FORMAT": stack.append(str(stack.pop()))
|
|
554
|
+
elif op=="FORMAT_VALUE":
|
|
555
|
+
spec=stack.pop() if arg["has_spec"] else ""; value=stack.pop()
|
|
556
|
+
if arg["conversion"]=="r": value=repr(value)
|
|
557
|
+
elif arg["conversion"]=="s": value=str(value)
|
|
558
|
+
elif arg["conversion"]=="a": value=ascii(value)
|
|
559
|
+
stack.append(format(value,spec))
|
|
560
|
+
elif op=="BUILD_STRING":
|
|
561
|
+
values=stack[-arg:] if arg else []
|
|
562
|
+
if arg: del stack[-arg:]
|
|
563
|
+
stack.append("".join(values))
|
|
564
|
+
elif op=="MAKE_INTERPOLATION":
|
|
565
|
+
spec=stack.pop(); conversion=stack.pop(); expression=stack.pop(); value=stack.pop(); stack.append(Interpolation(value,expression,conversion,spec))
|
|
566
|
+
elif op=="BUILD_TEMPLATE":
|
|
567
|
+
values=stack[-arg:] if arg else []
|
|
568
|
+
if arg: del stack[-arg:]
|
|
569
|
+
stack.append(Template(*values))
|
|
570
|
+
elif op=="ASSERT":
|
|
571
|
+
message=stack.pop(); condition=stack.pop()
|
|
572
|
+
if not condition: raise AssertionError(message) if message is not None else AssertionError()
|
|
573
|
+
elif op=="RAISE": raise stack.pop()
|
|
574
|
+
elif op=="RAISE_FROM":
|
|
575
|
+
cause=stack.pop(); error=stack.pop(); raise error from cause
|
|
576
|
+
elif op=="RERAISE":
|
|
577
|
+
self.vm.reraise(self.local)
|
|
578
|
+
elif op=="MATCH_PATTERN":
|
|
579
|
+
bindings={}; matched=self.vm.match_pattern(stack.pop(),arg,bindings,self.local)
|
|
580
|
+
if matched: self.vm.apply_pattern_bindings(self.local,bindings)
|
|
581
|
+
stack.append(matched)
|
|
582
|
+
elif op=="CHAIN_COMPARE": stack.append(self.vm.run_compare_chain(arg,self.local))
|
|
583
|
+
elif op=="CALL":
|
|
584
|
+
args=stack[-arg:] if arg else []
|
|
585
|
+
if arg: del stack[-arg:]
|
|
586
|
+
stack.append(self.vm.call_value(stack.pop(),args,{},self.local))
|
|
587
|
+
elif op=="CALL_EX":
|
|
588
|
+
values=stack[-len(arg):] if arg else []
|
|
589
|
+
if arg: del stack[-len(arg):]
|
|
590
|
+
function=stack.pop(); positional,keywords=self.vm.expand_call_arguments(arg,values)
|
|
591
|
+
stack.append(self.vm.call_value(function,positional,keywords,self.local))
|
|
592
|
+
elif op=="CALL_BEGIN": stack.append(CallArguments([],{}))
|
|
593
|
+
elif op=="CALL_ARG": self.vm.add_call_argument(stack[-2],arg,stack.pop())
|
|
594
|
+
elif op=="CALL_READY":
|
|
595
|
+
arguments=stack.pop(); function=stack.pop()
|
|
596
|
+
stack.append(self.vm.call_value(function,arguments.positional,arguments.keywords,self.local))
|
|
597
|
+
elif op=="CLASS_BEGIN": stack.append(CallArguments([],{}))
|
|
598
|
+
elif op=="CLASS_ARG": self.vm.add_class_argument(stack[-2],arg,stack.pop())
|
|
599
|
+
elif op=="MAKE_FUNCTION":
|
|
600
|
+
stack.append(self.vm.create_function(arg,self.local,stack))
|
|
601
|
+
elif op=="MAKE_CLASS":
|
|
602
|
+
stack.append(self.vm.create_class(arg,self.local,stack))
|
|
603
|
+
elif op=="COMPREHENSION":
|
|
604
|
+
if arg.get("async",any(clause.get("async",False) for clause in arg["clauses"])):
|
|
605
|
+
if arg["kind"]=="generatorexpr":
|
|
606
|
+
self.suspended=True; raise HythonAwait(self.vm.prepare_async_generator_expression(arg,self.local))
|
|
607
|
+
self.suspended=True; raise HythonAwait(self.vm.run_async_comprehension(arg,self.local))
|
|
608
|
+
if arg["kind"]=="generatorexpr": stack.append(self.vm.generator_expression(arg,self.local)); continue
|
|
609
|
+
scope=ComprehensionScope(self.vm.comprehension_parent(self.local),arg.get("bindings",())); result={} if arg["kind"]=="dictcomp" else set() if arg["kind"]=="setcomp" else []
|
|
610
|
+
def collect(index):
|
|
611
|
+
if index<len(arg["clauses"]):
|
|
612
|
+
clause=arg["clauses"][index]
|
|
613
|
+
for item in self.vm.run(CodeObject.from_dict(clause["iter"]),scope):
|
|
614
|
+
self.vm.assign_target(scope,clause["target"],item)
|
|
615
|
+
if all(self.vm.run(CodeObject.from_dict(test),scope) for test in clause["filters"]): collect(index+1)
|
|
616
|
+
return
|
|
617
|
+
if arg["kind"]=="dictcomp":
|
|
618
|
+
key=self.vm.run(CodeObject.from_dict(arg["key"]),scope)
|
|
619
|
+
result[key]=self.vm.run(CodeObject.from_dict(arg["value"]),scope)
|
|
620
|
+
else:
|
|
621
|
+
value=self.vm.run(CodeObject.from_dict(arg["element"]),scope)
|
|
622
|
+
result.add(value) if arg["kind"]=="setcomp" else result.append(value)
|
|
623
|
+
collect(0); self.vm.commit_comprehension_bindings(arg,scope,self.local); stack.append(result)
|
|
624
|
+
elif op=="YIELD":
|
|
625
|
+
result=stack.pop(); self.suspended=True; return result
|
|
626
|
+
elif op=="AWAIT":
|
|
627
|
+
awaitable=stack.pop(); self.vm.inherit_active_exception(awaitable,self.local)
|
|
628
|
+
self.suspended=True; raise HythonAwait(awaitable)
|
|
629
|
+
elif op=="ASYNC_FOR": raise HythonAsyncDelegate(self._run_async_for(arg))
|
|
630
|
+
elif op=="ASYNC_WITH": raise HythonAsyncDelegate(self._run_async_with(arg))
|
|
631
|
+
elif op=="YIELD_FROM":
|
|
632
|
+
self.delegate=iter(stack.pop()); self.delegate_push_result=True; self.delegate_control=None
|
|
633
|
+
try:
|
|
634
|
+
result=next(self.delegate); self.suspended=True; return result
|
|
635
|
+
except StopIteration as stop: self.delegate=None; stack.append(stop.value)
|
|
636
|
+
elif op=="TRY":
|
|
637
|
+
self.delegate=self._run_try(arg); self.delegate_push_result=False; self.delegate_control=arg
|
|
638
|
+
try:
|
|
639
|
+
result=next(self.delegate); self.suspended=True; return result
|
|
640
|
+
except HythonReturn as signal:
|
|
641
|
+
self.done=True; self.delegate=None; raise _GeneratorReturn(signal.value)
|
|
642
|
+
except StopIteration:
|
|
643
|
+
self.delegate=None; self.delegate_push_result=True
|
|
644
|
+
elif op=="WITH":
|
|
645
|
+
self.delegate=self._run_with(arg); self.delegate_push_result=False; self.delegate_control=arg
|
|
646
|
+
try:
|
|
647
|
+
result=next(self.delegate); self.suspended=True; return result
|
|
648
|
+
except HythonReturn as signal:
|
|
649
|
+
self.done=True; self.delegate=None; raise _GeneratorReturn(signal.value)
|
|
650
|
+
except StopIteration:
|
|
651
|
+
self.delegate=None; self.delegate_push_result=True
|
|
652
|
+
elif op=="RETURN": self.done=True; raise _GeneratorReturn(stack.pop())
|
|
653
|
+
elif op=="SIGNAL_RETURN": self.done=True; raise HythonReturn(stack.pop())
|
|
654
|
+
elif op=="SIGNAL_BREAK": self.done=True; raise HythonBreak()
|
|
655
|
+
elif op=="SIGNAL_CONTINUE": self.done=True; raise HythonContinue()
|
|
656
|
+
elif op=="NOP": pass
|
|
657
|
+
else: raise VMError(f"제너레이터에서 아직 지원하지 않는 HBC 명령어: {op}")
|
|
658
|
+
self.done=True; raise _GeneratorReturn()
|
|
659
|
+
def _run_child(self,payload):
|
|
660
|
+
return HythonGenerator(self.vm,CodeObject.from_dict(payload),self.local)
|
|
661
|
+
def _run_try(self,arg):
|
|
662
|
+
"""Execute structured TRY payload while preserving yields and injected exceptions."""
|
|
663
|
+
try:
|
|
664
|
+
try:
|
|
665
|
+
yield from self._run_child(arg["body"])
|
|
666
|
+
except (HythonReturn,HythonBreak,HythonContinue):
|
|
667
|
+
raise
|
|
668
|
+
except BaseException as exc:
|
|
669
|
+
if arg["handlers"] and arg["handlers"][0].get("star",False):
|
|
670
|
+
original=exc if isinstance(exc,BaseExceptionGroup) else BaseExceptionGroup("",[exc]); remaining=original; raised=[]; reraised=[]
|
|
671
|
+
for handler in arg["handlers"]:
|
|
672
|
+
expected=self.vm.run(CodeObject.from_dict(handler["type"]),self.local)
|
|
673
|
+
matched,remaining=remaining.split(expected)
|
|
674
|
+
if matched is None: continue
|
|
675
|
+
if handler["alias"]: self.vm.assign_name(self.local,handler["alias"],matched,handler.get("alias_scope","local"))
|
|
676
|
+
previous=self.vm.push_active_exception(self.local,matched)
|
|
677
|
+
try: yield from self._run_child(handler["code"])
|
|
678
|
+
except BaseException as failure:
|
|
679
|
+
(reraised if failure is matched else raised).append(failure)
|
|
680
|
+
finally:
|
|
681
|
+
self.vm.pop_active_exception(self.local,previous)
|
|
682
|
+
if handler["alias"]: self.vm.delete_name(self.local,handler["alias"],handler.get("alias_scope","local"))
|
|
683
|
+
failure=_merge_except_star(original,reraised,raised,remaining)
|
|
684
|
+
if failure is not None: raise failure
|
|
685
|
+
return
|
|
686
|
+
handled=False
|
|
687
|
+
for handler in arg["handlers"]:
|
|
688
|
+
expected=self.vm.run(CodeObject.from_dict(handler["type"]),self.local) if handler["type"] else BaseException
|
|
689
|
+
if isinstance(exc,expected):
|
|
690
|
+
if handler["alias"]: self.vm.assign_name(self.local,handler["alias"],exc,handler.get("alias_scope","local"))
|
|
691
|
+
previous=self.vm.push_active_exception(self.local,exc)
|
|
692
|
+
try: yield from self._run_child(handler["code"])
|
|
693
|
+
finally:
|
|
694
|
+
self.vm.pop_active_exception(self.local,previous)
|
|
695
|
+
if handler["alias"]: self.vm.delete_name(self.local,handler["alias"],handler.get("alias_scope","local"))
|
|
696
|
+
handled=True; break
|
|
697
|
+
if not handled: raise
|
|
698
|
+
else:
|
|
699
|
+
if arg["else"]: yield from self._run_child(arg["else"])
|
|
700
|
+
finally:
|
|
701
|
+
if arg["finally"]:
|
|
702
|
+
active=sys.exception(); previous=_MISSING; pushed=False
|
|
703
|
+
if active is not None and not isinstance(active,(HythonReturn,HythonBreak,HythonContinue)):
|
|
704
|
+
previous=self.vm.push_active_exception(self.local,active); pushed=True
|
|
705
|
+
try: yield from self._run_child(arg["finally"])
|
|
706
|
+
finally:
|
|
707
|
+
if pushed: self.vm.pop_active_exception(self.local,previous)
|
|
708
|
+
def _run_with(self,arg):
|
|
709
|
+
exits=[]; failure=None
|
|
710
|
+
try:
|
|
711
|
+
for manager in arg["managers"]:
|
|
712
|
+
context=self.vm.run(CodeObject.from_dict(manager["code"]),self.local)
|
|
713
|
+
enter_method,exit_method=self.vm.context_methods(context,False)
|
|
714
|
+
entered=enter_method()
|
|
715
|
+
exits.append(exit_method)
|
|
716
|
+
if manager["alias"]: self.vm.assign_target(self.local,manager["alias"],entered)
|
|
717
|
+
yield from self._run_child(arg["body"])
|
|
718
|
+
except BaseException as caught:
|
|
719
|
+
failure=caught
|
|
720
|
+
self.vm.unwind_exits(exits,failure)
|
|
721
|
+
async def _run_async_for(self,arg):
|
|
722
|
+
iterable=self.vm.run(CodeObject.from_dict(arg["iter"]),self.local)
|
|
723
|
+
broken=False
|
|
724
|
+
async for item in iterable:
|
|
725
|
+
self.vm.assign_target(self.local,arg["target"],item)
|
|
726
|
+
child=HythonAsyncGenerator(self._run_child(arg["body"]))
|
|
727
|
+
try:
|
|
728
|
+
operation=("next",None)
|
|
729
|
+
while True:
|
|
730
|
+
try:
|
|
731
|
+
yielded=await (child.__anext__() if operation[0]=="next" else child.asend(operation[1]) if operation[0]=="send" else child.athrow(operation[1]))
|
|
732
|
+
except StopAsyncIteration: break
|
|
733
|
+
try:
|
|
734
|
+
sent=yield yielded; operation=("next",None) if sent is None else ("send",sent)
|
|
735
|
+
except GeneratorExit:
|
|
736
|
+
await child.aclose(); raise
|
|
737
|
+
except BaseException as injected: operation=("throw",injected)
|
|
738
|
+
except HythonContinue: continue
|
|
739
|
+
except HythonBreak: broken=True; break
|
|
740
|
+
if not broken and arg.get("else"):
|
|
741
|
+
child=HythonAsyncGenerator(self._run_child(arg["else"]))
|
|
742
|
+
operation=("next",None)
|
|
743
|
+
while True:
|
|
744
|
+
try:
|
|
745
|
+
yielded=await (child.__anext__() if operation[0]=="next" else child.asend(operation[1]) if operation[0]=="send" else child.athrow(operation[1]))
|
|
746
|
+
except StopAsyncIteration: break
|
|
747
|
+
try:
|
|
748
|
+
sent=yield yielded; operation=("next",None) if sent is None else ("send",sent)
|
|
749
|
+
except GeneratorExit:
|
|
750
|
+
await child.aclose(); raise
|
|
751
|
+
except BaseException as injected: operation=("throw",injected)
|
|
752
|
+
async def _run_async_with(self,arg):
|
|
753
|
+
exits=[]; failure=None
|
|
754
|
+
try:
|
|
755
|
+
for manager in arg["managers"]:
|
|
756
|
+
context=self.vm.run(CodeObject.from_dict(manager["code"]),self.local)
|
|
757
|
+
enter_method,exit_method=self.vm.context_methods(context,True)
|
|
758
|
+
entered=await enter_method()
|
|
759
|
+
exits.append(exit_method)
|
|
760
|
+
if manager["alias"]: self.vm.assign_target(self.local,manager["alias"],entered)
|
|
761
|
+
child=HythonAsyncGenerator(self._run_child(arg["body"]))
|
|
762
|
+
operation=("next",None)
|
|
763
|
+
while True:
|
|
764
|
+
try:
|
|
765
|
+
yielded=await (child.__anext__() if operation[0]=="next" else child.asend(operation[1]) if operation[0]=="send" else child.athrow(operation[1]))
|
|
766
|
+
except StopAsyncIteration: break
|
|
767
|
+
try:
|
|
768
|
+
sent=yield yielded; operation=("next",None) if sent is None else ("send",sent)
|
|
769
|
+
except GeneratorExit:
|
|
770
|
+
await child.aclose(); raise
|
|
771
|
+
except BaseException as injected: operation=("throw",injected)
|
|
772
|
+
except BaseException as caught:
|
|
773
|
+
failure=caught
|
|
774
|
+
await self.vm.unwind_async_exits(exits,failure)
|
|
775
|
+
def close(self):
|
|
776
|
+
if self.done: return None
|
|
777
|
+
if self.delegate is not None and self.delegate_control is None:
|
|
778
|
+
delegate=self.delegate
|
|
779
|
+
try:
|
|
780
|
+
close=getattr(delegate,"close",None)
|
|
781
|
+
if close is not None: close()
|
|
782
|
+
return None
|
|
783
|
+
finally:
|
|
784
|
+
self.done=True; self.stack.clear(); self.delegate=None
|
|
785
|
+
try:
|
|
786
|
+
result=self.throw(GeneratorExit)
|
|
787
|
+
except GeneratorExit: return None
|
|
788
|
+
except StopIteration as stopped: return stopped.value
|
|
789
|
+
else:
|
|
790
|
+
raise RuntimeError("generator ignored GeneratorExit")
|
|
791
|
+
finally:
|
|
792
|
+
self.done=True; self.stack.clear(); self.delegate=None
|
|
793
|
+
def throw(self,exception,*args):
|
|
794
|
+
error=_thrown_exception(exception,args)
|
|
795
|
+
if self.done: raise error
|
|
796
|
+
if self.delegate is not None and hasattr(self.delegate,"throw"):
|
|
797
|
+
try:
|
|
798
|
+
return self.delegate.throw(error)
|
|
799
|
+
except HythonReturn as signal:
|
|
800
|
+
self.done=True; self.delegate=None; self.stack.clear()
|
|
801
|
+
raise StopIteration(signal.value)
|
|
802
|
+
except StopIteration as stop:
|
|
803
|
+
self.delegate=None
|
|
804
|
+
if self.delegate_push_result: self.stack.append(stop.value)
|
|
805
|
+
self.delegate_push_result=True
|
|
806
|
+
return self.send(None)
|
|
807
|
+
except BaseException:
|
|
808
|
+
self.done=True; raise
|
|
809
|
+
self.done=True; self.stack.clear(); self.delegate=None
|
|
810
|
+
if isinstance(error,StopIteration): raise RuntimeError("generator raised StopIteration") from error
|
|
811
|
+
raise error
|
|
812
|
+
|
|
813
|
+
class HythonCoroutine:
|
|
814
|
+
"""Awaitable HBC frame; resumes after each AWAIT opcode."""
|
|
815
|
+
def __init__(self,vm,code,local,function_name=None,qualname=None): self.vm=vm; self.code=code; self.local=local; self.function_name=function_name or code.name; self.qualname=qualname or self.function_name; self.ip=0; self._driver=None; self._running=False; self._closed=False; self._awaiting=None; self._started=False
|
|
816
|
+
@property
|
|
817
|
+
def cr_code(self): return self.code
|
|
818
|
+
@property
|
|
819
|
+
def cr_frame(self): return None if self._closed else SimpleNamespace(f_code=self.code,f_locals=self.local,f_lasti=self.ip-1)
|
|
820
|
+
@property
|
|
821
|
+
def cr_running(self): return self._running
|
|
822
|
+
@property
|
|
823
|
+
def cr_suspended(self): return self._started and not self._running and not self._closed
|
|
824
|
+
@property
|
|
825
|
+
def cr_await(self):
|
|
826
|
+
awaiting=self._awaiting
|
|
827
|
+
seen=set()
|
|
828
|
+
while isinstance(awaiting,HythonCoroutine) and id(awaiting) not in seen:
|
|
829
|
+
seen.add(id(awaiting)); nested=awaiting.cr_await
|
|
830
|
+
if nested is None: break
|
|
831
|
+
awaiting=nested
|
|
832
|
+
return awaiting
|
|
833
|
+
def __getattribute__(self,name):
|
|
834
|
+
if name=="__name__": return object.__getattribute__(self,"function_name")
|
|
835
|
+
if name=="__qualname__": return object.__getattribute__(self,"qualname")
|
|
836
|
+
return object.__getattribute__(self,name)
|
|
837
|
+
def _iterator(self):
|
|
838
|
+
if self._driver is None:
|
|
839
|
+
if self._closed: raise RuntimeError("cannot reuse already awaited coroutine")
|
|
840
|
+
self._driver=self.wrapped().__await__()
|
|
841
|
+
return self._driver
|
|
842
|
+
def __await__(self): return self
|
|
843
|
+
def __iter__(self): return self
|
|
844
|
+
def __next__(self): return self.send(None)
|
|
845
|
+
def send(self,value):
|
|
846
|
+
if self._closed: raise RuntimeError("cannot reuse already awaited coroutine")
|
|
847
|
+
if self._running: raise ValueError("coroutine already executing")
|
|
848
|
+
self._running=True
|
|
849
|
+
self._started=True
|
|
850
|
+
try: return self._iterator().send(value)
|
|
851
|
+
except StopIteration: self._closed=True; raise
|
|
852
|
+
except BaseException: self._closed=True; raise
|
|
853
|
+
finally: self._running=False
|
|
854
|
+
def throw(self,exception,*args):
|
|
855
|
+
if self._closed: raise RuntimeError("cannot reuse already awaited coroutine")
|
|
856
|
+
if self._running: raise ValueError("coroutine already executing")
|
|
857
|
+
error=_thrown_exception(exception,args)
|
|
858
|
+
self._running=True
|
|
859
|
+
self._started=True
|
|
860
|
+
try: return self._iterator().throw(error)
|
|
861
|
+
except StopIteration: self._closed=True; raise
|
|
862
|
+
except BaseException: self._closed=True; raise
|
|
863
|
+
finally: self._running=False
|
|
864
|
+
def close(self):
|
|
865
|
+
if self._running: raise ValueError("coroutine already executing")
|
|
866
|
+
if self._closed: return None
|
|
867
|
+
self._closed=True
|
|
868
|
+
if self._driver is not None: return self._driver.close()
|
|
869
|
+
return None
|
|
870
|
+
async def wrapped(self):
|
|
871
|
+
try: return await self.execute()
|
|
872
|
+
except HythonReturn as signal: return signal.value
|
|
873
|
+
except BaseException as exc:
|
|
874
|
+
self.vm.restore_saved_names(self.local)
|
|
875
|
+
index=max(0,self.ip-1); line=self.code.lines[index] if self.code.lines and index<len(self.code.lines) else 0
|
|
876
|
+
frames=getattr(exc,"__hython_frames__",None)
|
|
877
|
+
if frames is None: frames=[]; setattr(exc,"__hython_frames__",frames)
|
|
878
|
+
frame=(self.code.name,line,index)
|
|
879
|
+
if not frames or frames[-1]!=frame:
|
|
880
|
+
frames.append(frame); exc.add_note(f"하이썬 위치: {self.code.name}:{line}" if line else f"하이썬 위치: {self.code.name}")
|
|
881
|
+
raise
|
|
882
|
+
async def _await(self,awaitable):
|
|
883
|
+
self._awaiting=awaitable
|
|
884
|
+
try: return await awaitable
|
|
885
|
+
finally: self._awaiting=None
|
|
886
|
+
async def execute(self):
|
|
887
|
+
stack=[]; ip=0; insns=self.code.instructions
|
|
888
|
+
binary={"ADD":operator.add,"SUB":operator.sub,"MUL":operator.mul,"DIV":operator.truediv,"FLOORDIV":operator.floordiv,"MOD":operator.mod,"POW":operator.pow,
|
|
889
|
+
"EQ":operator.eq,"NE":operator.ne,"LT":operator.lt,"LE":operator.le,"GT":operator.gt,"GE":operator.ge}
|
|
890
|
+
binary.update({"IN":lambda a,b:a in b,"IS":operator.is_,"NOT_IN":lambda a,b:a not in b,"IS_NOT":operator.is_not,
|
|
891
|
+
"BIT_OR":operator.or_,"BIT_XOR":operator.xor,"BIT_AND":operator.and_,"LSHIFT":operator.lshift,"RSHIFT":operator.rshift,"MATMUL":operator.matmul})
|
|
892
|
+
binary.update({"IADD":operator.iadd,"ISUB":operator.isub,"IMUL":operator.imul,"IDIV":operator.itruediv,"IFLOORDIV":operator.ifloordiv,"IMOD":operator.imod,"IPOW":operator.ipow,"IBIT_OR":operator.ior,"IBIT_XOR":operator.ixor,"IBIT_AND":operator.iand,"ILSHIFT":operator.ilshift,"IRSHIFT":operator.irshift,"IMATMUL":operator.imatmul})
|
|
893
|
+
while ip<len(insns):
|
|
894
|
+
self.ip=ip
|
|
895
|
+
ins=insns[ip]; op=ins[0]; arg=ins[1] if len(ins)>1 else None; ip+=1; self.ip=ip
|
|
896
|
+
if op=="CONST": stack.append(self.code.constants[arg])
|
|
897
|
+
elif op=="LOAD":
|
|
898
|
+
if arg in self.local: stack.append(self.local[arg])
|
|
899
|
+
elif arg in self.local.get("$local_names",()): raise UnboundLocalError(f"local variable '{arg}' referenced before assignment")
|
|
900
|
+
elif arg in self.local.get("$free_names",()):
|
|
901
|
+
closure=self.vm.nonlocal_scope(self.local,arg)
|
|
902
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
903
|
+
stack.append(closure[arg])
|
|
904
|
+
elif (found:=self.vm.lookup_closure(self.local,arg))[0]: stack.append(found[1])
|
|
905
|
+
elif arg in self.vm.globals: stack.append(self.vm.globals[arg])
|
|
906
|
+
else: raise NameError(f"name '{arg}' is not defined")
|
|
907
|
+
elif op=="STORE": self.local[arg]=stack.pop()
|
|
908
|
+
elif op=="SAVE_NAME": self.vm.save_name(self.local,arg)
|
|
909
|
+
elif op=="RESTORE_NAME": self.vm.restore_name(self.local,arg)
|
|
910
|
+
elif op=="ANNOTATE": self.local.setdefault("__annotations__",{})[arg]=stack.pop()
|
|
911
|
+
elif op=="ANNOTATE_LAZY": self.vm.register_annotation(self.local,arg)
|
|
912
|
+
elif op=="SUPER": stack.append(self.vm.zero_argument_super(self.local,arg))
|
|
913
|
+
elif op=="MAKE_TYPE_ALIAS": stack.append(self.vm.make_type_alias(arg,self.local))
|
|
914
|
+
elif op=="MAKE_TYPE_PARAMETER": stack.append(self.vm.make_type_parameter(arg,self.local))
|
|
915
|
+
elif op=="STORE_GLOBAL": self.vm.globals[arg]=stack.pop()
|
|
916
|
+
elif op=="STORE_NONLOCAL":
|
|
917
|
+
closure=self.vm.nonlocal_scope(self.local,arg); closure[arg]=stack.pop()
|
|
918
|
+
elif op=="UNPACK":
|
|
919
|
+
values=self.vm.unpack_exact(stack.pop(),arg)
|
|
920
|
+
stack.extend(reversed(values))
|
|
921
|
+
elif op=="UNPACK_EX":
|
|
922
|
+
before=arg>>16; after=arg&0xFFFF
|
|
923
|
+
stack.extend(reversed(self.vm.unpack_extended(stack.pop(),before,after)))
|
|
924
|
+
elif op=="DELETE":
|
|
925
|
+
if arg not in self.local: raise self.vm.missing_delete_error(self.local,arg)
|
|
926
|
+
del self.local[arg]
|
|
927
|
+
elif op=="DELETE_GLOBAL":
|
|
928
|
+
if arg not in self.vm.globals: raise NameError(f"name '{arg}' is not defined")
|
|
929
|
+
del self.vm.globals[arg]
|
|
930
|
+
elif op=="DELETE_NONLOCAL":
|
|
931
|
+
closure=self.vm.nonlocal_scope(self.local,arg)
|
|
932
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
933
|
+
del closure[arg]
|
|
934
|
+
elif op=="DELETE_ITEM": index=stack.pop(); del stack.pop()[index]
|
|
935
|
+
elif op=="DELETE_ATTR": delattr(stack.pop(),arg)
|
|
936
|
+
elif op=="POP": stack.pop()
|
|
937
|
+
elif op=="DUP": stack.append(stack[-1])
|
|
938
|
+
elif op=="DUP2": stack.extend(stack[-2:])
|
|
939
|
+
elif op in binary: b=stack.pop(); a=stack.pop(); stack.append(binary[op](a,b))
|
|
940
|
+
elif op in ("NEG","POS","NOT","INVERT"): stack.append({"NEG":operator.neg,"POS":operator.pos,"NOT":operator.not_,"INVERT":operator.invert}[op](stack.pop()))
|
|
941
|
+
elif op=="JUMP": ip=arg
|
|
942
|
+
elif op=="JUMP_FALSE":
|
|
943
|
+
if not stack.pop(): ip=arg
|
|
944
|
+
elif op=="JUMP_IF_FALSE_OR_POP":
|
|
945
|
+
if not stack[-1]: ip=arg
|
|
946
|
+
else: stack.pop()
|
|
947
|
+
elif op=="JUMP_IF_TRUE_OR_POP":
|
|
948
|
+
if stack[-1]: ip=arg
|
|
949
|
+
else: stack.pop()
|
|
950
|
+
elif op=="ITER": stack.append(iter(stack.pop()))
|
|
951
|
+
elif op=="FOR_ITER":
|
|
952
|
+
try: stack.append(next(stack[-1]))
|
|
953
|
+
except StopIteration: stack.pop(); ip=arg
|
|
954
|
+
elif op in ("BUILD_LIST","BUILD_TUPLE","BUILD_SET"):
|
|
955
|
+
values=stack[-arg:] if arg else []
|
|
956
|
+
if arg: del stack[-arg:]
|
|
957
|
+
stack.append(list(values) if op=="BUILD_LIST" else tuple(values) if op=="BUILD_TUPLE" else set(values))
|
|
958
|
+
elif op=="BUILD_DICT":
|
|
959
|
+
values=stack[-arg*2:] if arg else []
|
|
960
|
+
if arg: del stack[-arg*2:]
|
|
961
|
+
stack.append(dict(zip(values[::2],values[1::2])))
|
|
962
|
+
elif op=="BUILD_UNPACK":
|
|
963
|
+
count=len(arg["starred"]); values=stack[-count:] if count else []
|
|
964
|
+
if count: del stack[-count:]
|
|
965
|
+
merged=[]
|
|
966
|
+
for value,starred in zip(values,arg["starred"]): merged.extend(value) if starred else merged.append(value)
|
|
967
|
+
stack.append(tuple(merged) if arg["kind"]=="tuple" else set(merged) if arg["kind"]=="set" else merged)
|
|
968
|
+
elif op=="BUILD_DICT_UNPACK":
|
|
969
|
+
count=sum(2 if item=="pair" else 1 for item in arg); values=stack[-count:] if count else []
|
|
970
|
+
if count: del stack[-count:]
|
|
971
|
+
result={}; index=0
|
|
972
|
+
for item in arg:
|
|
973
|
+
if item=="pair": result[values[index]]=values[index+1]; index+=2
|
|
974
|
+
else: result.update(values[index]); index+=1
|
|
975
|
+
stack.append(result)
|
|
976
|
+
elif op=="COLLECTION_BEGIN": stack.append(self.vm.collection_builder(arg))
|
|
977
|
+
elif op=="COLLECTION_ADD":
|
|
978
|
+
value=stack.pop(); key=stack.pop() if arg=="pair" else None
|
|
979
|
+
self.vm.add_collection_item(stack[-1],arg,value,key)
|
|
980
|
+
elif op=="COLLECTION_READY": stack.append(self.vm.finish_collection(stack.pop()))
|
|
981
|
+
elif op=="BUILD_SLICE":
|
|
982
|
+
step=stack.pop(); stop=stack.pop(); start=stack.pop(); stack.append(slice(start,stop,step))
|
|
983
|
+
elif op=="GET_ITEM": index=stack.pop(); stack.append(stack.pop()[index])
|
|
984
|
+
elif op=="SET_ITEM": value=stack.pop(); index=stack.pop(); stack.pop()[index]=value
|
|
985
|
+
elif op=="GET_ATTR": stack.append(getattr(stack.pop(),arg))
|
|
986
|
+
elif op=="SET_ATTR":
|
|
987
|
+
value=stack.pop(); target=stack.pop(); setattr(target,arg,value)
|
|
988
|
+
elif op=="IMPORT": stack.append(self.vm.import_module(arg,self.code))
|
|
989
|
+
elif op=="IMPORT_FROM": stack.append(self.vm.import_from(arg["module"],arg["name"],self.code))
|
|
990
|
+
elif op=="IMPORT_STAR": self.vm.import_star(self.local,stack.pop())
|
|
991
|
+
elif op=="FORMAT": stack.append(str(stack.pop()))
|
|
992
|
+
elif op=="FORMAT_VALUE":
|
|
993
|
+
spec=stack.pop() if arg["has_spec"] else ""; value=stack.pop()
|
|
994
|
+
if arg["conversion"]=="r": value=repr(value)
|
|
995
|
+
elif arg["conversion"]=="s": value=str(value)
|
|
996
|
+
elif arg["conversion"]=="a": value=ascii(value)
|
|
997
|
+
stack.append(format(value,spec))
|
|
998
|
+
elif op=="BUILD_STRING":
|
|
999
|
+
values=stack[-arg:] if arg else []
|
|
1000
|
+
if arg: del stack[-arg:]
|
|
1001
|
+
stack.append("".join(values))
|
|
1002
|
+
elif op=="MAKE_INTERPOLATION":
|
|
1003
|
+
spec=stack.pop(); conversion=stack.pop(); expression=stack.pop(); value=stack.pop(); stack.append(Interpolation(value,expression,conversion,spec))
|
|
1004
|
+
elif op=="BUILD_TEMPLATE":
|
|
1005
|
+
values=stack[-arg:] if arg else []
|
|
1006
|
+
if arg: del stack[-arg:]
|
|
1007
|
+
stack.append(Template(*values))
|
|
1008
|
+
elif op=="ASSERT":
|
|
1009
|
+
message=stack.pop(); condition=stack.pop()
|
|
1010
|
+
if not condition: raise AssertionError(message) if message is not None else AssertionError()
|
|
1011
|
+
elif op=="MATCH_PATTERN":
|
|
1012
|
+
bindings={}; matched=self.vm.match_pattern(stack.pop(),arg,bindings,self.local)
|
|
1013
|
+
if matched: self.vm.apply_pattern_bindings(self.local,bindings)
|
|
1014
|
+
stack.append(matched)
|
|
1015
|
+
elif op=="CHAIN_COMPARE":
|
|
1016
|
+
operands=arg["operands"]; operators=arg["operators"]; left=await HythonCoroutine(self.vm,CodeObject.from_dict(operands[0]),self.local).execute(); result=True
|
|
1017
|
+
for index,(operator_name,payload) in enumerate(zip(operators,operands[1:])):
|
|
1018
|
+
right=await HythonCoroutine(self.vm,CodeObject.from_dict(payload),self.local).execute()
|
|
1019
|
+
result=self.vm.compare_values(operator_name,left,right)
|
|
1020
|
+
if index<len(operators)-1 and not result: break
|
|
1021
|
+
left=right
|
|
1022
|
+
stack.append(result)
|
|
1023
|
+
elif op=="CALL":
|
|
1024
|
+
args=stack[-arg:] if arg else []
|
|
1025
|
+
if arg: del stack[-arg:]
|
|
1026
|
+
stack.append(self.vm.call_value(stack.pop(),args,{},self.local))
|
|
1027
|
+
elif op=="CALL_EX":
|
|
1028
|
+
values=stack[-len(arg):] if arg else []
|
|
1029
|
+
if arg: del stack[-len(arg):]
|
|
1030
|
+
function=stack.pop(); positional,keywords=self.vm.expand_call_arguments(arg,values)
|
|
1031
|
+
stack.append(self.vm.call_value(function,positional,keywords,self.local))
|
|
1032
|
+
elif op=="CALL_BEGIN": stack.append(CallArguments([],{}))
|
|
1033
|
+
elif op=="CALL_ARG": self.vm.add_call_argument(stack[-2],arg,stack.pop())
|
|
1034
|
+
elif op=="CALL_READY":
|
|
1035
|
+
arguments=stack.pop(); function=stack.pop()
|
|
1036
|
+
stack.append(self.vm.call_value(function,arguments.positional,arguments.keywords,self.local))
|
|
1037
|
+
elif op=="CLASS_BEGIN": stack.append(CallArguments([],{}))
|
|
1038
|
+
elif op=="CLASS_ARG": self.vm.add_class_argument(stack[-2],arg,stack.pop())
|
|
1039
|
+
elif op=="MAKE_FUNCTION":
|
|
1040
|
+
stack.append(self.vm.create_function(arg,self.local,stack))
|
|
1041
|
+
elif op=="MAKE_CLASS":
|
|
1042
|
+
stack.append(self.vm.create_class(arg,self.local,stack))
|
|
1043
|
+
elif op=="AWAIT":
|
|
1044
|
+
awaitable=stack.pop(); self.vm.inherit_active_exception(awaitable,self.local); stack.append(await self._await(awaitable))
|
|
1045
|
+
elif op=="RAISE": raise stack.pop()
|
|
1046
|
+
elif op=="RAISE_FROM":
|
|
1047
|
+
cause=stack.pop(); error=stack.pop(); raise error from cause
|
|
1048
|
+
elif op=="RERAISE":
|
|
1049
|
+
self.vm.reraise(self.local)
|
|
1050
|
+
elif op=="TRY":
|
|
1051
|
+
control=None
|
|
1052
|
+
try:
|
|
1053
|
+
await HythonCoroutine(self.vm,CodeObject.from_dict(arg["body"]),self.local).execute()
|
|
1054
|
+
except (HythonBreak,HythonContinue) as signal: control=signal
|
|
1055
|
+
except HythonReturn:
|
|
1056
|
+
raise
|
|
1057
|
+
except BaseException as exc:
|
|
1058
|
+
if arg["handlers"] and arg["handlers"][0].get("star",False):
|
|
1059
|
+
original=exc if isinstance(exc,BaseExceptionGroup) else BaseExceptionGroup("",[exc]); remaining=original; raised=[]; reraised=[]
|
|
1060
|
+
for handler in arg["handlers"]:
|
|
1061
|
+
expected=self.vm.run(CodeObject.from_dict(handler["type"]),self.local)
|
|
1062
|
+
matched,remaining=remaining.split(expected)
|
|
1063
|
+
if matched is None: continue
|
|
1064
|
+
if handler["alias"]: self.vm.assign_name(self.local,handler["alias"],matched,handler.get("alias_scope","local"))
|
|
1065
|
+
previous=self.vm.push_active_exception(self.local,matched)
|
|
1066
|
+
try: await HythonCoroutine(self.vm,CodeObject.from_dict(handler["code"]),self.local).execute()
|
|
1067
|
+
except BaseException as failure:
|
|
1068
|
+
(reraised if failure is matched else raised).append(failure)
|
|
1069
|
+
finally:
|
|
1070
|
+
self.vm.pop_active_exception(self.local,previous)
|
|
1071
|
+
if handler["alias"]: self.vm.delete_name(self.local,handler["alias"],handler.get("alias_scope","local"))
|
|
1072
|
+
failure=_merge_except_star(original,reraised,raised,remaining)
|
|
1073
|
+
if failure is not None: raise failure
|
|
1074
|
+
continue
|
|
1075
|
+
handled=False
|
|
1076
|
+
for handler in arg["handlers"]:
|
|
1077
|
+
expected=self.vm.run(CodeObject.from_dict(handler["type"]),self.local) if handler["type"] else BaseException
|
|
1078
|
+
if isinstance(exc,expected):
|
|
1079
|
+
if handler["alias"]: self.vm.assign_name(self.local,handler["alias"],exc,handler.get("alias_scope","local"))
|
|
1080
|
+
previous=self.vm.push_active_exception(self.local,exc)
|
|
1081
|
+
try: await HythonCoroutine(self.vm,CodeObject.from_dict(handler["code"]),self.local).execute()
|
|
1082
|
+
finally:
|
|
1083
|
+
self.vm.pop_active_exception(self.local,previous)
|
|
1084
|
+
if handler["alias"]: self.vm.delete_name(self.local,handler["alias"],handler.get("alias_scope","local"))
|
|
1085
|
+
handled=True; break
|
|
1086
|
+
if not handled: raise
|
|
1087
|
+
else:
|
|
1088
|
+
if arg["else"]: await HythonCoroutine(self.vm,CodeObject.from_dict(arg["else"]),self.local).execute()
|
|
1089
|
+
finally:
|
|
1090
|
+
if arg["finally"]:
|
|
1091
|
+
active=sys.exception(); previous=_MISSING; pushed=False
|
|
1092
|
+
if active is not None and not isinstance(active,(HythonReturn,HythonBreak,HythonContinue)):
|
|
1093
|
+
previous=self.vm.push_active_exception(self.local,active); pushed=True
|
|
1094
|
+
try: await HythonCoroutine(self.vm,CodeObject.from_dict(arg["finally"]),self.local).execute()
|
|
1095
|
+
finally:
|
|
1096
|
+
if pushed: self.vm.pop_active_exception(self.local,previous)
|
|
1097
|
+
if isinstance(control,HythonBreak): ip=arg["break_target"]
|
|
1098
|
+
elif isinstance(control,HythonContinue): ip=arg["continue_target"]
|
|
1099
|
+
elif op=="WITH":
|
|
1100
|
+
exits=[]; failure=None
|
|
1101
|
+
try:
|
|
1102
|
+
for manager in arg["managers"]:
|
|
1103
|
+
context=self.vm.run(CodeObject.from_dict(manager["code"]),self.local)
|
|
1104
|
+
enter_method,exit_method=self.vm.context_methods(context,False)
|
|
1105
|
+
entered=enter_method(); exits.append(exit_method)
|
|
1106
|
+
if manager["alias"]: self.vm.assign_target(self.local,manager["alias"],entered)
|
|
1107
|
+
await HythonCoroutine(self.vm,CodeObject.from_dict(arg["body"]),self.local).execute()
|
|
1108
|
+
except BaseException as caught:
|
|
1109
|
+
failure=caught
|
|
1110
|
+
try: self.vm.unwind_exits(exits,failure)
|
|
1111
|
+
except HythonBreak: ip=arg["break_target"]
|
|
1112
|
+
except HythonContinue: ip=arg["continue_target"]
|
|
1113
|
+
elif op=="COMPREHENSION":
|
|
1114
|
+
if arg.get("async",any(clause.get("async",False) for clause in arg["clauses"])):
|
|
1115
|
+
if arg["kind"]=="generatorexpr": stack.append(await self.vm.prepare_async_generator_expression(arg,self.local,self._await))
|
|
1116
|
+
else: stack.append(await self.vm.run_async_comprehension(arg,self.local,self._await))
|
|
1117
|
+
continue
|
|
1118
|
+
if arg["kind"]=="generatorexpr": stack.append(self.vm.generator_expression(arg,self.local)); continue
|
|
1119
|
+
scope=ComprehensionScope(self.vm.comprehension_parent(self.local),arg.get("bindings",())); result={} if arg["kind"]=="dictcomp" else set() if arg["kind"]=="setcomp" else []
|
|
1120
|
+
def collect(index):
|
|
1121
|
+
if index<len(arg["clauses"]):
|
|
1122
|
+
clause=arg["clauses"][index]
|
|
1123
|
+
for item in self.vm.run(CodeObject.from_dict(clause["iter"]),scope):
|
|
1124
|
+
self.vm.assign_target(scope,clause["target"],item)
|
|
1125
|
+
if all(self.vm.run(CodeObject.from_dict(test),scope) for test in clause["filters"]): collect(index+1)
|
|
1126
|
+
return
|
|
1127
|
+
if arg["kind"]=="dictcomp": result[self.vm.run(CodeObject.from_dict(arg["key"]),scope)]=self.vm.run(CodeObject.from_dict(arg["value"]),scope)
|
|
1128
|
+
else:
|
|
1129
|
+
value=self.vm.run(CodeObject.from_dict(arg["element"]),scope)
|
|
1130
|
+
result.add(value) if arg["kind"]=="setcomp" else result.append(value)
|
|
1131
|
+
collect(0); self.vm.commit_comprehension_bindings(arg,scope,self.local); stack.append(result)
|
|
1132
|
+
elif op=="ASYNC_FOR":
|
|
1133
|
+
iterable=self.vm.run(CodeObject.from_dict(arg["iter"]),self.local)
|
|
1134
|
+
iterator=builtins.aiter(iterable)
|
|
1135
|
+
broken=False
|
|
1136
|
+
while True:
|
|
1137
|
+
try: item=await self._await(builtins.anext(iterator))
|
|
1138
|
+
except StopAsyncIteration: break
|
|
1139
|
+
self.vm.assign_target(self.local,arg["target"],item)
|
|
1140
|
+
try: await HythonCoroutine(self.vm,CodeObject.from_dict(arg["body"]),self.local).execute()
|
|
1141
|
+
except HythonContinue: continue
|
|
1142
|
+
except HythonBreak: broken=True; break
|
|
1143
|
+
if not broken and arg.get("else"): await HythonCoroutine(self.vm,CodeObject.from_dict(arg["else"]),self.local).execute()
|
|
1144
|
+
elif op=="ASYNC_WITH":
|
|
1145
|
+
exits=[]; failure=None
|
|
1146
|
+
try:
|
|
1147
|
+
for manager in arg["managers"]:
|
|
1148
|
+
context=self.vm.run(CodeObject.from_dict(manager["code"]),self.local)
|
|
1149
|
+
enter_method,exit_method=self.vm.context_methods(context,True)
|
|
1150
|
+
entered=await self._await(enter_method())
|
|
1151
|
+
exits.append(exit_method)
|
|
1152
|
+
if manager["alias"]: self.vm.assign_target(self.local,manager["alias"],entered)
|
|
1153
|
+
await HythonCoroutine(self.vm,CodeObject.from_dict(arg["body"]),self.local).execute()
|
|
1154
|
+
except BaseException as caught:
|
|
1155
|
+
failure=caught
|
|
1156
|
+
try: await self.vm.unwind_async_exits(exits,failure,self._await)
|
|
1157
|
+
except HythonBreak: ip=arg["break_target"]
|
|
1158
|
+
except HythonContinue: ip=arg["continue_target"]
|
|
1159
|
+
elif op=="RETURN": return stack.pop()
|
|
1160
|
+
elif op=="SIGNAL_RETURN": raise HythonReturn(stack.pop())
|
|
1161
|
+
elif op=="SIGNAL_BREAK": raise HythonBreak()
|
|
1162
|
+
elif op=="SIGNAL_CONTINUE": raise HythonContinue()
|
|
1163
|
+
elif op=="NOP": pass
|
|
1164
|
+
else: raise VMError(f"코루틴에서 아직 지원하지 않는 HBC 명령어: {op}")
|
|
1165
|
+
return None
|
|
1166
|
+
|
|
1167
|
+
class HythonAsyncGenerator:
|
|
1168
|
+
"""Asynchronous iterator facade over a resumable HBC generator frame."""
|
|
1169
|
+
def __init__(self,generator): self.generator=generator; self.async_delegate=None; self._awaiting=None; self._running=False; self._closed=False
|
|
1170
|
+
@property
|
|
1171
|
+
def ag_code(self): return self.generator.code
|
|
1172
|
+
@property
|
|
1173
|
+
def ag_frame(self): return self.generator.gi_frame
|
|
1174
|
+
@property
|
|
1175
|
+
def ag_running(self): return self._running or self.generator.gi_running
|
|
1176
|
+
@property
|
|
1177
|
+
def ag_suspended(self): return self.generator.gi_suspended and not self.ag_running and not self._closed
|
|
1178
|
+
@property
|
|
1179
|
+
def ag_await(self): return self._awaiting if self._awaiting is not None else self.async_delegate
|
|
1180
|
+
def __getattribute__(self,name):
|
|
1181
|
+
if name in ("__name__","__qualname__"): return getattr(object.__getattribute__(self,"generator"),name)
|
|
1182
|
+
return object.__getattribute__(self,name)
|
|
1183
|
+
def __aiter__(self): return self
|
|
1184
|
+
async def _await(self,awaitable):
|
|
1185
|
+
self._awaiting=awaitable
|
|
1186
|
+
try: return await awaitable
|
|
1187
|
+
finally: self._awaiting=None
|
|
1188
|
+
async def _drive(self,value=None):
|
|
1189
|
+
while True:
|
|
1190
|
+
if self.async_delegate is not None:
|
|
1191
|
+
try: return await (builtins.anext(self.async_delegate) if value is None else self.async_delegate.asend(value))
|
|
1192
|
+
except StopAsyncIteration: self.async_delegate=None; value=None; continue
|
|
1193
|
+
try: return self.generator.send(value)
|
|
1194
|
+
except HythonAwait as signal:
|
|
1195
|
+
value=await self._await(signal.awaitable)
|
|
1196
|
+
except HythonAsyncDelegate as signal:
|
|
1197
|
+
self.async_delegate=builtins.aiter(signal.iterator); value=None
|
|
1198
|
+
except StopIteration: raise _AsyncGeneratorReturn from None
|
|
1199
|
+
async def __anext__(self):
|
|
1200
|
+
if self._closed: raise StopAsyncIteration
|
|
1201
|
+
if self._running: raise RuntimeError("anext(): asynchronous generator is already running")
|
|
1202
|
+
self._running=True
|
|
1203
|
+
try: return await self._drive(None)
|
|
1204
|
+
except _AsyncGeneratorReturn: raise StopAsyncIteration from None
|
|
1205
|
+
except StopAsyncIteration as exc: raise RuntimeError("async generator raised StopAsyncIteration") from exc
|
|
1206
|
+
finally: self._running=False
|
|
1207
|
+
async def asend(self,value):
|
|
1208
|
+
if self._closed: raise StopAsyncIteration
|
|
1209
|
+
if self._running: raise RuntimeError("anext(): asynchronous generator is already running")
|
|
1210
|
+
self._running=True
|
|
1211
|
+
try: return await self._drive(value)
|
|
1212
|
+
except _AsyncGeneratorReturn: raise StopAsyncIteration from None
|
|
1213
|
+
except StopAsyncIteration as exc: raise RuntimeError("async generator raised StopAsyncIteration") from exc
|
|
1214
|
+
finally: self._running=False
|
|
1215
|
+
async def aclose(self):
|
|
1216
|
+
if self._closed: return None
|
|
1217
|
+
try:
|
|
1218
|
+
yielded=await self.athrow(GeneratorExit)
|
|
1219
|
+
except (GeneratorExit,StopAsyncIteration):
|
|
1220
|
+
self._closed=True; return None
|
|
1221
|
+
self._closed=True
|
|
1222
|
+
raise RuntimeError("비동기 제너레이터가 GeneratorExit를 무시했습니다.")
|
|
1223
|
+
async def athrow(self,exception,*args):
|
|
1224
|
+
if self._closed: raise StopAsyncIteration
|
|
1225
|
+
if self._running: raise RuntimeError("athrow(): asynchronous generator is already running")
|
|
1226
|
+
self._running=True
|
|
1227
|
+
try:
|
|
1228
|
+
if self.async_delegate is not None:
|
|
1229
|
+
try: return await self.async_delegate.athrow(exception,*args)
|
|
1230
|
+
except StopAsyncIteration: self.async_delegate=None; return await self._drive(None)
|
|
1231
|
+
try:
|
|
1232
|
+
value=self.generator.throw(exception,*args)
|
|
1233
|
+
return value
|
|
1234
|
+
except HythonAwait as signal:
|
|
1235
|
+
return await self._drive(await self._await(signal.awaitable))
|
|
1236
|
+
except StopIteration: raise _AsyncGeneratorReturn from None
|
|
1237
|
+
except StopAsyncIteration as exc: raise RuntimeError("async generator raised StopAsyncIteration") from exc
|
|
1238
|
+
except _AsyncGeneratorReturn: raise StopAsyncIteration from None
|
|
1239
|
+
finally: self._running=False
|
|
1240
|
+
|
|
1241
|
+
class VM:
|
|
1242
|
+
def __init__(self, module_paths: list[Path] | None = None, modules: dict | None = None,
|
|
1243
|
+
module_files: dict | None = None):
|
|
1244
|
+
self.globals = {name:value for name,value in vars(builtins).items() if not name.startswith("_")}
|
|
1245
|
+
self.globals["asyncio_run"]=asyncio.run
|
|
1246
|
+
self.globals["__name__"]="__main__"
|
|
1247
|
+
self.module_paths = module_paths or [Path.cwd()]
|
|
1248
|
+
self.modules = modules if modules is not None else {}
|
|
1249
|
+
self.module_files = module_files if module_files is not None else {}
|
|
1250
|
+
self._last_instruction = {}
|
|
1251
|
+
|
|
1252
|
+
@staticmethod
|
|
1253
|
+
def save_name(scope,name):
|
|
1254
|
+
scope.setdefault("$saved_names",{}).setdefault(name,[]).append((name in scope,scope.get(name)))
|
|
1255
|
+
|
|
1256
|
+
@staticmethod
|
|
1257
|
+
def restore_name(scope,name):
|
|
1258
|
+
saved=scope["$saved_names"]; existed,value=saved[name].pop()
|
|
1259
|
+
if existed: scope[name]=value
|
|
1260
|
+
else: scope.pop(name,None)
|
|
1261
|
+
if not saved[name]: del saved[name]
|
|
1262
|
+
if not saved: del scope["$saved_names"]
|
|
1263
|
+
|
|
1264
|
+
@classmethod
|
|
1265
|
+
def restore_saved_names(cls,scope):
|
|
1266
|
+
saved=scope.get("$saved_names",{})
|
|
1267
|
+
for name in list(saved):
|
|
1268
|
+
while name in saved: cls.restore_name(scope,name)
|
|
1269
|
+
scope.pop("$type_parameter_scope",None)
|
|
1270
|
+
|
|
1271
|
+
@staticmethod
|
|
1272
|
+
def push_active_exception(scope,exception):
|
|
1273
|
+
previous=scope.get("$active_exception",_MISSING)
|
|
1274
|
+
scope["$active_exception"]=exception
|
|
1275
|
+
return previous
|
|
1276
|
+
|
|
1277
|
+
@staticmethod
|
|
1278
|
+
def pop_active_exception(scope,previous):
|
|
1279
|
+
if previous is _MISSING: scope.pop("$active_exception",None)
|
|
1280
|
+
else: scope["$active_exception"]=previous
|
|
1281
|
+
|
|
1282
|
+
@staticmethod
|
|
1283
|
+
def reraise(scope):
|
|
1284
|
+
exception=scope.get("$active_exception",_MISSING)
|
|
1285
|
+
if exception is _MISSING: raise RuntimeError("No active exception to reraise")
|
|
1286
|
+
if sys.exception() is exception: raise
|
|
1287
|
+
raise exception
|
|
1288
|
+
|
|
1289
|
+
@staticmethod
|
|
1290
|
+
def inherit_active_exception(awaitable,scope):
|
|
1291
|
+
if "$active_exception" not in scope: return
|
|
1292
|
+
target=awaitable.generator if isinstance(awaitable,HythonAsyncGenerator) else awaitable
|
|
1293
|
+
if isinstance(target,(HythonCoroutine,HythonGenerator)) and "$active_exception" not in target.local:
|
|
1294
|
+
target.local["$active_exception"]=scope["$active_exception"]
|
|
1295
|
+
target.local["$inherited_active_exception"]=scope["$active_exception"]
|
|
1296
|
+
|
|
1297
|
+
@staticmethod
|
|
1298
|
+
def zero_argument_super(scope,parameter):
|
|
1299
|
+
if not parameter: raise RuntimeError("super(): no arguments")
|
|
1300
|
+
if not scope.get("$has_class_cell",False): raise RuntimeError("super(): __class__ cell not found")
|
|
1301
|
+
if parameter not in scope: raise RuntimeError("super(): arg[0] deleted")
|
|
1302
|
+
return super(scope["__class__"],scope[parameter])
|
|
1303
|
+
|
|
1304
|
+
@staticmethod
|
|
1305
|
+
def unwind_exits(exits,active=None):
|
|
1306
|
+
control=active if isinstance(active,(HythonReturn,HythonBreak,HythonContinue)) else None
|
|
1307
|
+
pending=None if control is not None else active
|
|
1308
|
+
for exit_method in reversed(exits):
|
|
1309
|
+
previous=pending
|
|
1310
|
+
try:
|
|
1311
|
+
suppressed=exit_method(type(pending),pending,pending.__traceback__) if pending is not None else exit_method(None,None,None)
|
|
1312
|
+
if pending is not None and suppressed: pending=None
|
|
1313
|
+
except BaseException as failure:
|
|
1314
|
+
if failure is not previous: failure.__context__=previous
|
|
1315
|
+
pending=failure; control=None
|
|
1316
|
+
if pending is not None: raise pending
|
|
1317
|
+
if control is not None: raise control
|
|
1318
|
+
|
|
1319
|
+
@staticmethod
|
|
1320
|
+
def lookup_special(value,name):
|
|
1321
|
+
value_type=type(value)
|
|
1322
|
+
for owner in value_type.__mro__:
|
|
1323
|
+
if name not in owner.__dict__: continue
|
|
1324
|
+
descriptor=owner.__dict__[name]
|
|
1325
|
+
getter=getattr(type(descriptor),"__get__",None)
|
|
1326
|
+
return getter(descriptor,value,value_type) if getter is not None else descriptor
|
|
1327
|
+
raise AttributeError(f"'{value_type.__name__}' object has no attribute '{name}'")
|
|
1328
|
+
|
|
1329
|
+
@classmethod
|
|
1330
|
+
def context_methods(cls,context,is_async):
|
|
1331
|
+
enter_name="__aenter__" if is_async else "__enter__"
|
|
1332
|
+
exit_name="__aexit__" if is_async else "__exit__"
|
|
1333
|
+
try: enter_method=cls.lookup_special(context,enter_name)
|
|
1334
|
+
except AttributeError as exc:
|
|
1335
|
+
protocol="asynchronous context manager" if is_async else "context manager"
|
|
1336
|
+
raise TypeError(f"'{type(context).__name__}' object does not support the {protocol} protocol") from exc
|
|
1337
|
+
try: exit_method=cls.lookup_special(context,exit_name)
|
|
1338
|
+
except AttributeError as exc:
|
|
1339
|
+
protocol="asynchronous context manager" if is_async else "context manager"
|
|
1340
|
+
raise TypeError(f"'{type(context).__name__}' object does not support the {protocol} protocol (missed {exit_name} method)") from exc
|
|
1341
|
+
return enter_method,exit_method
|
|
1342
|
+
|
|
1343
|
+
@staticmethod
|
|
1344
|
+
async def unwind_async_exits(exits,active=None,waiter=None):
|
|
1345
|
+
control=active if isinstance(active,(HythonReturn,HythonBreak,HythonContinue)) else None
|
|
1346
|
+
pending=None if control is not None else active
|
|
1347
|
+
for exit_method in reversed(exits):
|
|
1348
|
+
previous=pending
|
|
1349
|
+
try:
|
|
1350
|
+
awaitable=exit_method(type(pending),pending,pending.__traceback__) if pending is not None else exit_method(None,None,None)
|
|
1351
|
+
suppressed=await (waiter(awaitable) if waiter is not None else awaitable)
|
|
1352
|
+
if pending is not None and suppressed: pending=None
|
|
1353
|
+
except BaseException as failure:
|
|
1354
|
+
if failure is not previous: failure.__context__=previous
|
|
1355
|
+
pending=failure; control=None
|
|
1356
|
+
if pending is not None: raise pending
|
|
1357
|
+
if control is not None: raise control
|
|
1358
|
+
|
|
1359
|
+
def import_module(self, name: str, parent_code: CodeObject):
|
|
1360
|
+
source_path=Path(parent_code.name)
|
|
1361
|
+
relative=name.startswith("."); clean=name.lstrip("."); depth=len(name)-len(clean)
|
|
1362
|
+
if relative:
|
|
1363
|
+
package=self.parent_package(source_path)
|
|
1364
|
+
if not package: raise ImportError("attempted relative import with no known parent package")
|
|
1365
|
+
parts=package.split(".")
|
|
1366
|
+
if depth>len(parts): raise ImportError("attempted relative import beyond top-level package")
|
|
1367
|
+
base=parts[:len(parts)-depth+1]
|
|
1368
|
+
name=".".join([*base,*([clean] if clean else [])]); clean=name; relative=False
|
|
1369
|
+
if name in self.modules:
|
|
1370
|
+
module = self.modules[name]
|
|
1371
|
+
if module is None: raise VMError(f"순환 모듈 import: {name}")
|
|
1372
|
+
return module
|
|
1373
|
+
if not clean: raise VMError(f"모듈 이름이 필요합니다: {name}")
|
|
1374
|
+
parent=None
|
|
1375
|
+
if "." in clean:
|
|
1376
|
+
parent_name=clean.rsplit(".",1)[0]
|
|
1377
|
+
parent=self.import_module(parent_name,parent_code)
|
|
1378
|
+
module_path=Path(*clean.split(".")); roots=[source_path.parent]
|
|
1379
|
+
if relative:
|
|
1380
|
+
for _ in range(max(0,depth-1)): roots=[root.parent for root in roots]
|
|
1381
|
+
else: roots.extend(self.module_paths)
|
|
1382
|
+
candidates=[]
|
|
1383
|
+
for root in roots: candidates.extend((root/module_path.with_suffix(".hbc"),root/module_path/"__init__.hbc"))
|
|
1384
|
+
path=next((candidate for candidate in candidates if candidate.is_file()),None)
|
|
1385
|
+
if path is None:
|
|
1386
|
+
namespace_path=next((root/module_path for root in roots if (root/module_path).is_dir()),None)
|
|
1387
|
+
native_namespace=namespace_path is not None and any(namespace_path.rglob("*.hbc"))
|
|
1388
|
+
if not relative and not native_namespace:
|
|
1389
|
+
try: module=importlib.import_module(clean)
|
|
1390
|
+
except ModuleNotFoundError as exc:
|
|
1391
|
+
if exc.name not in (clean,clean.split(".")[0]): raise
|
|
1392
|
+
else:
|
|
1393
|
+
self.modules[name]=module
|
|
1394
|
+
return module
|
|
1395
|
+
if namespace_path is None or not native_namespace: raise ModuleNotFoundError(f"HBC 또는 Python 모듈을 찾을 수 없습니다: {name}",name=name)
|
|
1396
|
+
cache_key=str(namespace_path.resolve())
|
|
1397
|
+
module=self.module_files.get(cache_key)
|
|
1398
|
+
if module is None:
|
|
1399
|
+
spec=importlib.machinery.ModuleSpec(clean,loader=None,is_package=True)
|
|
1400
|
+
spec.submodule_search_locations=[str(namespace_path.resolve())]
|
|
1401
|
+
module=HythonModule(clean,__package__=clean,__file__=None,__loader__=None,
|
|
1402
|
+
__spec__=spec,__cached__=None,__path__=[str(namespace_path.resolve())])
|
|
1403
|
+
self.module_files[cache_key]=module
|
|
1404
|
+
self.modules[name]=module
|
|
1405
|
+
return module
|
|
1406
|
+
cache_key=str(path.resolve())
|
|
1407
|
+
if cache_key in self.module_files:
|
|
1408
|
+
module=self.module_files[cache_key]
|
|
1409
|
+
if module is None: raise VMError(f"순환 모듈 import: {name}")
|
|
1410
|
+
self.modules[name]=module
|
|
1411
|
+
return module
|
|
1412
|
+
child=VM([path.parent,*self.module_paths],self.modules,self.module_files)
|
|
1413
|
+
initial=dict(child.globals)
|
|
1414
|
+
module_name=clean
|
|
1415
|
+
is_package=path.name=="__init__.hbc"
|
|
1416
|
+
spec=importlib.machinery.ModuleSpec(module_name,loader=None,origin=str(path.resolve()),is_package=is_package)
|
|
1417
|
+
if is_package: spec.submodule_search_locations=[str(path.parent.resolve())]
|
|
1418
|
+
child.globals.update({
|
|
1419
|
+
"__name__":module_name,
|
|
1420
|
+
"__file__":str(path.resolve()),
|
|
1421
|
+
"__package__":module_name if is_package else module_name.rpartition(".")[0],
|
|
1422
|
+
"__loader__":None,"__spec__":spec,"__cached__":str(path.resolve()),
|
|
1423
|
+
})
|
|
1424
|
+
module=HythonModule(__name__=module_name,__file__=str(path.resolve()),
|
|
1425
|
+
__package__=module_name if is_package else module_name.rpartition(".")[0],
|
|
1426
|
+
__loader__=None,__spec__=spec,__cached__=str(path.resolve()),
|
|
1427
|
+
**({"__path__":[str(path.parent.resolve())]} if is_package else {}),
|
|
1428
|
+
_hython_scope=child.globals)
|
|
1429
|
+
self.modules[name]=module; self.module_files[cache_key]=module
|
|
1430
|
+
try:
|
|
1431
|
+
child.run(read_hbc(path))
|
|
1432
|
+
except BaseException:
|
|
1433
|
+
self.modules.pop(name,None); self.module_files.pop(cache_key,None)
|
|
1434
|
+
raise
|
|
1435
|
+
namespace={key:value for key,value in child.globals.items()
|
|
1436
|
+
if key not in initial or value is not initial[key]}
|
|
1437
|
+
vars(module).update(namespace); vars(module).pop("_hython_scope",None)
|
|
1438
|
+
module_annotations=vars(module).get("__annotations__")
|
|
1439
|
+
if isinstance(module_annotations,LazyAnnotations): module_annotations.owner=module; module_annotations.scope=vars(module)
|
|
1440
|
+
if "." in clean:
|
|
1441
|
+
_,attribute=clean.rsplit(".",1)
|
|
1442
|
+
setattr(parent,attribute,module)
|
|
1443
|
+
return module
|
|
1444
|
+
|
|
1445
|
+
def parent_package(self,source_path:Path):
|
|
1446
|
+
source=source_path.resolve()
|
|
1447
|
+
for module in self.modules.values():
|
|
1448
|
+
filename=getattr(module,"__file__",None) if module is not None else None
|
|
1449
|
+
if not filename: continue
|
|
1450
|
+
loaded=Path(filename).resolve()
|
|
1451
|
+
if loaded.parent==source.parent and (loaded.stem==source.stem or loaded.name=="__init__.hbc"):
|
|
1452
|
+
return getattr(module,"__package__","")
|
|
1453
|
+
for root in self.module_paths:
|
|
1454
|
+
try: relative=source.parent.relative_to(Path(root).resolve())
|
|
1455
|
+
except ValueError: continue
|
|
1456
|
+
if relative.parts: return ".".join(relative.parts)
|
|
1457
|
+
return ""
|
|
1458
|
+
|
|
1459
|
+
def register_annotation(self,scope,arg):
|
|
1460
|
+
annotations=scope.get("__annotations__")
|
|
1461
|
+
if not isinstance(annotations,LazyAnnotations):
|
|
1462
|
+
annotations=LazyAnnotations(self,scope,annotations if isinstance(annotations,dict) else None)
|
|
1463
|
+
scope["__annotations__"]=annotations
|
|
1464
|
+
scope["__annotate__"]=staticmethod(annotations.evaluate) if "$class_outer" in scope else annotations.evaluate
|
|
1465
|
+
annotations.add(arg["name"],arg["code"],arg.get("text",""))
|
|
1466
|
+
|
|
1467
|
+
@staticmethod
|
|
1468
|
+
def import_star(scope: dict, module) -> None:
|
|
1469
|
+
namespace=vars(module)
|
|
1470
|
+
names=getattr(module,"__all__",None)
|
|
1471
|
+
if names is None: names=[name for name in namespace if not name.startswith("_")]
|
|
1472
|
+
for name in names:
|
|
1473
|
+
if not isinstance(name,str): raise TypeError("__all__의 항목은 문자열이어야 합니다.")
|
|
1474
|
+
scope[name]=getattr(module,name)
|
|
1475
|
+
|
|
1476
|
+
def import_from(self,module_name:str,name:str,parent_code:CodeObject):
|
|
1477
|
+
if not module_name.lstrip("."):
|
|
1478
|
+
return self.import_module(f"{module_name}{name}",parent_code)
|
|
1479
|
+
module=self.import_module(module_name,parent_code)
|
|
1480
|
+
try: return getattr(module,name)
|
|
1481
|
+
except AttributeError:
|
|
1482
|
+
separator="" if module_name.endswith(".") else "."
|
|
1483
|
+
try: return self.import_module(f"{module_name}{separator}{name}",parent_code)
|
|
1484
|
+
except ModuleNotFoundError as exc:
|
|
1485
|
+
raise ImportError(f"{module_name}에서 {name} 이름을 가져올 수 없습니다.") from exc
|
|
1486
|
+
|
|
1487
|
+
def bind(self,function:Function,args,kwargs):
|
|
1488
|
+
signature=function.signature or {"positional":function.code.parameters,"positional_only":[],"keyword_only":[],"vararg":None,"kwarg":None}
|
|
1489
|
+
positional=signature["positional"]; keyword_only=signature["keyword_only"]
|
|
1490
|
+
if len(args)>len(positional) and not signature["vararg"]: raise TypeError(f"{function.code.name}: 위치 인자가 너무 많습니다.")
|
|
1491
|
+
bound=dict(zip(positional,args)); defaults=function.defaults or {}; extras={}
|
|
1492
|
+
if signature["vararg"]: bound[signature["vararg"]]=tuple(args[len(positional):])
|
|
1493
|
+
for name,value in kwargs.items():
|
|
1494
|
+
if name in signature.get("positional_only",[]):
|
|
1495
|
+
if signature["kwarg"]: extras[name]=value; continue
|
|
1496
|
+
raise TypeError(f"{function.code.name}: 위치 전용 인자 '{name}'은 키워드로 전달할 수 없습니다.")
|
|
1497
|
+
if name not in positional and name not in keyword_only:
|
|
1498
|
+
if signature["kwarg"]: extras[name]=value; continue
|
|
1499
|
+
raise TypeError(f"{function.code.name}: 알 수 없는 키워드 인자 '{name}'")
|
|
1500
|
+
if name in bound: raise TypeError(f"{function.code.name}: 인자 '{name}'이 중복되었습니다.")
|
|
1501
|
+
bound[name]=value
|
|
1502
|
+
missing=[name for name in [*positional,*keyword_only] if name not in bound and name not in defaults]
|
|
1503
|
+
if missing: raise TypeError(f"{function.code.name}: 필수 인자 누락: {', '.join(missing)}")
|
|
1504
|
+
for name in [*positional,*keyword_only]:
|
|
1505
|
+
if name not in bound: bound[name]=defaults[name]
|
|
1506
|
+
if signature["kwarg"]: bound[signature["kwarg"]]=extras
|
|
1507
|
+
return bound
|
|
1508
|
+
|
|
1509
|
+
@staticmethod
|
|
1510
|
+
def expand_call_arguments(descriptors,values):
|
|
1511
|
+
positional=[]; keywords={}
|
|
1512
|
+
for descriptor,item in zip(descriptors,values):
|
|
1513
|
+
if descriptor[0]=="positional": positional.append(item)
|
|
1514
|
+
elif descriptor[0]=="star": positional.extend(item)
|
|
1515
|
+
elif descriptor[0]=="kwstar":
|
|
1516
|
+
try: names=item.keys()
|
|
1517
|
+
except AttributeError: raise TypeError("** 뒤의 인자는 매핑이어야 합니다.") from None
|
|
1518
|
+
for name in names:
|
|
1519
|
+
if name in keywords: raise TypeError(f"키워드 인자 중복: {name}")
|
|
1520
|
+
keywords[name]=item[name]
|
|
1521
|
+
else:
|
|
1522
|
+
name=descriptor[1]
|
|
1523
|
+
if name in keywords: raise TypeError(f"키워드 인자 중복: {name}")
|
|
1524
|
+
keywords[name]=item
|
|
1525
|
+
return positional,keywords
|
|
1526
|
+
|
|
1527
|
+
@staticmethod
|
|
1528
|
+
def add_call_argument(arguments,descriptor,value):
|
|
1529
|
+
kind,name=descriptor
|
|
1530
|
+
if kind=="positional": arguments.positional.append(value); return
|
|
1531
|
+
if kind=="star":
|
|
1532
|
+
try: iterator=iter(value)
|
|
1533
|
+
except TypeError: raise TypeError(f"argument after * must be an iterable, not {type(value).__name__}") from None
|
|
1534
|
+
arguments.positional.extend(iterator)
|
|
1535
|
+
return
|
|
1536
|
+
if kind=="keyword":
|
|
1537
|
+
if name in arguments.keywords: raise TypeError(f"키워드 인자 중복: {name}")
|
|
1538
|
+
arguments.keywords[name]=value; return
|
|
1539
|
+
try: names=value.keys()
|
|
1540
|
+
except AttributeError: raise TypeError(f"argument after ** must be a mapping, not {type(value).__name__}") from None
|
|
1541
|
+
for key in names:
|
|
1542
|
+
if key in arguments.keywords: raise TypeError(f"키워드 인자 중복: {key}")
|
|
1543
|
+
arguments.keywords[key]=value[key]
|
|
1544
|
+
|
|
1545
|
+
@staticmethod
|
|
1546
|
+
def add_class_argument(arguments,descriptor,value):
|
|
1547
|
+
kind,name=descriptor
|
|
1548
|
+
if kind!="kwstar":
|
|
1549
|
+
VM.add_call_argument(arguments,["positional" if kind=="base" else kind,name],value); return
|
|
1550
|
+
try: names=value.keys()
|
|
1551
|
+
except AttributeError: raise TypeError(f"argument after ** must be a mapping, not {type(value).__name__}") from None
|
|
1552
|
+
for key in names:
|
|
1553
|
+
if not isinstance(key,str): raise TypeError("keywords must be strings")
|
|
1554
|
+
if key in arguments.keywords: raise TypeError(f"클래스 키워드 인자 중복: {key}")
|
|
1555
|
+
arguments.keywords[key]=value[key]
|
|
1556
|
+
|
|
1557
|
+
@staticmethod
|
|
1558
|
+
def collection_builder(kind):
|
|
1559
|
+
return CollectionBuilder(kind,{} if kind=="dict" else set() if kind=="set" else [])
|
|
1560
|
+
|
|
1561
|
+
@staticmethod
|
|
1562
|
+
def add_collection_item(builder,kind,value,key=None):
|
|
1563
|
+
if kind=="pair": builder.value[key]=value; return
|
|
1564
|
+
if kind=="unpack":
|
|
1565
|
+
try: keys=value.keys()
|
|
1566
|
+
except AttributeError: raise TypeError(f"'{type(value).__name__}' object is not a mapping") from None
|
|
1567
|
+
for item in keys: builder.value[item]=value[item]
|
|
1568
|
+
return
|
|
1569
|
+
if builder.kind=="set":
|
|
1570
|
+
if kind=="star": builder.value.update(value)
|
|
1571
|
+
else: builder.value.add(value)
|
|
1572
|
+
elif kind=="star": builder.value.extend(value)
|
|
1573
|
+
else: builder.value.append(value)
|
|
1574
|
+
|
|
1575
|
+
@staticmethod
|
|
1576
|
+
def finish_collection(builder):
|
|
1577
|
+
return tuple(builder.value) if builder.kind=="tuple" else builder.value
|
|
1578
|
+
|
|
1579
|
+
@staticmethod
|
|
1580
|
+
def pop_class_arguments(stack,arg):
|
|
1581
|
+
if arg.get("incremental_arguments"):
|
|
1582
|
+
arguments=stack.pop(); type_names=arg.get("type_params",[])
|
|
1583
|
+
type_values=stack[-len(type_names):] if type_names else []
|
|
1584
|
+
if type_names: del stack[-len(type_names):]
|
|
1585
|
+
return arguments.positional,arguments.keywords,type_names,type_values
|
|
1586
|
+
descriptors=arg.get("class_arguments")
|
|
1587
|
+
if descriptors:
|
|
1588
|
+
values=stack[-len(descriptors):]
|
|
1589
|
+
del stack[-len(descriptors):]
|
|
1590
|
+
bases=[]; keywords={}
|
|
1591
|
+
for (kind,name),value in zip(descriptors,values):
|
|
1592
|
+
if kind=="base": bases.append(value)
|
|
1593
|
+
elif kind=="star": bases.extend(value)
|
|
1594
|
+
elif kind=="kwstar":
|
|
1595
|
+
try: names=value.keys()
|
|
1596
|
+
except AttributeError: raise TypeError(f"argument after ** must be a mapping, not {type(value).__name__}") from None
|
|
1597
|
+
for key in names:
|
|
1598
|
+
if not isinstance(key,str): raise TypeError("keywords must be strings")
|
|
1599
|
+
if key in keywords: raise TypeError(f"클래스 키워드 인자 중복: {key}")
|
|
1600
|
+
keywords[key]=value[key]
|
|
1601
|
+
else:
|
|
1602
|
+
if name in keywords: raise TypeError(f"클래스 키워드 인자 중복: {name}")
|
|
1603
|
+
keywords[name]=value
|
|
1604
|
+
type_names=arg.get("type_params",[]); type_values=stack[-len(type_names):] if type_names else []
|
|
1605
|
+
if type_names: del stack[-len(type_names):]
|
|
1606
|
+
return bases,keywords,type_names,type_values
|
|
1607
|
+
keyword_names=arg.get("keywords",[]); keyword_values=stack[-len(keyword_names):] if keyword_names else []
|
|
1608
|
+
if keyword_names: del stack[-len(keyword_names):]
|
|
1609
|
+
keywords={}
|
|
1610
|
+
for name,value in zip(keyword_names,keyword_values):
|
|
1611
|
+
if name is None:
|
|
1612
|
+
for key,item in value.items():
|
|
1613
|
+
if key in keywords: raise TypeError(f"클래스 키워드 인자 중복: {key}")
|
|
1614
|
+
keywords[key]=item
|
|
1615
|
+
else:
|
|
1616
|
+
if name in keywords: raise TypeError(f"클래스 키워드 인자 중복: {name}")
|
|
1617
|
+
keywords[name]=value
|
|
1618
|
+
count=arg["bases"]; values=stack[-count:] if count else []
|
|
1619
|
+
if count: del stack[-count:]
|
|
1620
|
+
bases=[]
|
|
1621
|
+
for starred,value in zip(arg.get("base_starred",[False]*count),values): bases.extend(value) if starred else bases.append(value)
|
|
1622
|
+
type_names=arg.get("type_params",[]); type_values=stack[-len(type_names):] if type_names else []
|
|
1623
|
+
if type_names: del stack[-len(type_names):]
|
|
1624
|
+
return bases,keywords,type_names,type_values
|
|
1625
|
+
|
|
1626
|
+
@staticmethod
|
|
1627
|
+
def mapping_pop(mapping,key,default=None):
|
|
1628
|
+
try: value=mapping[key]
|
|
1629
|
+
except KeyError: return default
|
|
1630
|
+
del mapping[key]
|
|
1631
|
+
return value
|
|
1632
|
+
|
|
1633
|
+
def create_class(self,arg,scope,stack):
|
|
1634
|
+
bases,keywords,type_names,type_values=self.pop_class_arguments(stack,arg)
|
|
1635
|
+
original_bases=tuple(bases); bases=types.resolve_bases(original_bases)
|
|
1636
|
+
class_code=CodeObject.from_dict(arg["code"])
|
|
1637
|
+
metaclass,namespace,keywords=types.prepare_class(class_code.name,bases,keywords)
|
|
1638
|
+
for name,value in zip(type_names,type_values): namespace[name]=value
|
|
1639
|
+
class_qualname=self.qualified_name(scope,arg.get("name",class_code.name))
|
|
1640
|
+
namespace["__module__"]=scope.get("__name__",self.globals.get("__name__")); namespace["__qualname__"]=class_qualname; namespace["__doc__"]=arg.get("doc")
|
|
1641
|
+
if arg.get("firstlineno") is not None: namespace["__firstlineno__"]=arg["firstlineno"]
|
|
1642
|
+
namespace["$class_outer"]=scope; namespace["$class_local_names"]=set(arg.get("local_names",[])); namespace["$free_names"]=set(arg.get("free_names",[])); namespace["$qualname_prefix"]=class_qualname; namespace["$class_functions"]=[]; namespace["$class_type_parameters"]=dict(zip(type_names,type_values))
|
|
1643
|
+
class_cell=(lambda value: lambda: value)(None).__closure__[0]; del class_cell.cell_contents
|
|
1644
|
+
namespace["$class_cell"]=class_cell; namespace["$class_cell_needed"]=False
|
|
1645
|
+
if bases!=original_bases: namespace["__orig_bases__"]=original_bases
|
|
1646
|
+
self.run(class_code,namespace)
|
|
1647
|
+
class_cell_needed=self.mapping_pop(namespace,"$class_cell_needed"); self.mapping_pop(namespace,"$class_cell")
|
|
1648
|
+
class_functions=self.mapping_pop(namespace,"$class_functions",[]); self.mapping_pop(namespace,"$class_type_parameters")
|
|
1649
|
+
self.mapping_pop(namespace,"__return__"); self.mapping_pop(namespace,"$class_outer"); self.mapping_pop(namespace,"$class_local_names"); self.mapping_pop(namespace,"$free_names"); self.mapping_pop(namespace,"$qualname_prefix")
|
|
1650
|
+
namespace["__type_params__"]=tuple(type_values)
|
|
1651
|
+
namespace["__static_attributes__"]=tuple(arg.get("static_attributes",()))
|
|
1652
|
+
lazy_annotations=self.mapping_pop(namespace,"__annotations__")
|
|
1653
|
+
if isinstance(lazy_annotations,LazyAnnotations): lazy_annotations.scope=dict(namespace)
|
|
1654
|
+
for name,value in zip(type_names,type_values):
|
|
1655
|
+
try: current=namespace[name]
|
|
1656
|
+
except KeyError: continue
|
|
1657
|
+
if current is value: del namespace[name]
|
|
1658
|
+
if class_cell_needed: namespace["__classcell__"]=class_cell
|
|
1659
|
+
created=metaclass(class_code.name,bases,namespace,**keywords)
|
|
1660
|
+
if isinstance(lazy_annotations,LazyAnnotations): lazy_annotations.owner=created; lazy_annotations.scope=ClassAnnotationScope(created,scope.get("$class_outer",scope),dict(zip(type_names,type_values)))
|
|
1661
|
+
if isinstance(created,type):
|
|
1662
|
+
self.bind_class_functions(namespace,created)
|
|
1663
|
+
for function in class_functions: self.bind_class_function(function,created)
|
|
1664
|
+
return created
|
|
1665
|
+
|
|
1666
|
+
def create_function(self,arg,scope,stack):
|
|
1667
|
+
type_names=arg.get("type_params",[]); type_values=stack[-len(type_names):] if type_names else []
|
|
1668
|
+
if type_names: del stack[-len(type_names):]
|
|
1669
|
+
annotation_names=arg.get("annotations",[]); annotation_values=stack[-len(annotation_names):] if annotation_names else []
|
|
1670
|
+
if annotation_names: del stack[-len(annotation_names):]
|
|
1671
|
+
names=arg["defaults"]; values=stack[-len(names):] if names else []
|
|
1672
|
+
if names: del stack[-len(names):]
|
|
1673
|
+
closure=scope.get("$class_outer",scope)
|
|
1674
|
+
class_parameters=scope.get("$class_type_parameters",{})
|
|
1675
|
+
if class_parameters: closure={**class_parameters,"$closure":closure}
|
|
1676
|
+
name=arg.get("name",arg["code"].get("name","<함수>")); qualname=self.qualified_name(scope,name)
|
|
1677
|
+
function=Function(CodeObject.from_dict(arg["code"]),self.globals,dict(zip(names,values)),arg["signature"],closure,arg["generator"],arg["async"],dict(zip(annotation_names,annotation_values)),dict(zip(type_names,type_values)),None,name,qualname,scope.get("__name__",self.globals.get("__name__")),arg.get("doc"),arg.get("annotation_codes"),not bool(arg.get("annotation_codes")),arg.get("annotation_strings"),self,set(arg.get("local_names",arg["code"].get("parameters",[]))),set(arg.get("free_names",[])))
|
|
1678
|
+
function.free_names.update(name for name in class_parameters if self.code_loads_name(function.code.instructions,name))
|
|
1679
|
+
function.builtins_namespace=self.globals.get("__builtins__",builtins.__dict__)
|
|
1680
|
+
if "$class_functions" in scope: scope["$class_functions"].append(function)
|
|
1681
|
+
if "$class_cell" in scope and "__class__" not in function.local_names and self.code_needs_class_cell(function.code.instructions):
|
|
1682
|
+
function.class_cell=scope["$class_cell"]
|
|
1683
|
+
if "$class_cell_needed" in scope: scope["$class_cell_needed"]=True
|
|
1684
|
+
positional=arg["signature"].get("positional",[]); keyword_only=arg["signature"].get("keyword_only",[]); default_map=function.defaults or {}
|
|
1685
|
+
positional_values=tuple(default_map[item] for item in positional if item in default_map)
|
|
1686
|
+
keyword_values={item:default_map[item] for item in keyword_only if item in default_map}
|
|
1687
|
+
function.positional_defaults=positional_values or None; function.keyword_defaults=keyword_values or None
|
|
1688
|
+
return function
|
|
1689
|
+
|
|
1690
|
+
def call_value(self,function,args,kwargs,scope=None):
|
|
1691
|
+
if any(not isinstance(name,str) for name in kwargs): raise TypeError("keywords must be strings")
|
|
1692
|
+
if function is builtins.globals and not args and not kwargs: return self.globals
|
|
1693
|
+
if function is builtins.locals and not args and not kwargs: return self.visible_locals(scope) if scope is not None else self.globals
|
|
1694
|
+
if function is builtins.vars and not args and not kwargs: return self.visible_locals(scope) if scope is not None else self.globals
|
|
1695
|
+
if function is builtins.dir and not args and not kwargs: return sorted(self.visible_locals(scope) if scope is not None else self.globals)
|
|
1696
|
+
if function is sys.exception and not args and not kwargs and scope is not None and "$active_exception" in scope:
|
|
1697
|
+
return scope["$active_exception"]
|
|
1698
|
+
if function is sys.exc_info and not args and not kwargs and scope is not None and "$active_exception" in scope:
|
|
1699
|
+
exception=scope["$active_exception"]
|
|
1700
|
+
return type(exception),exception,exception.__traceback__
|
|
1701
|
+
if function is builtins.eval and len(args)==1 and not kwargs:
|
|
1702
|
+
return builtins.eval(args[0],self.globals,scope if scope is not None else self.globals)
|
|
1703
|
+
if function is builtins.exec and len(args)==1 and not kwargs:
|
|
1704
|
+
builtins.exec(args[0],self.globals,scope if scope is not None else self.globals)
|
|
1705
|
+
return None
|
|
1706
|
+
if isinstance(function,BoundFunction): args=[function.instance,*args]; function=function.function
|
|
1707
|
+
if isinstance(function,Function):
|
|
1708
|
+
caller_scope=scope
|
|
1709
|
+
function_scope={**(function.type_parameters or {}),**self.bind(function,args,kwargs),"$closure":function.closure or {},"$local_names":set(function.local_names or function.code.parameters),"$free_names":set(function.free_names or ()),"$qualname_prefix":f"{function.__qualname__}.<locals>"}
|
|
1710
|
+
if function.class_cell is not None:
|
|
1711
|
+
try: function_scope["__class__"]=function.class_cell.cell_contents
|
|
1712
|
+
except ValueError: pass
|
|
1713
|
+
function_scope["$has_class_cell"]=True
|
|
1714
|
+
if function.class_cell is not None: function_scope["$class_cell"]=function.class_cell
|
|
1715
|
+
if function.generator and function.asynchronous: return HythonAsyncGenerator(HythonGenerator(self,function.code,function_scope,function.__name__,function.__qualname__))
|
|
1716
|
+
if function.generator: return HythonGenerator(self,function.code,function_scope,function.__name__,function.__qualname__)
|
|
1717
|
+
if function.asynchronous: return HythonCoroutine(self,function.code,function_scope,function.__name__,function.__qualname__)
|
|
1718
|
+
if caller_scope is not None and "$active_exception" in caller_scope: function_scope["$active_exception"]=caller_scope["$active_exception"]
|
|
1719
|
+
try: return self.run(function.code,function_scope)
|
|
1720
|
+
except HythonReturn as signal: return signal.value
|
|
1721
|
+
if scope is not None and "$active_exception" in scope:
|
|
1722
|
+
target=args[0] if function is builtins.next and args else getattr(function,"__self__",None)
|
|
1723
|
+
if isinstance(target,(HythonGenerator,HythonAsyncGenerator,HythonCoroutine)):
|
|
1724
|
+
self.inherit_active_exception(target,scope)
|
|
1725
|
+
active=scope["$active_exception"]
|
|
1726
|
+
if sys.exception() is not active:
|
|
1727
|
+
try: raise active
|
|
1728
|
+
except BaseException: return function(*args,**kwargs)
|
|
1729
|
+
return function(*args,**kwargs)
|
|
1730
|
+
|
|
1731
|
+
def match_pattern(self,subject,spec,bindings,environment=None):
|
|
1732
|
+
environment=environment or self.globals
|
|
1733
|
+
kind=spec["kind"]
|
|
1734
|
+
if kind=="wildcard": return True
|
|
1735
|
+
if kind=="capture": bindings[spec["name"]]=(subject,spec.get("scope","local")); return True
|
|
1736
|
+
if kind=="literal": return subject==spec["value"]
|
|
1737
|
+
if kind=="singleton": return subject is spec["value"]
|
|
1738
|
+
if kind=="value":
|
|
1739
|
+
return subject==self.resolve_pattern_value(spec["path"],environment)
|
|
1740
|
+
if kind=="as":
|
|
1741
|
+
if not self.match_pattern(subject,spec["pattern"],bindings,environment): return False
|
|
1742
|
+
if spec["name"]!="_": bindings[spec["name"]]=(subject,spec.get("scope","local"))
|
|
1743
|
+
return True
|
|
1744
|
+
if kind=="or":
|
|
1745
|
+
for item in spec["items"]:
|
|
1746
|
+
trial={}
|
|
1747
|
+
if self.match_pattern(subject,item,trial,environment): bindings.update(trial); return True
|
|
1748
|
+
return False
|
|
1749
|
+
if kind=="sequence":
|
|
1750
|
+
if isinstance(subject,(str,bytes,bytearray)) or not isinstance(subject,Sequence): return False
|
|
1751
|
+
items=spec["items"]; stars=[i for i,p in enumerate(items) if p["kind"]=="star"]
|
|
1752
|
+
if len(stars)>1: return False
|
|
1753
|
+
if not stars and len(subject)!=len(items): return False
|
|
1754
|
+
if stars and len(subject)<len(items)-1: return False
|
|
1755
|
+
star=stars[0] if stars else None
|
|
1756
|
+
for index,pattern in enumerate(items):
|
|
1757
|
+
if pattern["kind"]=="star":
|
|
1758
|
+
if pattern["name"]!="_":
|
|
1759
|
+
stop=len(subject)-(len(items)-index-1)
|
|
1760
|
+
bindings[pattern["name"]]=([subject[position] for position in range(index,stop)],pattern.get("scope","local"))
|
|
1761
|
+
continue
|
|
1762
|
+
actual=index if star is None or index<star else len(subject)-(len(items)-index)
|
|
1763
|
+
if not self.match_pattern(subject[actual],pattern,bindings,environment): return False
|
|
1764
|
+
return True
|
|
1765
|
+
if kind=="mapping":
|
|
1766
|
+
if not isinstance(subject,Mapping): return False
|
|
1767
|
+
used=set()
|
|
1768
|
+
for pair in spec["pairs"]:
|
|
1769
|
+
key_spec=pair["key"]
|
|
1770
|
+
key=key_spec["value"] if key_spec["kind"]=="literal" else self.resolve_pattern_value(key_spec["path"],environment)
|
|
1771
|
+
if key in used: raise ValueError(f"매핑 패턴 키 중복: {key!r}")
|
|
1772
|
+
value=subject.get(key,_MISSING)
|
|
1773
|
+
if value is _MISSING: return False
|
|
1774
|
+
used.add(key)
|
|
1775
|
+
if not self.match_pattern(value,pair["pattern"],bindings,environment): return False
|
|
1776
|
+
if spec["rest"] and spec["rest"]!="_": bindings[spec["rest"]]=({k:v for k,v in subject.items() if k not in used},spec.get("rest_scope","local"))
|
|
1777
|
+
return True
|
|
1778
|
+
if kind=="class":
|
|
1779
|
+
expected=self.resolve_pattern_value(spec["name"],environment)
|
|
1780
|
+
if not isinstance(expected,type): raise TypeError("클래스 패턴 대상은 형식이어야 합니다.")
|
|
1781
|
+
if not isinstance(subject,expected): return False
|
|
1782
|
+
positional=spec["positional"]
|
|
1783
|
+
if not positional:
|
|
1784
|
+
positional_names=()
|
|
1785
|
+
else:
|
|
1786
|
+
match_args=getattr(expected,"__match_args__",_MISSING)
|
|
1787
|
+
match_self=match_args is _MISSING and issubclass(expected,_MATCH_SELF_TYPES)
|
|
1788
|
+
if match_args is _MISSING: match_args=()
|
|
1789
|
+
elif not isinstance(match_args,tuple): raise TypeError("__match_args__는 튜플이어야 합니다.")
|
|
1790
|
+
if match_self:
|
|
1791
|
+
if len(positional)>1: raise TypeError("클래스 패턴의 위치 패턴이 너무 많습니다.")
|
|
1792
|
+
positional_names=(None,)
|
|
1793
|
+
else:
|
|
1794
|
+
if len(positional)>len(match_args): raise TypeError("클래스 패턴의 위치 패턴이 너무 많습니다.")
|
|
1795
|
+
positional_names=match_args[:len(positional)]
|
|
1796
|
+
if not all(isinstance(name,str) for name in positional_names): raise TypeError("사용되는 __match_args__ 항목은 문자열이어야 합니다.")
|
|
1797
|
+
keyword_names=[item["name"] for item in spec["keywords"]]
|
|
1798
|
+
seen_attributes=set()
|
|
1799
|
+
for attribute in (*positional_names,*keyword_names):
|
|
1800
|
+
if attribute is None: continue
|
|
1801
|
+
if attribute in seen_attributes: raise TypeError(f"클래스 패턴 속성 중복: {attribute}")
|
|
1802
|
+
seen_attributes.add(attribute)
|
|
1803
|
+
for attribute,pattern in zip(positional_names,positional):
|
|
1804
|
+
if attribute is None: value=subject
|
|
1805
|
+
else:
|
|
1806
|
+
try: value=getattr(subject,attribute)
|
|
1807
|
+
except AttributeError: return False
|
|
1808
|
+
if not self.match_pattern(value,pattern,bindings,environment): return False
|
|
1809
|
+
for item in spec["keywords"]:
|
|
1810
|
+
try: value=getattr(subject,item["name"])
|
|
1811
|
+
except AttributeError: return False
|
|
1812
|
+
if not self.match_pattern(value,item["pattern"],bindings,environment): return False
|
|
1813
|
+
return True
|
|
1814
|
+
return False
|
|
1815
|
+
|
|
1816
|
+
def resolve_pattern_value(self,path,environment):
|
|
1817
|
+
parts=path.split(".")
|
|
1818
|
+
if parts[0] in environment: value=environment[parts[0]]
|
|
1819
|
+
elif parts[0] in self.globals: value=self.globals[parts[0]]
|
|
1820
|
+
else: raise NameError(parts[0])
|
|
1821
|
+
for part in parts[1:]: value=getattr(value,part)
|
|
1822
|
+
return value
|
|
1823
|
+
|
|
1824
|
+
def apply_pattern_bindings(self,scope,bindings):
|
|
1825
|
+
for name,(value,storage) in bindings.items(): self.assign_name(scope,name,value,storage)
|
|
1826
|
+
|
|
1827
|
+
def generator_expression(self,arg,local):
|
|
1828
|
+
scope=ComprehensionScope(self.comprehension_parent(local),arg.get("bindings",()))
|
|
1829
|
+
first=arg["clauses"][0]
|
|
1830
|
+
outer_iterator=iter(self.run(CodeObject.from_dict(first["iter"]),scope))
|
|
1831
|
+
def generate(index):
|
|
1832
|
+
if index<len(arg["clauses"]):
|
|
1833
|
+
clause=arg["clauses"][index]
|
|
1834
|
+
iterable=outer_iterator if index==0 else self.run(CodeObject.from_dict(clause["iter"]),scope)
|
|
1835
|
+
iterator=iterable if index==0 else iter(iterable)
|
|
1836
|
+
while True:
|
|
1837
|
+
try: item=next(iterator)
|
|
1838
|
+
except StopIteration: break
|
|
1839
|
+
self.assign_target(scope,clause["target"],item)
|
|
1840
|
+
if all(self.run(CodeObject.from_dict(test),scope) for test in clause["filters"]):
|
|
1841
|
+
yield from generate(index+1)
|
|
1842
|
+
return
|
|
1843
|
+
value=self.run(CodeObject.from_dict(arg["element"]),scope); self.commit_comprehension_bindings(arg,scope,local); yield value
|
|
1844
|
+
return generate(0)
|
|
1845
|
+
|
|
1846
|
+
def async_generator_expression(self,arg,local,scope=None,outer=_MISSING,waiter=None):
|
|
1847
|
+
scope=ComprehensionScope(self.comprehension_parent(local),arg.get("bindings",())) if scope is None else scope
|
|
1848
|
+
first=arg["clauses"][0]
|
|
1849
|
+
if outer is _MISSING: outer=self.run(CodeObject.from_dict(first["iter"]),scope)
|
|
1850
|
+
outer_iterator=builtins.aiter(outer) if first.get("async",False) else iter(outer)
|
|
1851
|
+
async def evaluate(payload):
|
|
1852
|
+
coroutine=HythonCoroutine(self,CodeObject.from_dict(payload),scope)
|
|
1853
|
+
return await (waiter(coroutine) if waiter is not None else coroutine)
|
|
1854
|
+
async def generate(index):
|
|
1855
|
+
if index<len(arg["clauses"]):
|
|
1856
|
+
clause=arg["clauses"][index]; iterable=outer_iterator if index==0 else await evaluate(clause["iter"])
|
|
1857
|
+
async def accepted(item):
|
|
1858
|
+
self.assign_target(scope,clause["target"],item)
|
|
1859
|
+
for test in clause["filters"]:
|
|
1860
|
+
if not await evaluate(test): return False
|
|
1861
|
+
return True
|
|
1862
|
+
if clause.get("async",False):
|
|
1863
|
+
iterator=iterable if index==0 else builtins.aiter(iterable)
|
|
1864
|
+
while True:
|
|
1865
|
+
try: item=await builtins.anext(iterator)
|
|
1866
|
+
except StopAsyncIteration: break
|
|
1867
|
+
if await accepted(item):
|
|
1868
|
+
async for result in generate(index+1): yield result
|
|
1869
|
+
else:
|
|
1870
|
+
iterator=iterable if index==0 else iter(iterable)
|
|
1871
|
+
while True:
|
|
1872
|
+
try: item=next(iterator)
|
|
1873
|
+
except StopIteration: break
|
|
1874
|
+
if await accepted(item):
|
|
1875
|
+
async for result in generate(index+1): yield result
|
|
1876
|
+
return
|
|
1877
|
+
value=await evaluate(arg["element"]); self.commit_comprehension_bindings(arg,scope,local); yield value
|
|
1878
|
+
return generate(0)
|
|
1879
|
+
|
|
1880
|
+
async def prepare_async_generator_expression(self,arg,local,waiter=None):
|
|
1881
|
+
scope=ComprehensionScope(self.comprehension_parent(local),arg.get("bindings",())); first=arg["clauses"][0]
|
|
1882
|
+
awaitable=HythonCoroutine(self,CodeObject.from_dict(first["iter"]),scope)
|
|
1883
|
+
outer=await (waiter(awaitable) if waiter is not None else awaitable)
|
|
1884
|
+
return self.async_generator_expression(arg,local,scope,outer)
|
|
1885
|
+
|
|
1886
|
+
async def run_async_comprehension(self,arg,local,waiter=None):
|
|
1887
|
+
result={} if arg["kind"]=="dictcomp" else set() if arg["kind"]=="setcomp" else []
|
|
1888
|
+
scope=ComprehensionScope(self.comprehension_parent(local),arg.get("bindings",()))
|
|
1889
|
+
async def evaluate(payload):
|
|
1890
|
+
coroutine=HythonCoroutine(self,CodeObject.from_dict(payload),scope)
|
|
1891
|
+
return await (waiter(coroutine) if waiter is not None else coroutine)
|
|
1892
|
+
async def wait(awaitable): return await (waiter(awaitable) if waiter is not None else awaitable)
|
|
1893
|
+
async def collect(index):
|
|
1894
|
+
if index<len(arg["clauses"]):
|
|
1895
|
+
clause=arg["clauses"][index]; iterable=await evaluate(clause["iter"])
|
|
1896
|
+
async def visit(item):
|
|
1897
|
+
self.assign_target(scope,clause["target"],item)
|
|
1898
|
+
for test in clause["filters"]:
|
|
1899
|
+
if not await evaluate(test): return
|
|
1900
|
+
await collect(index+1)
|
|
1901
|
+
if clause.get("async",False):
|
|
1902
|
+
iterator=builtins.aiter(iterable)
|
|
1903
|
+
while True:
|
|
1904
|
+
try: item=await wait(builtins.anext(iterator))
|
|
1905
|
+
except StopAsyncIteration: break
|
|
1906
|
+
await visit(item)
|
|
1907
|
+
else:
|
|
1908
|
+
for item in iterable: await visit(item)
|
|
1909
|
+
return
|
|
1910
|
+
if arg["kind"]=="dictcomp": result[await evaluate(arg["key"])]=await evaluate(arg["value"])
|
|
1911
|
+
else:
|
|
1912
|
+
value=await evaluate(arg["element"]); result.add(value) if arg["kind"]=="setcomp" else result.append(value)
|
|
1913
|
+
await collect(0); self.commit_comprehension_bindings(arg,scope,local); return result
|
|
1914
|
+
|
|
1915
|
+
@staticmethod
|
|
1916
|
+
def commit_comprehension_bindings(arg,scope,local):
|
|
1917
|
+
for name in arg.get("bindings",[]):
|
|
1918
|
+
if name in scope: local[name]=scope[name]
|
|
1919
|
+
|
|
1920
|
+
def assign_target(self,scope,spec,value):
|
|
1921
|
+
if isinstance(spec,str): scope[spec]=value; return
|
|
1922
|
+
if spec["kind"]=="name": self.assign_name(scope,spec["name"],value,spec.get("scope","local")); return
|
|
1923
|
+
if spec["kind"]=="attribute": setattr(self.run(CodeObject.from_dict(spec["object"]),scope),spec["name"],value); return
|
|
1924
|
+
if spec["kind"]=="subscript":
|
|
1925
|
+
target=self.run(CodeObject.from_dict(spec["object"]),scope); index=self.run(CodeObject.from_dict(spec["index"]),scope); target[index]=value; return
|
|
1926
|
+
if spec["kind"]=="starred": self.assign_target(scope,spec["target"],list(value)); return
|
|
1927
|
+
items=spec["items"]; stars=[i for i,item in enumerate(items) if item["kind"]=="starred"]
|
|
1928
|
+
if len(stars)>1: raise VMError("구조 분해 별표 대상은 하나만 허용됩니다.")
|
|
1929
|
+
if not stars:
|
|
1930
|
+
assigned=self.unpack_exact(value,len(items))
|
|
1931
|
+
else:
|
|
1932
|
+
star=stars[0]; after=len(items)-star-1
|
|
1933
|
+
assigned=self.unpack_extended(value,star,after)
|
|
1934
|
+
for target,item in zip(items,assigned): self.assign_target(scope,target,item)
|
|
1935
|
+
|
|
1936
|
+
@staticmethod
|
|
1937
|
+
def unpack_exact(value,expected):
|
|
1938
|
+
iterator=iter(value); values=[]
|
|
1939
|
+
for _ in range(expected):
|
|
1940
|
+
try: values.append(next(iterator))
|
|
1941
|
+
except StopIteration: raise ValueError(f"not enough values to unpack (expected {expected}, got {len(values)})") from None
|
|
1942
|
+
try: next(iterator)
|
|
1943
|
+
except StopIteration: return values
|
|
1944
|
+
raise ValueError(f"too many values to unpack (expected {expected})")
|
|
1945
|
+
|
|
1946
|
+
@staticmethod
|
|
1947
|
+
def unpack_extended(value,before,after):
|
|
1948
|
+
values=list(value); minimum=before+after
|
|
1949
|
+
if len(values)<minimum: raise ValueError(f"not enough values to unpack (expected at least {minimum}, got {len(values)})")
|
|
1950
|
+
tail=values[len(values)-after:] if after else []
|
|
1951
|
+
return [*values[:before],values[before:len(values)-after if after else None],*tail]
|
|
1952
|
+
|
|
1953
|
+
@staticmethod
|
|
1954
|
+
def compare_values(name,left,right):
|
|
1955
|
+
operations={"==":operator.eq,"!=":operator.ne,"<":operator.lt,"<=":operator.le,">":operator.gt,">=":operator.ge,
|
|
1956
|
+
"in":lambda a,b:a in b,"is":operator.is_,"not in":lambda a,b:a not in b,"is not":operator.is_not}
|
|
1957
|
+
return operations[name](left,right)
|
|
1958
|
+
|
|
1959
|
+
def run_compare_chain(self,arg,local):
|
|
1960
|
+
operands=arg["operands"]; operators=arg["operators"]; left=self.run(CodeObject.from_dict(operands[0]),local); result=True
|
|
1961
|
+
for index,(operator_name,payload) in enumerate(zip(operators,operands[1:])):
|
|
1962
|
+
right=self.run(CodeObject.from_dict(payload),local)
|
|
1963
|
+
result=self.compare_values(operator_name,left,right)
|
|
1964
|
+
if index<len(operators)-1 and not result: return result
|
|
1965
|
+
left=right
|
|
1966
|
+
return result
|
|
1967
|
+
|
|
1968
|
+
def make_type_alias(self,arg,local):
|
|
1969
|
+
payloads=[]
|
|
1970
|
+
for payload in arg["parameters"]:
|
|
1971
|
+
if isinstance(payload,(list,tuple)): payload={"kind":payload[0],"name":payload[1],"bound":None,"default":None}
|
|
1972
|
+
payloads.append(payload)
|
|
1973
|
+
if arg.get("value_text") is not None:
|
|
1974
|
+
namespace=TypeExpressionNamespace(local,{"__name__":local.get("__name__",self.globals.get("__name__","__main__"))},self.globals)
|
|
1975
|
+
declarations=[]
|
|
1976
|
+
for payload in payloads:
|
|
1977
|
+
prefix={"typevar":"","typevartuple":"*","paramspec":"**"}[payload["kind"]]
|
|
1978
|
+
declaration=f'{prefix}{payload["name"]}'
|
|
1979
|
+
if payload.get("bound_text") is not None: declaration+=f': {payload["bound_text"]}'
|
|
1980
|
+
if payload.get("default_text") is not None: declaration+=f' = {payload["default_text"]}'
|
|
1981
|
+
declarations.append(declaration)
|
|
1982
|
+
parameters=f"[{', '.join(declarations)}]" if declarations else ""
|
|
1983
|
+
builtins.exec(f'type {arg["name"]}{parameters} = {arg["value_text"]}',namespace)
|
|
1984
|
+
return namespace[arg["name"]]
|
|
1985
|
+
namespace={"__name__":local.get("__name__",self.globals.get("__name__","__main__"))}
|
|
1986
|
+
previous=[]; declarations=[]
|
|
1987
|
+
def evaluator(code,names):
|
|
1988
|
+
def evaluate(*values):
|
|
1989
|
+
scope=dict(local); scope.update(zip(names,values))
|
|
1990
|
+
return self.run(CodeObject.from_dict(code),scope)
|
|
1991
|
+
return evaluate
|
|
1992
|
+
for index,payload in enumerate(payloads):
|
|
1993
|
+
prefix={"typevar":"","typevartuple":"*","paramspec":"**"}[payload["kind"]]
|
|
1994
|
+
declaration=f'{prefix}{payload["name"]}'
|
|
1995
|
+
arguments=','.join(previous)
|
|
1996
|
+
if payload.get("bound") is not None:
|
|
1997
|
+
helper=f"__hython_bound_{index}"; namespace[helper]=evaluator(payload["bound"],tuple(previous))
|
|
1998
|
+
declaration+=f": {helper}({arguments})"
|
|
1999
|
+
if payload.get("default") is not None:
|
|
2000
|
+
helper=f"__hython_default_{index}"; namespace[helper]=evaluator(payload["default"],tuple(previous))
|
|
2001
|
+
declaration+=f" = {helper}({arguments})"
|
|
2002
|
+
declarations.append(declaration); previous.append(payload["name"])
|
|
2003
|
+
value_helper="__hython_alias_value"
|
|
2004
|
+
namespace[value_helper]=evaluator(arg["value"],tuple(previous))
|
|
2005
|
+
parameters=f"[{', '.join(declarations)}]" if declarations else ""
|
|
2006
|
+
arguments=','.join(previous)
|
|
2007
|
+
builtins.exec(f'type {arg["name"]}{parameters} = {value_helper}({arguments})',namespace)
|
|
2008
|
+
return namespace[arg["name"]]
|
|
2009
|
+
|
|
2010
|
+
def make_type_parameter(self,arg,local):
|
|
2011
|
+
group_names=arg.get("group_names",[arg["name"]]); group_index=arg.get("group_index",0)
|
|
2012
|
+
if group_index==0:
|
|
2013
|
+
group_scope={"$closure":local}
|
|
2014
|
+
local["$type_parameter_scope"]=group_scope
|
|
2015
|
+
else: group_scope=local.get("$type_parameter_scope",{"$closure":local})
|
|
2016
|
+
if arg.get("bound_text") is not None or arg.get("default_text") is not None:
|
|
2017
|
+
namespace=TypeExpressionNamespace(group_scope,{"__name__":local.get("__name__",self.globals.get("__name__","__main__"))},self.globals)
|
|
2018
|
+
prefix={"typevar":"","typevartuple":"*","paramspec":"**"}[arg["kind"]]
|
|
2019
|
+
declaration=f'{prefix}{arg["name"]}'
|
|
2020
|
+
if arg.get("bound_text") is not None: declaration+=f': {arg["bound_text"]}'
|
|
2021
|
+
if arg.get("default_text") is not None: declaration+=f' = {arg["default_text"]}'
|
|
2022
|
+
builtins.exec(f"type __HythonParameter[{declaration}] = object",namespace)
|
|
2023
|
+
parameter=namespace["__HythonParameter"].__type_params__[0]
|
|
2024
|
+
else:
|
|
2025
|
+
namespace={"__name__":local.get("__name__",self.globals.get("__name__","__main__"))}
|
|
2026
|
+
prefix={"typevar":"","typevartuple":"*","paramspec":"**"}[arg["kind"]]
|
|
2027
|
+
declaration=f'{prefix}{arg["name"]}'
|
|
2028
|
+
def evaluator(code):
|
|
2029
|
+
def evaluate(): return self.run(CodeObject.from_dict(code),dict(group_scope))
|
|
2030
|
+
return evaluate
|
|
2031
|
+
if arg.get("bound") is not None:
|
|
2032
|
+
namespace["__hython_bound"]=evaluator(arg["bound"]); declaration+=" : __hython_bound()"
|
|
2033
|
+
if arg.get("default") is not None:
|
|
2034
|
+
namespace["__hython_default"]=evaluator(arg["default"]); declaration+=" = __hython_default()"
|
|
2035
|
+
builtins.exec(f"type __HythonParameter[{declaration}] = object",namespace)
|
|
2036
|
+
parameter=namespace["__HythonParameter"].__type_params__[0]
|
|
2037
|
+
group_scope[arg["name"]]=parameter
|
|
2038
|
+
if group_index==len(group_names)-1: local.pop("$type_parameter_scope",None)
|
|
2039
|
+
return parameter
|
|
2040
|
+
|
|
2041
|
+
def run(self, code: CodeObject, locals_: dict | None = None):
|
|
2042
|
+
try:
|
|
2043
|
+
return self._run(code,locals_)
|
|
2044
|
+
except (HythonReturn,HythonBreak,HythonContinue,HythonAwait,HythonAsyncDelegate):
|
|
2045
|
+
raise
|
|
2046
|
+
except BaseException as exc:
|
|
2047
|
+
self.restore_saved_names(self.globals if locals_ is None else locals_)
|
|
2048
|
+
index=self._last_instruction.get(id(code),0)
|
|
2049
|
+
line=code.lines[index] if code.lines and 0<=index<len(code.lines) else 0
|
|
2050
|
+
frame=(code.name,line,index)
|
|
2051
|
+
frames=getattr(exc,"__hython_frames__",None)
|
|
2052
|
+
if frames is None:
|
|
2053
|
+
frames=[]
|
|
2054
|
+
try: setattr(exc,"__hython_frames__",frames)
|
|
2055
|
+
except Exception: frames=None
|
|
2056
|
+
if frames is not None and (not frames or frames[-1]!=frame):
|
|
2057
|
+
frames.append(frame)
|
|
2058
|
+
location=f"{code.name}:{line}" if line else code.name
|
|
2059
|
+
try: exc.add_note(f"하이썬 위치: {location}")
|
|
2060
|
+
except (AttributeError,TypeError): pass
|
|
2061
|
+
raise
|
|
2062
|
+
|
|
2063
|
+
def _run(self, code: CodeObject, locals_: dict | None = None):
|
|
2064
|
+
local = self.globals if locals_ is None else locals_
|
|
2065
|
+
stack=[]; ip=0; instructions=code.instructions
|
|
2066
|
+
binary={"ADD":operator.add,"SUB":operator.sub,"MUL":operator.mul,"DIV":operator.truediv,"FLOORDIV":operator.floordiv,"MOD":operator.mod,"POW":operator.pow,
|
|
2067
|
+
"EQ":operator.eq,"NE":operator.ne,"LT":operator.lt,"LE":operator.le,"GT":operator.gt,"GE":operator.ge,"IN":lambda a,b:a in b,"IS":operator.is_,
|
|
2068
|
+
"NOT_IN":lambda a,b:a not in b,"IS_NOT":operator.is_not}
|
|
2069
|
+
binary.update({"BIT_OR":operator.or_,"BIT_XOR":operator.xor,"BIT_AND":operator.and_,"LSHIFT":operator.lshift,"RSHIFT":operator.rshift,"MATMUL":operator.matmul})
|
|
2070
|
+
binary.update({"IADD":operator.iadd,"ISUB":operator.isub,"IMUL":operator.imul,"IDIV":operator.itruediv,"IFLOORDIV":operator.ifloordiv,"IMOD":operator.imod,"IPOW":operator.ipow,"IBIT_OR":operator.ior,"IBIT_XOR":operator.ixor,"IBIT_AND":operator.iand,"ILSHIFT":operator.ilshift,"IRSHIFT":operator.irshift,"IMATMUL":operator.imatmul})
|
|
2071
|
+
while ip < len(instructions):
|
|
2072
|
+
self._last_instruction[id(code)]=ip
|
|
2073
|
+
ins=instructions[ip]; op=ins[0]; arg=ins[1] if len(ins)>1 else None; ip+=1
|
|
2074
|
+
if op=="CONST": stack.append(code.constants[arg])
|
|
2075
|
+
elif op=="LOAD":
|
|
2076
|
+
if arg in local: stack.append(local[arg])
|
|
2077
|
+
elif arg in local.get("$local_names",()): raise UnboundLocalError(f"local variable '{arg}' referenced before assignment")
|
|
2078
|
+
elif arg in local.get("$free_names",()):
|
|
2079
|
+
closure=self.nonlocal_scope(local,arg)
|
|
2080
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
2081
|
+
stack.append(closure[arg])
|
|
2082
|
+
elif (found:=self.lookup_closure(local,arg))[0]: stack.append(found[1])
|
|
2083
|
+
elif "$class_outer" in local and arg not in local.get("$class_local_names",()) and arg in local["$class_outer"]: stack.append(local["$class_outer"][arg])
|
|
2084
|
+
elif arg in self.globals: stack.append(self.globals[arg])
|
|
2085
|
+
else: raise NameError(f"name '{arg}' is not defined")
|
|
2086
|
+
elif op=="STORE": local[arg]=stack.pop()
|
|
2087
|
+
elif op=="SAVE_NAME": self.save_name(local,arg)
|
|
2088
|
+
elif op=="RESTORE_NAME": self.restore_name(local,arg)
|
|
2089
|
+
elif op=="ANNOTATE": local.setdefault("__annotations__",{})[arg]=stack.pop()
|
|
2090
|
+
elif op=="ANNOTATE_LAZY": self.register_annotation(local,arg)
|
|
2091
|
+
elif op=="SUPER": stack.append(self.zero_argument_super(local,arg))
|
|
2092
|
+
elif op=="MAKE_TYPE_ALIAS": stack.append(self.make_type_alias(arg,local))
|
|
2093
|
+
elif op=="MAKE_TYPE_PARAMETER": stack.append(self.make_type_parameter(arg,local))
|
|
2094
|
+
elif op=="UNPACK":
|
|
2095
|
+
values=self.unpack_exact(stack.pop(),arg)
|
|
2096
|
+
stack.extend(reversed(values))
|
|
2097
|
+
elif op=="UNPACK_EX":
|
|
2098
|
+
before=arg>>16; after=arg&0xFFFF
|
|
2099
|
+
stack.extend(reversed(self.unpack_extended(stack.pop(),before,after)))
|
|
2100
|
+
elif op=="STORE_GLOBAL": self.globals[arg]=stack.pop()
|
|
2101
|
+
elif op=="STORE_NONLOCAL":
|
|
2102
|
+
closure=self.nonlocal_scope(local,arg)
|
|
2103
|
+
closure[arg]=stack.pop()
|
|
2104
|
+
elif op=="DELETE":
|
|
2105
|
+
if arg not in local: raise self.missing_delete_error(local,arg)
|
|
2106
|
+
del local[arg]
|
|
2107
|
+
elif op=="DELETE_GLOBAL":
|
|
2108
|
+
if arg not in self.globals: raise NameError(f"name '{arg}' is not defined")
|
|
2109
|
+
del self.globals[arg]
|
|
2110
|
+
elif op=="DELETE_NONLOCAL":
|
|
2111
|
+
closure=self.nonlocal_scope(local,arg)
|
|
2112
|
+
if arg not in closure: raise NameError(f"free variable '{arg}' is not defined in enclosing scope")
|
|
2113
|
+
del closure[arg]
|
|
2114
|
+
elif op=="POP": stack.pop()
|
|
2115
|
+
elif op=="DUP": stack.append(stack[-1])
|
|
2116
|
+
elif op=="DUP2": stack.extend(stack[-2:])
|
|
2117
|
+
elif op in binary: b=stack.pop(); a=stack.pop(); stack.append(binary[op](a,b))
|
|
2118
|
+
elif op in ("NEG","POS","NOT","INVERT"): stack.append({"NEG":operator.neg,"POS":operator.pos,"NOT":operator.not_,"INVERT":operator.invert}[op](stack.pop()))
|
|
2119
|
+
elif op=="JUMP": ip=arg
|
|
2120
|
+
elif op=="JUMP_FALSE":
|
|
2121
|
+
if not stack.pop(): ip=arg
|
|
2122
|
+
elif op=="JUMP_IF_FALSE_OR_POP":
|
|
2123
|
+
if not stack[-1]: ip=arg
|
|
2124
|
+
else: stack.pop()
|
|
2125
|
+
elif op=="JUMP_IF_TRUE_OR_POP":
|
|
2126
|
+
if stack[-1]: ip=arg
|
|
2127
|
+
else: stack.pop()
|
|
2128
|
+
elif op=="ITER": stack.append(iter(stack.pop()))
|
|
2129
|
+
elif op=="FOR_ITER":
|
|
2130
|
+
try: stack.append(next(stack[-1]))
|
|
2131
|
+
except StopIteration: stack.pop(); ip=arg
|
|
2132
|
+
elif op in ("BUILD_LIST","BUILD_TUPLE","BUILD_SET"):
|
|
2133
|
+
values=stack[-arg:] if arg else []
|
|
2134
|
+
if arg: del stack[-arg:]
|
|
2135
|
+
stack.append(list(values) if op=="BUILD_LIST" else tuple(values) if op=="BUILD_TUPLE" else set(values))
|
|
2136
|
+
elif op=="BUILD_DICT":
|
|
2137
|
+
values=stack[-arg*2:] if arg else []
|
|
2138
|
+
if arg: del stack[-arg*2:]
|
|
2139
|
+
stack.append(dict(zip(values[::2],values[1::2])))
|
|
2140
|
+
elif op=="BUILD_UNPACK":
|
|
2141
|
+
count=len(arg["starred"]); values=stack[-count:] if count else []
|
|
2142
|
+
if count: del stack[-count:]
|
|
2143
|
+
merged=[]
|
|
2144
|
+
for value,starred in zip(values,arg["starred"]): merged.extend(value) if starred else merged.append(value)
|
|
2145
|
+
stack.append(tuple(merged) if arg["kind"]=="tuple" else set(merged) if arg["kind"]=="set" else merged)
|
|
2146
|
+
elif op=="BUILD_DICT_UNPACK":
|
|
2147
|
+
count=sum(2 if item=="pair" else 1 for item in arg); values=stack[-count:] if count else []
|
|
2148
|
+
if count: del stack[-count:]
|
|
2149
|
+
result={}; index=0
|
|
2150
|
+
for item in arg:
|
|
2151
|
+
if item=="pair": result[values[index]]=values[index+1]; index+=2
|
|
2152
|
+
else: result.update(values[index]); index+=1
|
|
2153
|
+
stack.append(result)
|
|
2154
|
+
elif op=="COLLECTION_BEGIN": stack.append(self.collection_builder(arg))
|
|
2155
|
+
elif op=="COLLECTION_ADD":
|
|
2156
|
+
value=stack.pop(); key=stack.pop() if arg=="pair" else None
|
|
2157
|
+
self.add_collection_item(stack[-1],arg,value,key)
|
|
2158
|
+
elif op=="COLLECTION_READY": stack.append(self.finish_collection(stack.pop()))
|
|
2159
|
+
elif op=="BUILD_SLICE":
|
|
2160
|
+
step=stack.pop(); stop=stack.pop(); start=stack.pop(); stack.append(slice(start,stop,step))
|
|
2161
|
+
elif op=="GET_ITEM":
|
|
2162
|
+
index=stack.pop(); container=stack.pop(); stack.append(container[index])
|
|
2163
|
+
elif op=="SET_ITEM":
|
|
2164
|
+
value=stack.pop(); index=stack.pop(); container=stack.pop(); container[index]=value
|
|
2165
|
+
elif op=="DELETE_ITEM":
|
|
2166
|
+
index=stack.pop(); container=stack.pop(); del container[index]
|
|
2167
|
+
elif op=="GET_ATTR": stack.append(getattr(stack.pop(),arg))
|
|
2168
|
+
elif op=="SET_ATTR":
|
|
2169
|
+
value=stack.pop(); target=stack.pop(); setattr(target,arg,value)
|
|
2170
|
+
elif op=="DELETE_ATTR": delattr(stack.pop(),arg)
|
|
2171
|
+
elif op=="IMPORT": stack.append(self.import_module(arg,code))
|
|
2172
|
+
elif op=="IMPORT_FROM": stack.append(self.import_from(arg["module"],arg["name"],code))
|
|
2173
|
+
elif op=="IMPORT_STAR": self.import_star(local,stack.pop())
|
|
2174
|
+
elif op=="FORMAT": stack.append(str(stack.pop()))
|
|
2175
|
+
elif op=="FORMAT_VALUE":
|
|
2176
|
+
spec=stack.pop() if arg["has_spec"] else ""; value=stack.pop()
|
|
2177
|
+
if arg["conversion"]=="r": value=repr(value)
|
|
2178
|
+
elif arg["conversion"]=="s": value=str(value)
|
|
2179
|
+
elif arg["conversion"]=="a": value=ascii(value)
|
|
2180
|
+
stack.append(format(value,spec))
|
|
2181
|
+
elif op=="BUILD_STRING":
|
|
2182
|
+
values=stack[-arg:] if arg else []
|
|
2183
|
+
if arg: del stack[-arg:]
|
|
2184
|
+
stack.append("".join(values))
|
|
2185
|
+
elif op=="MAKE_INTERPOLATION":
|
|
2186
|
+
spec=stack.pop(); conversion=stack.pop(); expression=stack.pop(); value=stack.pop(); stack.append(Interpolation(value,expression,conversion,spec))
|
|
2187
|
+
elif op=="BUILD_TEMPLATE":
|
|
2188
|
+
values=stack[-arg:] if arg else []
|
|
2189
|
+
if arg: del stack[-arg:]
|
|
2190
|
+
stack.append(Template(*values))
|
|
2191
|
+
elif op=="ASSERT":
|
|
2192
|
+
message=stack.pop(); condition=stack.pop()
|
|
2193
|
+
if not condition: raise AssertionError(message) if message is not None else AssertionError()
|
|
2194
|
+
elif op=="MATCH_PATTERN":
|
|
2195
|
+
bindings={}; matched=self.match_pattern(stack.pop(),arg,bindings,local)
|
|
2196
|
+
if matched: self.apply_pattern_bindings(local,bindings)
|
|
2197
|
+
stack.append(matched)
|
|
2198
|
+
elif op=="CHAIN_COMPARE": stack.append(self.run_compare_chain(arg,local))
|
|
2199
|
+
elif op=="RAISE": raise stack.pop()
|
|
2200
|
+
elif op=="RAISE_FROM":
|
|
2201
|
+
cause=stack.pop(); error=stack.pop(); raise error from cause
|
|
2202
|
+
elif op=="RERAISE":
|
|
2203
|
+
self.reraise(local)
|
|
2204
|
+
elif op=="TRY":
|
|
2205
|
+
failure=None; control=None
|
|
2206
|
+
try:
|
|
2207
|
+
self.run(CodeObject.from_dict(arg["body"]),local)
|
|
2208
|
+
except (HythonBreak,HythonContinue) as signal:
|
|
2209
|
+
control=signal
|
|
2210
|
+
except HythonReturn:
|
|
2211
|
+
raise
|
|
2212
|
+
except BaseException as exc:
|
|
2213
|
+
if arg["handlers"] and arg["handlers"][0].get("star",False):
|
|
2214
|
+
original=exc if isinstance(exc,BaseExceptionGroup) else BaseExceptionGroup("",[exc]); remaining=original; raised=[]; reraised=[]
|
|
2215
|
+
for handler in arg["handlers"]:
|
|
2216
|
+
expected=self.run(CodeObject.from_dict(handler["type"]),local)
|
|
2217
|
+
matched,remaining=remaining.split(expected)
|
|
2218
|
+
if matched is None: continue
|
|
2219
|
+
if handler["alias"]: self.assign_name(local,handler["alias"],matched,handler.get("alias_scope","local"))
|
|
2220
|
+
previous=self.push_active_exception(local,matched)
|
|
2221
|
+
try: self.run(CodeObject.from_dict(handler["code"]),local)
|
|
2222
|
+
except BaseException as failure:
|
|
2223
|
+
(reraised if failure is matched else raised).append(failure)
|
|
2224
|
+
finally:
|
|
2225
|
+
self.pop_active_exception(local,previous)
|
|
2226
|
+
if handler["alias"]: self.delete_name(local,handler["alias"],handler.get("alias_scope","local"))
|
|
2227
|
+
failure=_merge_except_star(original,reraised,raised,remaining)
|
|
2228
|
+
if failure is not None: raise failure
|
|
2229
|
+
failure=None; continue
|
|
2230
|
+
failure=exc; handled=False
|
|
2231
|
+
for handler in arg["handlers"]:
|
|
2232
|
+
expected=self.run(CodeObject.from_dict(handler["type"]),local) if handler["type"] else BaseException
|
|
2233
|
+
if isinstance(exc,expected):
|
|
2234
|
+
if handler["alias"]: self.assign_name(local,handler["alias"],exc,handler.get("alias_scope","local"))
|
|
2235
|
+
previous=self.push_active_exception(local,exc)
|
|
2236
|
+
try: self.run(CodeObject.from_dict(handler["code"]),local)
|
|
2237
|
+
finally:
|
|
2238
|
+
self.pop_active_exception(local,previous)
|
|
2239
|
+
if handler["alias"]: self.delete_name(local,handler["alias"],handler.get("alias_scope","local"))
|
|
2240
|
+
handled=True; failure=None; break
|
|
2241
|
+
if not handled: raise
|
|
2242
|
+
else:
|
|
2243
|
+
if arg["else"]: self.run(CodeObject.from_dict(arg["else"]),local)
|
|
2244
|
+
finally:
|
|
2245
|
+
if arg["finally"]:
|
|
2246
|
+
active=sys.exception(); previous=_MISSING; pushed=False
|
|
2247
|
+
if active is not None and not isinstance(active,(HythonReturn,HythonBreak,HythonContinue)):
|
|
2248
|
+
previous=self.push_active_exception(local,active); pushed=True
|
|
2249
|
+
try: self.run(CodeObject.from_dict(arg["finally"]),local)
|
|
2250
|
+
finally:
|
|
2251
|
+
if pushed: self.pop_active_exception(local,previous)
|
|
2252
|
+
if isinstance(control,HythonBreak): ip=arg["break_target"]
|
|
2253
|
+
elif isinstance(control,HythonContinue): ip=arg["continue_target"]
|
|
2254
|
+
elif op=="COMPREHENSION":
|
|
2255
|
+
if any(clause.get("async",False) for clause in arg["clauses"]):
|
|
2256
|
+
if arg["kind"]=="generatorexpr": stack.append(self.async_generator_expression(arg,local)); continue
|
|
2257
|
+
raise VMError("비동기 컴프리헨션은 비동기 함수 안에서만 사용할 수 있습니다.")
|
|
2258
|
+
if arg["kind"]=="generatorexpr": stack.append(self.generator_expression(arg,local)); continue
|
|
2259
|
+
scope=ComprehensionScope(self.comprehension_parent(local),arg.get("bindings",()))
|
|
2260
|
+
result={} if arg["kind"]=="dictcomp" else set() if arg["kind"]=="setcomp" else []
|
|
2261
|
+
def collect(index):
|
|
2262
|
+
if index<len(arg["clauses"]):
|
|
2263
|
+
clause=arg["clauses"][index]
|
|
2264
|
+
iterable=self.run(CodeObject.from_dict(clause["iter"]),scope)
|
|
2265
|
+
for item in iterable:
|
|
2266
|
+
self.assign_target(scope,clause["target"],item)
|
|
2267
|
+
if all(self.run(CodeObject.from_dict(test),scope) for test in clause["filters"]): collect(index+1)
|
|
2268
|
+
return
|
|
2269
|
+
if arg["kind"]=="dictcomp":
|
|
2270
|
+
key=self.run(CodeObject.from_dict(arg["key"]),scope)
|
|
2271
|
+
value=self.run(CodeObject.from_dict(arg["value"]),scope); result[key]=value
|
|
2272
|
+
else:
|
|
2273
|
+
value=self.run(CodeObject.from_dict(arg["element"]),scope)
|
|
2274
|
+
result.add(value) if arg["kind"]=="setcomp" else result.append(value)
|
|
2275
|
+
collect(0); self.commit_comprehension_bindings(arg,scope,local)
|
|
2276
|
+
stack.append(result)
|
|
2277
|
+
elif op=="WITH":
|
|
2278
|
+
exits=[]; failure=None
|
|
2279
|
+
try:
|
|
2280
|
+
for manager in arg["managers"]:
|
|
2281
|
+
context=self.run(CodeObject.from_dict(manager["code"]),local)
|
|
2282
|
+
enter_method,exit_method=self.context_methods(context,False)
|
|
2283
|
+
entered=enter_method()
|
|
2284
|
+
exits.append(exit_method)
|
|
2285
|
+
if manager["alias"]: self.assign_target(local,manager["alias"],entered)
|
|
2286
|
+
self.run(CodeObject.from_dict(arg["body"]),local)
|
|
2287
|
+
except BaseException as caught:
|
|
2288
|
+
failure=caught
|
|
2289
|
+
try: self.unwind_exits(exits,failure)
|
|
2290
|
+
except HythonBreak: ip=arg["break_target"]
|
|
2291
|
+
except HythonContinue: ip=arg["continue_target"]
|
|
2292
|
+
elif op=="MAKE_FUNCTION":
|
|
2293
|
+
stack.append(self.create_function(arg,local,stack))
|
|
2294
|
+
elif op=="MAKE_CLASS":
|
|
2295
|
+
stack.append(self.create_class(arg,local,stack))
|
|
2296
|
+
elif op=="CALL":
|
|
2297
|
+
args=stack[-arg:] if arg else [];
|
|
2298
|
+
if arg: del stack[-arg:]
|
|
2299
|
+
function=stack.pop(); stack.append(self.call_value(function,args,{},local))
|
|
2300
|
+
elif op=="CALL_EX":
|
|
2301
|
+
values=stack[-len(arg):] if arg else []
|
|
2302
|
+
if arg: del stack[-len(arg):]
|
|
2303
|
+
function=stack.pop(); positional,keywords=self.expand_call_arguments(arg,values)
|
|
2304
|
+
stack.append(self.call_value(function,positional,keywords,local))
|
|
2305
|
+
elif op=="CALL_BEGIN": stack.append(CallArguments([],{}))
|
|
2306
|
+
elif op=="CALL_ARG": self.add_call_argument(stack[-2],arg,stack.pop())
|
|
2307
|
+
elif op=="CALL_READY":
|
|
2308
|
+
arguments=stack.pop(); function=stack.pop()
|
|
2309
|
+
stack.append(self.call_value(function,arguments.positional,arguments.keywords,local))
|
|
2310
|
+
elif op=="CLASS_BEGIN": stack.append(CallArguments([],{}))
|
|
2311
|
+
elif op=="CLASS_ARG": self.add_class_argument(stack[-2],arg,stack.pop())
|
|
2312
|
+
elif op=="RETURN": return stack.pop()
|
|
2313
|
+
elif op=="SIGNAL_RETURN": raise HythonReturn(stack.pop())
|
|
2314
|
+
elif op=="SIGNAL_BREAK": raise HythonBreak()
|
|
2315
|
+
elif op=="SIGNAL_CONTINUE": raise HythonContinue()
|
|
2316
|
+
elif op=="NOP": pass
|
|
2317
|
+
else: raise VMError(f"알 수 없는 HBC 명령어: {op}")
|
|
2318
|
+
return None
|
|
2319
|
+
@staticmethod
|
|
2320
|
+
def lookup_closure(scope,name):
|
|
2321
|
+
seen=set(); current=scope.get("$closure") if isinstance(scope,dict) else None
|
|
2322
|
+
while isinstance(current,dict) and id(current) not in seen:
|
|
2323
|
+
seen.add(id(current))
|
|
2324
|
+
if name in current: return True,current[name]
|
|
2325
|
+
current=current.get("$closure")
|
|
2326
|
+
return False,None
|
|
2327
|
+
|
|
2328
|
+
@staticmethod
|
|
2329
|
+
def nonlocal_scope(scope,name):
|
|
2330
|
+
seen=set(); current=scope.get("$closure",scope.get("$class_outer")) if isinstance(scope,dict) else None
|
|
2331
|
+
while isinstance(current,dict) and id(current) not in seen:
|
|
2332
|
+
seen.add(id(current))
|
|
2333
|
+
if "$class_outer" in current:
|
|
2334
|
+
current=current["$class_outer"]
|
|
2335
|
+
continue
|
|
2336
|
+
if name in current or name in current.get("$local_names",()): return current
|
|
2337
|
+
current=current.get("$closure")
|
|
2338
|
+
raise NameError(f"free variable '{name}' is not defined in enclosing scope")
|
|
2339
|
+
|
|
2340
|
+
@staticmethod
|
|
2341
|
+
def bind_class_functions(namespace,owner):
|
|
2342
|
+
for name in namespace:
|
|
2343
|
+
value=namespace[name]
|
|
2344
|
+
if isinstance(value,(staticmethod,classmethod)):
|
|
2345
|
+
targets=(value.__func__,)
|
|
2346
|
+
elif isinstance(value,property):
|
|
2347
|
+
targets=(value.fget,value.fset,value.fdel)
|
|
2348
|
+
else:
|
|
2349
|
+
targets=(value,)
|
|
2350
|
+
for target in targets:
|
|
2351
|
+
VM.bind_class_function(target,owner)
|
|
2352
|
+
|
|
2353
|
+
@staticmethod
|
|
2354
|
+
def bind_class_function(target,owner):
|
|
2355
|
+
expected=f"{owner.__qualname__}.{target.__name__}" if isinstance(target,Function) else None
|
|
2356
|
+
if isinstance(target,Function) and target.__qualname__==expected:
|
|
2357
|
+
target.class_owner=owner
|
|
2358
|
+
target.module_name=owner.__module__
|
|
2359
|
+
|
|
2360
|
+
@staticmethod
|
|
2361
|
+
def code_needs_class_cell(value):
|
|
2362
|
+
if isinstance(value,(list,tuple)):
|
|
2363
|
+
direct=bool(value and (value[0]=="SUPER" or len(value)>1 and value[0]=="LOAD" and value[1]=="__class__"))
|
|
2364
|
+
return direct or any(VM.code_needs_class_cell(item) for item in value)
|
|
2365
|
+
if isinstance(value,dict): return any(VM.code_needs_class_cell(item) for item in value.values())
|
|
2366
|
+
return False
|
|
2367
|
+
|
|
2368
|
+
@staticmethod
|
|
2369
|
+
def code_loads_name(value,name):
|
|
2370
|
+
if isinstance(value,(list,tuple)):
|
|
2371
|
+
direct=len(value)>1 and value[0]=="LOAD" and value[1]==name
|
|
2372
|
+
return direct or any(VM.code_loads_name(item,name) for item in value)
|
|
2373
|
+
if isinstance(value,dict): return any(VM.code_loads_name(item,name) for item in value.values())
|
|
2374
|
+
return False
|
|
2375
|
+
|
|
2376
|
+
@staticmethod
|
|
2377
|
+
def comprehension_parent(scope):
|
|
2378
|
+
return scope.get("$class_outer",scope) if isinstance(scope,dict) else scope
|
|
2379
|
+
|
|
2380
|
+
@staticmethod
|
|
2381
|
+
def missing_delete_error(scope,name):
|
|
2382
|
+
if name in scope.get("$local_names",()):
|
|
2383
|
+
return UnboundLocalError(f"local variable '{name}' referenced before assignment")
|
|
2384
|
+
return NameError(f"name '{name}' is not defined")
|
|
2385
|
+
|
|
2386
|
+
@staticmethod
|
|
2387
|
+
def visible_locals(scope):
|
|
2388
|
+
hidden=scope.get("$class_type_parameters",{}) if isinstance(scope,dict) else {}
|
|
2389
|
+
visible={name:value for name,value in scope.items() if not name.startswith("$") and not (name in hidden and value is hidden[name])}
|
|
2390
|
+
if isinstance(scope,dict) and "$closure" in scope and "$class_outer" not in scope:
|
|
2391
|
+
for name in scope.get("$free_names",()):
|
|
2392
|
+
if name in visible: continue
|
|
2393
|
+
found,value=VM.lookup_closure(scope,name)
|
|
2394
|
+
if found: visible[name]=value
|
|
2395
|
+
return visible
|
|
2396
|
+
|
|
2397
|
+
@staticmethod
|
|
2398
|
+
def qualified_name(scope,name):
|
|
2399
|
+
prefix=scope.get("$qualname_prefix") if isinstance(scope,dict) else None
|
|
2400
|
+
return f"{prefix}.{name}" if prefix else name
|
|
2401
|
+
|
|
2402
|
+
def assign_name(self,scope,name,value,storage="local"):
|
|
2403
|
+
if storage=="global": self.globals[name]=value
|
|
2404
|
+
elif storage=="nonlocal": self.nonlocal_scope(scope,name)[name]=value
|
|
2405
|
+
else: scope[name]=value
|
|
2406
|
+
|
|
2407
|
+
def delete_name(self,scope,name,storage="local"):
|
|
2408
|
+
target=self.globals if storage=="global" else self.nonlocal_scope(scope,name) if storage=="nonlocal" else scope
|
|
2409
|
+
target.pop(name,None)
|