1616
1717PY3 , PY2 = six .PY3 , not six .PY3
1818
19- from .pyobj import Frame , Block , Method , Function , Generator
19+ from .pyobj import Frame , Block , Method , Function , Generator , Cell
2020
2121log = logging .getLogger (__name__ )
2222
@@ -91,7 +91,7 @@ def push_block(self, type, handler=None, level=None):
9191 def pop_block (self ):
9292 return self .frame .block_stack .pop ()
9393
94- def make_frame (self , code , callargs = {}, f_globals = None , f_locals = None ):
94+ def make_frame (self , code , callargs = {}, f_globals = None , f_locals = None , f_closure = None ):
9595 log .info ("make_frame: code=%r, callargs=%s" % (code , repper (callargs )))
9696 if f_globals is not None :
9797 f_globals = f_globals
@@ -108,7 +108,7 @@ def make_frame(self, code, callargs={}, f_globals=None, f_locals=None):
108108 '__package__' : None ,
109109 }
110110 f_locals .update (callargs )
111- frame = Frame (code , f_globals , f_locals , self .frame )
111+ frame = Frame (code , f_globals , f_locals , f_closure , self .frame )
112112 return frame
113113
114114 def push_frame (self , frame ):
@@ -446,7 +446,10 @@ def byte_LOAD_GLOBAL(self, name):
446446 elif name in f .f_builtins :
447447 val = f .f_builtins [name ]
448448 else :
449- raise NameError ("global name '%s' is not defined" % name )
449+ if PY2 :
450+ raise NameError ("global name '%s' is not defined" % name )
451+ elif PY3 :
452+ raise NameError ("name '%s' is not defined" % name )
450453 self .push (val )
451454
452455 def byte_STORE_GLOBAL (self , name ):
@@ -1169,11 +1172,59 @@ def byte_BUILD_CLASS(self):
11691172 elif PY3 :
11701173 def byte_LOAD_BUILD_CLASS (self ):
11711174 # New in py3
1172- self .push (__build_class__ )
1175+ self .push (build_class )
11731176
11741177 def byte_STORE_LOCALS (self ):
11751178 self .frame .f_locals = self .pop ()
11761179
11771180 if 0 : # Not in py2.7
11781181 def byte_SET_LINENO (self , lineno ):
11791182 self .frame .f_lineno = lineno
1183+
1184+ if PY3 :
1185+ def build_class (func , name , * bases , ** kwds ):
1186+ "Like __build_class__ in bltinmodule.c, but running in the byterun VM."
1187+ if not isinstance (func , Function ):
1188+ raise TypeError ("func must be a function" )
1189+ if not isinstance (name , str ):
1190+ raise TypeError ("name is not a string" )
1191+ metaclass = kwds .pop ('metaclass' , None )
1192+ # (We don't just write 'metaclass=None' in the signature above
1193+ # because that's a syntax error in Py2.)
1194+ if metaclass is None :
1195+ metaclass = type (bases [0 ]) if bases else type
1196+ if isinstance (metaclass , type ):
1197+ metaclass = calculate_metaclass (metaclass , bases )
1198+
1199+ try :
1200+ prepare = metaclass .__prepare__
1201+ except AttributeError :
1202+ namespace = {}
1203+ else :
1204+ namespace = prepare (name , bases , ** kwds )
1205+
1206+ # Execute the body of func. This is the step that would go wrong if
1207+ # we tried to use the built-in __build_class__, because __build_class__
1208+ # does not call func, it magically executes its body directly, as we
1209+ # do here (except we invoke our VirtualMachine instead of CPython's).
1210+ frame = func ._vm .make_frame (func .func_code ,
1211+ f_globals = func .func_globals ,
1212+ f_locals = namespace ,
1213+ f_closure = func .func_closure )
1214+ cell = func ._vm .run_frame (frame )
1215+
1216+ cls = metaclass (name , bases , namespace )
1217+ if isinstance (cell , Cell ):
1218+ cell .set (cls )
1219+ return cls
1220+
1221+ def calculate_metaclass (metaclass , bases ):
1222+ "Determine the most derived metatype."
1223+ winner = metaclass
1224+ for base in bases :
1225+ t = type (base )
1226+ if issubclass (t , winner ):
1227+ winner = t
1228+ elif not issubclass (winner , t ):
1229+ raise TypeError ("metaclass conflict" , winner , t )
1230+ return winner
0 commit comments