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 ):
@@ -1173,11 +1176,59 @@ def byte_BUILD_CLASS(self):
11731176 elif PY3 :
11741177 def byte_LOAD_BUILD_CLASS (self ):
11751178 # New in py3
1176- self .push (__build_class__ )
1179+ self .push (build_class )
11771180
11781181 def byte_STORE_LOCALS (self ):
11791182 self .frame .f_locals = self .pop ()
11801183
11811184 if 0 : # Not in py2.7
11821185 def byte_SET_LINENO (self , lineno ):
11831186 self .frame .f_lineno = lineno
1187+
1188+ if PY3 :
1189+ def build_class (func , name , * bases , ** kwds ):
1190+ "Like __build_class__ in bltinmodule.c, but running in the byterun VM."
1191+ if not isinstance (func , Function ):
1192+ raise TypeError ("func must be a function" )
1193+ if not isinstance (name , str ):
1194+ raise TypeError ("name is not a string" )
1195+ metaclass = kwds .pop ('metaclass' , None )
1196+ # (We don't just write 'metaclass=None' in the signature above
1197+ # because that's a syntax error in Py2.)
1198+ if metaclass is None :
1199+ metaclass = type (bases [0 ]) if bases else type
1200+ if isinstance (metaclass , type ):
1201+ metaclass = calculate_metaclass (metaclass , bases )
1202+
1203+ try :
1204+ prepare = metaclass .__prepare__
1205+ except AttributeError :
1206+ namespace = {}
1207+ else :
1208+ namespace = prepare (name , bases , ** kwds )
1209+
1210+ # Execute the body of func. This is the step that would go wrong if
1211+ # we tried to use the built-in __build_class__, because __build_class__
1212+ # does not call func, it magically executes its body directly, as we
1213+ # do here (except we invoke our VirtualMachine instead of CPython's).
1214+ frame = func ._vm .make_frame (func .func_code ,
1215+ f_globals = func .func_globals ,
1216+ f_locals = namespace ,
1217+ f_closure = func .func_closure )
1218+ cell = func ._vm .run_frame (frame )
1219+
1220+ cls = metaclass (name , bases , namespace )
1221+ if isinstance (cell , Cell ):
1222+ cell .set (cls )
1223+ return cls
1224+
1225+ def calculate_metaclass (metaclass , bases ):
1226+ "Determine the most derived metatype."
1227+ winner = metaclass
1228+ for base in bases :
1229+ t = type (base )
1230+ if issubclass (t , winner ):
1231+ winner = t
1232+ elif not issubclass (winner , t ):
1233+ raise TypeError ("metaclass conflict" , winner , t )
1234+ return winner
0 commit comments