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/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)