[pypy-svn] rev 1265 - pypy/branch/builtinrefactor/pypy/interpreter
arigo at codespeak.net
arigo at codespeak.net
Sun Aug 10 21:34:27 CEST 2003
Author: arigo
Date: Sun Aug 10 21:34:26 2003
New Revision: 1265
Added:
pypy/branch/builtinrefactor/pypy/interpreter/nestedscope.py
- copied, changed from rev 1264, pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py
Removed:
pypy/branch/builtinrefactor/pypy/interpreter/pyfastscope.py
pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py
Modified:
pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py
pypy/branch/builtinrefactor/pypy/interpreter/eval.py
pypy/branch/builtinrefactor/pypy/interpreter/gateway.py
pypy/branch/builtinrefactor/pypy/interpreter/pycode.py
pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py
pypy/branch/builtinrefactor/pypy/interpreter/pyopcode.py
pypy/branch/builtinrefactor/pypy/interpreter/unittest_w.py
Log:
Still nothing that works, far from it, but progress nevertheless
(I think).
Modified: pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py Sun Aug 10 21:34:26 2003
@@ -5,6 +5,11 @@
__all__ = ['ObjSpace', 'OperationError', 'NoValue']
+class Wrappable(object):
+ """A subclass of Wrappable is an internal, interpreter-level class
+ that can nevertheless be exposed at application-level by space.wrap()."""
+
+
class NoValue(Exception):
"""Raised to signal absence of value, e.g. in the iterator accessing
method 'op.next()' of object spaces."""
Modified: pypy/branch/builtinrefactor/pypy/interpreter/eval.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/eval.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/eval.py Sun Aug 10 21:34:26 2003
@@ -25,43 +25,31 @@
"([list-of-arg-names], vararg-name-or-None, kwarg-name-or-None)."
return [], None, None
- def getargcount(self):
- "Number of arguments including * and **."
+ def getvarnames(self):
+ """List of names including the arguments, vararg and kwarg,
+ and possibly more locals."""
argnames, varargname, kwargname = self.signature()
- count = len(argnames)
if varargname is not None:
- count += 1
+ argnames.append(argname)
if kwargname is not None:
- count += 1
- return count
+ argnames.append(kwargname)
+ return argnames
- def getlocalvarname(self, index):
- "Default implementation, can be overridden."
- argnames, varargname, kwargname = self.signature()
- try:
- return argnames[index]
- except IndexError:
- index -= len(argnames)
- if varargname is not None:
- if index == 0:
- return varargname
- index -= 1
- if kwargname is not None:
- if index == 0:
- return kwargname
- index -= 1
- raise IndexError, "local variable index out of bounds"
+
+UNDEFINED = object() # marker for undefined local variables
class Frame(object):
"""A frame is an environment supporting the execution of a code object.
Abstract base class."""
- def __init__(self, space, code, w_globals):
+ def __init__(self, space, code, w_globals, numlocals=0):
self.space = space
self.code = code # Code instance
self.w_globals = w_globals # wrapped dict of globals
self.w_locals = None # wrapped dict of locals
+ # flat list of wrapped locals
+ self.fastlocals_w = [UNDEFINED]*numlocals
def run(self):
"Run the frame."
@@ -78,21 +66,45 @@
raise TypeError, "abstract"
def getdictscope(self):
- "Overriden by subclasses with another representation for locals."
+ "Get the locals as a dictionary."
+ self.fast2locals()
return self.w_locals
def setdictscope(self, w_locals):
- """Initialize the locals from a dictionary.
- Overriden by subclasses with another representation for locals."""
+ "Initialize the locals from a dictionary."
self.w_locals = w_locals
+ self.locals2fast()
+
+ def getfastscope(self):
+ "Get the fast locals as a list."
+ return self.fastlocals_w
def setfastscope(self, scope_w):
- """Initialize the locals from a list of values,
- where the order is according to self.code.signature().
- Default implementation, to be overridden."""
- space = self.space
+ """Initialize the fast locals from a list of values,
+ where the order is according to self.code.signature()."""
+ if len(scope_w) > len(self.fastlocals_w):
+ raise ValueError, "too many fastlocals"
+ self.fastlocals_w[:len(scope_w)] = scope_w
+
+ def fast2locals(self):
+ # Copy values from self.fastlocals_w to self.w_locals
if self.w_locals is None:
- self.w_locals = space.newdict([])
- for i in range(len(scope_w)):
- varname = self.code.getlocalvarname(i)
- space.setitem(self.w_locals, space.wrap(varname), scope_w[i])
+ self.w_locals = self.space.newdict([])
+ varnames = self.code.getvarnames()
+ for name, w_value in zip(varnames, self.fastlocals_w):
+ if w_value is not UNDEFINED:
+ w_name = self.space.wrap(name)
+ self.space.setitem(self.w_locals, w_name, w_value)
+
+ def locals2fast(self):
+ # Copy values from self.w_locals to self.fastlocals_w
+ varnames = self.code.getvarnames()
+ for name, i in zip(varnames, range(len(self.fastlocals_w))):
+ w_name = self.space.wrap(varnames[i])
+ try:
+ w_value = self.space.getitem(self.w_locals, w_name)
+ except OperationError, e:
+ if not e.match(self.space, self.space.w_KeyError):
+ raise
+ else:
+ self.fastlocals_w[i] = w_value
Modified: pypy/branch/builtinrefactor/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/gateway.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/gateway.py Sun Aug 10 21:34:26 2003
@@ -1,331 +1,416 @@
"""
Gateway between app-level and interpreter-level:
-the Wrappable base class.
+* BuiltinCode (calling interp-level code from app-level)
+* code2interp (embedding a code object into an interpreter-level callable)
+* app2interp (embedding an app-level function's code object in the same way)
"""
-class Wrappable(object):
- """A subclass of Wrappable is an internal, interpreter-level class
- that can nevertheless be exposed at application-level,
- via space.wrap().
-
- The methods and attributes that a class wants to expose are defined
- with a naming convension: 'app_xxx' is exposed as 'xxx'.
- In general, 'app_xxx' should be a gateway (see below)."""
-
-# XXX most code from some classes below have been "stolen" in
-# XXX new classes in other modules. Will be removed.
-
-
-
-class ScopedCode(object):
- """ a code object within a certain global and closure scope.
- (the local scope is given when you call 'eval_frame')
- """
- def __init__(self, space, cpycode, w_globals=None, closure_w=()):
- self.space = space
- self.cpycode = cpycode
- self.w_code = space.wrap(cpycode)
- self.closure_w = closure_w
- if w_globals is None:
- w_globals = space.newdict([])
- self.w_globals = w_globals
-
- def create_frame(self, w_locals=None):
- """ return result of executing code object within a frame"""
- from pyframe import PyFrame
- frame = PyFrame()
- frame.initialize(self)
- if w_locals is None:
- w_locals = self.w_globals
- frame.setdictscope(w_locals)
- return frame
-
- def eval_frame(self, *args, **kwargs):
- frame = self.create_frame(*args, **kwargs)
- return self.space.getexecutioncontext().eval_frame(frame)
-
-class app2interp(object):
- """ this class exposes an app-level method at interpreter-level.
-
- Note that the wrapped method must *NOT* use a 'self' argument.
- Assumption: the instance on which this method is bound to has a
- 'space' attribute.
- """
- def __init__(self, appfunc):
- self.appfunc = appfunc
-
- def __get__(self, instance, cls=None):
- return InterpretedFunction(instance.space, self.appfunc)
-
-class InterpretedFunctionFromCode(ScopedCode):
- def __init__(self, space, cpycode, w_defs, w_globals=None, closure_w=()):
- ScopedCode.__init__(self, space, cpycode, w_globals, closure_w)
- self.w_defs = w_defs
- self.simple = cpycode.co_flags & (CO_VARARGS|CO_VARKEYWORDS)==0
- self.func_code = cpycode
-
- def parse_args(self, frame, w_args, w_kwargs):
- """ parse args and kwargs and set fast scope of frame.
- """
- space = self.space
- loc_w = None
- if self.simple and (w_kwargs is None or not space.is_true(w_kwargs)):
- try:
- loc_w = space.unpacktuple(w_args, self.cpycode.co_argcount)
- except ValueError:
- pass
- if loc_w is None:
- #print "complicated case of arguments for", self.cpycode.co_name, "simple=", self.simple
- w_loc = self.parse_args_complex(self.w_code, w_args, w_kwargs, self.w_defs)
- loc_w = space.unpacktuple(w_loc)
- loc_w.extend([_NULL] * (self.cpycode.co_nlocals - len(loc_w)))
-
- # make nested cells
- if self.cpycode.co_cellvars:
- varnames = list(self.cpycode.co_varnames)
- for name in self.cpycode.co_cellvars:
- i = varnames.index(name)
- w_value = loc_w[i]
- loc_w[i] = _NULL
- frame.closure_w += (Cell(w_value),)
-
- assert len(loc_w) == self.cpycode.co_nlocals, "local arguments not prepared correctly"
- frame.setfastscope(loc_w)
-
- def create_frame(self, w_args, w_kwargs):
- """ parse arguments and execute frame """
- from pyframe import PyFrame
- frame = PyFrame()
- frame.initialize(self)
- self.parse_args(frame, w_args, w_kwargs)
- return frame
-
- def app_parse_args_complex(cpycode, args, kwargs, defs):
- """ return list of initial local values parsed from
- 'args', 'kwargs' and defaults.
- """
- #if cpycode.co_name == 'failUnlessRaises':
- # print "co_name", cpycode.co_name
- # print "co_argcount", cpycode.co_argcount
- # print "co_nlocals", cpycode.co_nlocals
- # print "co_varnames", cpycode.co_varnames
- # print "args", args
- # print "kwargs", kwargs
- # print "defs", defs
-
- CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8
-
- # co_argcount number of expected positional arguments
- # (elipsis args like *args and **kwargs do not count)
- co_argcount = cpycode.co_argcount
-
- # construct list of positional args
- positional_args = list(args[:co_argcount])
-
- len_args = len(args)
- len_defs = len(defs)
-
- if len_args < co_argcount:
- # not enough args, fill in kwargs or defaults if exists
- i = len_args
- while i < co_argcount:
- name = cpycode.co_varnames[i]
- if name in kwargs:
- positional_args.append(kwargs[name])
- del kwargs[name]
- else:
- if i + len_defs < co_argcount:
- raise TypeError, "Not enough arguments"
- positional_args.append(defs[i-co_argcount])
- i+=1
- if cpycode.co_flags & CO_VARARGS:
- positional_args.append(tuple(args[co_argcount:]))
- elif len_args > co_argcount:
- raise TypeError, "Too many arguments"
-
- # we only do the next loop for determining multiple kw-values
- i = 0
- while i < len_args and i < co_argcount:
- name = cpycode.co_varnames[i]
- if name in kwargs:
- raise TypeError, "got multiple values for argument %r" % name
- i+=1
-
- if cpycode.co_flags & CO_VARKEYWORDS:
- positional_args.append(kwargs)
- elif kwargs:
- raise TypeError, "got unexpected keyword argument(s) %s" % repr(kwargs.keys()[0])
-
- return positional_args
- parse_args_complex = app2interp(app_parse_args_complex)
-
- def __call__(self, *args_w, **kwargs_w):
- """ execute function and take arguments with
- native interp-level parameter passing convention """
- w_args = self.space.newtuple(args_w)
- w = self.space.wrap
- w_kwargs = self.space.newdict([])
- for name, w_value in kwargs_w.items():
- self.space.setitem(w_kwargs, w(name), w_value)
- return self.eval_frame(w_args, w_kwargs)
-
-class InterpretedFunction(InterpretedFunctionFromCode):
- """ a function which executes at app-level (by interpreting bytecode
- and dispatching operations on an objectspace).
- """
-
- def __init__(self, space, cpyfunc, w_globals=None, closure_w=()):
- """ initialization similar to base class but it also wraps
- some function-specific stuff (like defaults).
- """
- assert not hasattr(cpyfunc, 'im_self')
- InterpretedFunctionFromCode.__init__(self, space,
- cpyfunc.func_code,
- space.wrap(cpyfunc.func_defaults or ()),
- w_globals, closure_w)
-
-class InterpretedMethod(InterpretedFunction):
- """ an InterpretedFunction with 'self' spice.
-
- XXX hpk: i think we want to eliminate all uses for this class
- as bound/unbound methods should be done in objspace?!
-
- """
-
- def __init__(self, *args):
- InterpretedFunction.__init__(self, *args)
-
- def parse_args(self, frame, w_args, w_kwargs):
- """ fills in "self" arg and dispatch to InterpreterFunction.
- """
- space = self.space
- args_w = space.unpacktuple(w_args)
- args_w = [space.wrap(self)] + args_w
- w_args = space.newtuple(args_w)
- return InterpretedFunction.parse_args(self, frame, w_args, w_kwargs)
-
-class AppVisibleModule:
- """ app-level visible Module defined at interpreter-level.
-
- Inherit from this class if you want to have a module that accesses
- the PyPy interpreter (e.g. builtins like 'locals()' require accessing the
- frame). You can mix in application-level code by prefixing your method
- with 'app_'. Both non-underscore methods and app-level methods will
- be available on app-level with their respective name.
-
- Note that app-level functions don't get a 'self' argument because it doesn't
- make sense and we really only need the function (there is no notion of beeing
- 'bound' or 'unbound' for them).
-
- """
- def __init__(self, space):
- self.space = space
-
- space = self.space
- modname = self.__class__.__name__
- self.w___name__ = space.wrap(modname)
- self._wrapped = _wrapped = space.newmodule(self.w___name__)
-
- # go through all items in the module class instance
- for name in dir(self):
- # skip spurious info and internal methods
- if name == '__module__' or name.startswith('_') and not name.endswith('_'):
- #print modname, "skipping", name
- continue
- obj = getattr(self, name)
- # see if we just need to expose an already wrapped value
- if name.startswith('w_'):
- space.setattr(_wrapped, space.wrap(name[2:]), obj)
-
- # see if have something defined at app-level
- elif name.startswith('app_'):
- obj = self.__class__.__dict__.get(name)
- name = name[4:]
- w_res = wrap_applevel(space, name, obj)
- # nope then we must expose interpreter-level to app-level
- else:
- w_res = wrap_interplevel(space, name, obj)
- setattr(self, 'w_'+name, w_res)
- w_name = space.wrap(name)
- space.setattr(_wrapped, w_name, w_res)
-
-def wrap_applevel(space, name, obj):
- """ wrap an app-level style object which was compiled at interp-level. """
- if hasattr(obj, 'func_code'):
- return space.wrap(InterpretedFunction(space, obj))
- elif inspect.isclass(obj):
- # XXX currently (rev 1020) unused, but it may be useful
- # to define builtin app-level classes at interp-level.
- return wrap_applevel_class(space, name, obj)
- else:
- raise ValueError, "cannot wrap %s, %s" % (name, obj)
-
-def wrap_applevel_class(space, name, obj):
- """ construct an app-level class by reproducing the
- source definition and running it through the interpreter.
- It's a bit ugly but i don't know a better way (holger).
- """
- assert 1!=1, "Oh you want to use this function?"
- l = ['class %s:' % name]
- indent = ' '
- for key, value in vars(obj).items():
- if hasattr(value, 'func_code'):
- s = inspect.getsource(value)
- l.append(s)
- indent = " " * (len(s) - len(s.lstrip()))
-
- if getattr(obj, '__doc__', None):
- l.insert(1, indent + obj.__doc__)
-
- for key, value in vars(obj).items():
- if not key in ('__module__', '__doc__'):
- if isinstance(value, (str, int, float, tuple, list)):
- l.append('%s%s = %r' % (indent, key, value))
-
- s = "\n".join(l)
- code = compile(s, s, 'exec')
- scopedcode = ScopedCode(space, code, None)
- scopedcode.eval_frame()
- w_name = space.wrap(name)
- w_res = space.getitem(scopedcode.w_globals, w_name)
- return w_res
-
-
-def wrap_interplevel(space, name, obj):
- """ make an interp-level object accessible on app-level. """
- return space.wrap(obj)
-
-## Cells (used for nested scopes only) ##
-
-_NULL = object() # Marker object
-
-class Cell:
- def __init__(self, w_value=_NULL):
- self.w_value = w_value
-
- def clone(self):
- return self.__class__(self.w_value)
-
- def get(self):
- if self.w_value is _NULL:
- raise ValueError, "get() from an empty cell"
- return self.w_value
-
- def set(self, w_value):
- self.w_value = w_value
-
- def delete(self):
- if self.w_value is _NULL:
- raise ValueError, "make_empty() on an empty cell"
- self.w_value = _NULL
-
- def __repr__(self):
- """ representation for debugging purposes """
- if self.w_value is _NULL:
- return "%s()" % self.__class__.__name__
- else:
- return "%s(%s)" % (self.__class__.__name__, self.w_value)
+from pypy.interpreter import eval, pycode
+from pypy.interpreter.baseobjspace import Wrappable
+
+class BuiltinCode(eval.Code):
+ "The code object implementing a built-in (interpreter-level) hook."
+ # When a BuiltinCode is stored in a Function object,
+ # you get the functionality of CPython's built-in function type.
+
+ def __init__(self, func):
+ # 'implfunc' is the interpreter-level function.
+ # note that this uses a lot of (construction-time) introspection.
+ eval.Code.__init__(self, func.__name__)
+ self.func = func
+ # extract the signature from the (CPython-level) code object
+ tmp = pycode.PyCode(None)
+ tmp._from_code(func.func_code)
+ self.sig = tmp.signature()
+ self.nargs = len(self.getvarnames())
+
+ def create_frame(self, space, w_globals, closure=None):
+ return BuiltinFrame(space, self, w_globals, numlocals=self.nargs)
+
+ def signature(self):
+ return self.sig
+
+
+class BuiltinFrame(eval.Frame):
+ "Frame emulation for BuiltinCode."
+ # This is essentially just a delegation to the 'func' of the BuiltinCode.
+ # Initialization of locals is already done by the time run() is called,
+ # via the interface defined in eval.Frame.
+
+ def run(self):
+ return call_with_prepared_arguments(self.space, self.code.func,
+ self.fastlocals_w)
+
+
+def call_with_prepared_arguments(space, function, argarray):
+ """Call the given function. 'argarray' is a correctly pre-formatted
+ list of values for the formal parameters, including one for * and one
+ for **."""
+ # XXX there is no clean way to do this in Python,
+ # we have to hack back an arguments tuple and keywords dict.
+ # This algorithm is put in its own well-isolated function so that
+ # you don't need to look at it :-)
+ keywords = {}
+ co = function.func_code
+ if co.flags & 8: # CO_VARKEYWORDS
+ w_kwds = argarray[-1]
+ for w_key in space.unpackiterable(w_kwds):
+ keywords[space.unwrap(w_key)] = space.getitem(w_kwds, w_key)
+ argarray = argarray[:-1]
+ if co.flags & 4: # CO_VARARGS
+ w_varargs = argarray[-1]
+ argarray = argarray[:-1] + space.unpacktuple(w_varargs)
+ return function(*argarray, **keywords)
+
+
+class code2interp(object):
+ # General-purpose utility for the interpreter-level to create callables
+ # that transparently invoke code objects (and thus possibly interpreted
+ # app-level code).
+
+ def __init__(self, code, staticglobals, staticdefaults=[]):
+ self.code = code
+ self.staticglobals = staticglobals # a StaticGlobals instance
+ self.staticdefaults = staticdefaults
+
+ def make_function(self, space):
+ assert self.staticglobals.is_frozen(), (
+ "gateway not callable before the StaticGlobals is frozen")
+ w_globals = space.wrap(self.staticglobals)
+ defs_w = [space.wrap(def_value) for def_value in self.staticdefaults]
+ return Function(space, self.code, w_globals, defs_w)
+
+ def __call__(self, space, *args, **kwds):
+ wrap = space.wrap
+ w_args = [wrap(arg) for arg in args]
+ w_kwds = space.newdict([(wrap(key), wrap(value))
+ for key, value in kwds.items()])
+ fn = self.make_function(space)
+ return fn.call(w_args, w_kwds)
+
+
+class StaticGlobals(Wrappable):
+ # This class captures a part of the content of an interpreter module
+ # or of a class definition, to be exposed at app-level with a read-only
+ # dict-like interface.
+
+ def __init__(self, content=None):
+ self.content = None
+ if content is not None:
+ self.freeze(content)
+
+ def freeze(self, content):
+ # Freeze the object to the value given by 'content':
+ # either a dictionary or a (new-style) class
+ assert self.content is None, "%r already frozen" % self
+ if isinstance(content, dict):
+ content = content.copy()
+ else:
+ mro = list(content.__mro__)
+ mro.reverse()
+ content = {}
+ for c in mro:
+ content.update(c.__dict__)
+ self.content = content
+
+ def is_frozen(self):
+ return self.content is not None
+
+ def app2interp(self, app_f):
+ "Build a code2interp gateway that calls 'app_f' at app-level."
+ code = pycode.PyCode(None)
+ code._from_code(app_f.func_code)
+ return code2interp(code, self, list(app_f.func_defaults or ()))
+
+ def __getitem__(self, key):
+ # XXX is only present for today's stdobjspace.cpythonobject wrapper
+ return self.content[key]
+
+noglobals = StaticGlobals({})
+
+
+##class app2interp(object):
+## """ this class exposes an app-level method at interpreter-level.
+
+## Note that the wrapped method must *NOT* use a 'self' argument.
+## Assumption: the instance on which this method is bound to has a
+## 'space' attribute.
+## """
+## def __init__(self, appfunc):
+## self.appfunc = appfunc
+
+## def __get__(self, instance, cls=None):
+## return InterpretedFunction(instance.space, self.appfunc)
+
+##class InterpretedFunctionFromCode(ScopedCode):
+## def __init__(self, space, cpycode, w_defs, w_globals=None, closure_w=()):
+## ScopedCode.__init__(self, space, cpycode, w_globals, closure_w)
+## self.w_defs = w_defs
+## self.simple = cpycode.co_flags & (CO_VARARGS|CO_VARKEYWORDS)==0
+## self.func_code = cpycode
+
+## def parse_args(self, frame, w_args, w_kwargs):
+## """ parse args and kwargs and set fast scope of frame.
+## """
+## space = self.space
+## loc_w = None
+## if self.simple and (w_kwargs is None or not space.is_true(w_kwargs)):
+## try:
+## loc_w = space.unpacktuple(w_args, self.cpycode.co_argcount)
+## except ValueError:
+## pass
+## if loc_w is None:
+## #print "complicated case of arguments for", self.cpycode.co_name, "simple=", self.simple
+## w_loc = self.parse_args_complex(self.w_code, w_args, w_kwargs, self.w_defs)
+## loc_w = space.unpacktuple(w_loc)
+## loc_w.extend([_NULL] * (self.cpycode.co_nlocals - len(loc_w)))
+
+## # make nested cells
+## if self.cpycode.co_cellvars:
+## varnames = list(self.cpycode.co_varnames)
+## for name in self.cpycode.co_cellvars:
+## i = varnames.index(name)
+## w_value = loc_w[i]
+## loc_w[i] = _NULL
+## frame.closure_w += (Cell(w_value),)
+
+## assert len(loc_w) == self.cpycode.co_nlocals, "local arguments not prepared correctly"
+## frame.setfastscope(loc_w)
+
+## def create_frame(self, w_args, w_kwargs):
+## """ parse arguments and execute frame """
+## from pyframe import PyFrame
+## frame = PyFrame()
+## frame.initialize(self)
+## self.parse_args(frame, w_args, w_kwargs)
+## return frame
+
+## def app_parse_args_complex(cpycode, args, kwargs, defs):
+## """ return list of initial local values parsed from
+## 'args', 'kwargs' and defaults.
+## """
+## #if cpycode.co_name == 'failUnlessRaises':
+## # print "co_name", cpycode.co_name
+## # print "co_argcount", cpycode.co_argcount
+## # print "co_nlocals", cpycode.co_nlocals
+## # print "co_varnames", cpycode.co_varnames
+## # print "args", args
+## # print "kwargs", kwargs
+## # print "defs", defs
+
+## CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8
+
+## # co_argcount number of expected positional arguments
+## # (elipsis args like *args and **kwargs do not count)
+## co_argcount = cpycode.co_argcount
+
+## # construct list of positional args
+## positional_args = list(args[:co_argcount])
+
+## len_args = len(args)
+## len_defs = len(defs)
+
+## if len_args < co_argcount:
+## # not enough args, fill in kwargs or defaults if exists
+## i = len_args
+## while i < co_argcount:
+## name = cpycode.co_varnames[i]
+## if name in kwargs:
+## positional_args.append(kwargs[name])
+## del kwargs[name]
+## else:
+## if i + len_defs < co_argcount:
+## raise TypeError, "Not enough arguments"
+## positional_args.append(defs[i-co_argcount])
+## i+=1
+## if cpycode.co_flags & CO_VARARGS:
+## positional_args.append(tuple(args[co_argcount:]))
+## elif len_args > co_argcount:
+## raise TypeError, "Too many arguments"
+
+## # we only do the next loop for determining multiple kw-values
+## i = 0
+## while i < len_args and i < co_argcount:
+## name = cpycode.co_varnames[i]
+## if name in kwargs:
+## raise TypeError, "got multiple values for argument %r" % name
+## i+=1
+
+## if cpycode.co_flags & CO_VARKEYWORDS:
+## positional_args.append(kwargs)
+## elif kwargs:
+## raise TypeError, "got unexpected keyword argument(s) %s" % repr(kwargs.keys()[0])
+
+## return positional_args
+## parse_args_complex = app2interp(app_parse_args_complex)
+
+## def __call__(self, *args_w, **kwargs_w):
+## """ execute function and take arguments with
+## native interp-level parameter passing convention """
+## w_args = self.space.newtuple(args_w)
+## w = self.space.wrap
+## w_kwargs = self.space.newdict([])
+## for name, w_value in kwargs_w.items():
+## self.space.setitem(w_kwargs, w(name), w_value)
+## return self.eval_frame(w_args, w_kwargs)
+
+##class InterpretedFunction(InterpretedFunctionFromCode):
+## """ a function which executes at app-level (by interpreting bytecode
+## and dispatching operations on an objectspace).
+## """
+
+## def __init__(self, space, cpyfunc, w_globals=None, closure_w=()):
+## """ initialization similar to base class but it also wraps
+## some function-specific stuff (like defaults).
+## """
+## assert not hasattr(cpyfunc, 'im_self')
+## InterpretedFunctionFromCode.__init__(self, space,
+## cpyfunc.func_code,
+## space.wrap(cpyfunc.func_defaults or ()),
+## w_globals, closure_w)
+
+##class InterpretedMethod(InterpretedFunction):
+## """ an InterpretedFunction with 'self' spice.
+
+## XXX hpk: i think we want to eliminate all uses for this class
+## as bound/unbound methods should be done in objspace?!
+
+## """
+
+## def __init__(self, *args):
+## InterpretedFunction.__init__(self, *args)
+
+## def parse_args(self, frame, w_args, w_kwargs):
+## """ fills in "self" arg and dispatch to InterpreterFunction.
+## """
+## space = self.space
+## args_w = space.unpacktuple(w_args)
+## args_w = [space.wrap(self)] + args_w
+## w_args = space.newtuple(args_w)
+## return InterpretedFunction.parse_args(self, frame, w_args, w_kwargs)
+
+##class AppVisibleModule:
+## """ app-level visible Module defined at interpreter-level.
+
+## Inherit from this class if you want to have a module that accesses
+## the PyPy interpreter (e.g. builtins like 'locals()' require accessing the
+## frame). You can mix in application-level code by prefixing your method
+## with 'app_'. Both non-underscore methods and app-level methods will
+## be available on app-level with their respective name.
+
+## Note that app-level functions don't get a 'self' argument because it doesn't
+## make sense and we really only need the function (there is no notion of beeing
+## 'bound' or 'unbound' for them).
+
+## """
+## def __init__(self, space):
+## self.space = space
+
+## space = self.space
+## modname = self.__class__.__name__
+## self.w___name__ = space.wrap(modname)
+## self._wrapped = _wrapped = space.newmodule(self.w___name__)
+
+## # go through all items in the module class instance
+## for name in dir(self):
+## # skip spurious info and internal methods
+## if name == '__module__' or name.startswith('_') and not name.endswith('_'):
+## #print modname, "skipping", name
+## continue
+## obj = getattr(self, name)
+## # see if we just need to expose an already wrapped value
+## if name.startswith('w_'):
+## space.setattr(_wrapped, space.wrap(name[2:]), obj)
+
+## # see if have something defined at app-level
+## elif name.startswith('app_'):
+## obj = self.__class__.__dict__.get(name)
+## name = name[4:]
+## w_res = wrap_applevel(space, name, obj)
+## # nope then we must expose interpreter-level to app-level
+## else:
+## w_res = wrap_interplevel(space, name, obj)
+## setattr(self, 'w_'+name, w_res)
+## w_name = space.wrap(name)
+## space.setattr(_wrapped, w_name, w_res)
+
+##def wrap_applevel(space, name, obj):
+## """ wrap an app-level style object which was compiled at interp-level. """
+## if hasattr(obj, 'func_code'):
+## return space.wrap(InterpretedFunction(space, obj))
+## elif inspect.isclass(obj):
+## # XXX currently (rev 1020) unused, but it may be useful
+## # to define builtin app-level classes at interp-level.
+## return wrap_applevel_class(space, name, obj)
+## else:
+## raise ValueError, "cannot wrap %s, %s" % (name, obj)
+
+##def wrap_applevel_class(space, name, obj):
+## """ construct an app-level class by reproducing the
+## source definition and running it through the interpreter.
+## It's a bit ugly but i don't know a better way (holger).
+## """
+## assert 1!=1, "Oh you want to use this function?"
+## l = ['class %s:' % name]
+## indent = ' '
+## for key, value in vars(obj).items():
+## if hasattr(value, 'func_code'):
+## s = inspect.getsource(value)
+## l.append(s)
+## indent = " " * (len(s) - len(s.lstrip()))
+
+## if getattr(obj, '__doc__', None):
+## l.insert(1, indent + obj.__doc__)
+
+## for key, value in vars(obj).items():
+## if not key in ('__module__', '__doc__'):
+## if isinstance(value, (str, int, float, tuple, list)):
+## l.append('%s%s = %r' % (indent, key, value))
+
+## s = "\n".join(l)
+## code = compile(s, s, 'exec')
+## scopedcode = ScopedCode(space, code, None)
+## scopedcode.eval_frame()
+## w_name = space.wrap(name)
+## w_res = space.getitem(scopedcode.w_globals, w_name)
+## return w_res
+
+
+##def wrap_interplevel(space, name, obj):
+## """ make an interp-level object accessible on app-level. """
+## return space.wrap(obj)
+
+#### Cells (used for nested scopes only) ##
+
+##_NULL = object() # Marker object
+
+##class Cell:
+## def __init__(self, w_value=_NULL):
+## self.w_value = w_value
+
+## def clone(self):
+## return self.__class__(self.w_value)
+
+## def get(self):
+## if self.w_value is _NULL:
+## raise ValueError, "get() from an empty cell"
+## return self.w_value
+
+## def set(self, w_value):
+## self.w_value = w_value
+
+## def delete(self):
+## if self.w_value is _NULL:
+## raise ValueError, "make_empty() on an empty cell"
+## self.w_value = _NULL
+
+## def __repr__(self):
+## """ representation for debugging purposes """
+## if self.w_value is _NULL:
+## return "%s()" % self.__class__.__name__
+## else:
+## return "%s(%s)" % (self.__class__.__name__, self.w_value)
Copied: pypy/branch/builtinrefactor/pypy/interpreter/nestedscope.py (from rev 1264, pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py)
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/nestedscope.py Sun Aug 10 21:34:26 2003
@@ -1,4 +1,5 @@
-from pypy.interpreter.pyfastscope import PyFastScopeFrame, UNDEFINED
+from pypy.interpreter.eval import UNDEFINED
+from pypy.interpreter.pyopcode import PyInterpFrame
class Cell(object):
@@ -36,7 +37,7 @@
content, id(self))
-class PyNestedScopeFrame(PyFastScopeFrame):
+class PyNestedScopeFrame(PyInterpFrame):
"""This class enhances a standard frame with nested scope abilities,
i.e. handling of cell/free variables."""
@@ -47,14 +48,23 @@
# 'closure' is a list of Cell instances: the received free vars.
def __init__(self, space, code, w_globals, closure):
- PyFastScopeFrame.__init__(self, space, code, w_globals, closure)
+ PyInterpFrame.__init__(self, space, code, w_globals, closure)
ncellvars = len(code.co_cellvars)
nfreevars = len(code.co_freevars)
+ if closure is None:
+ if nfreevars:
+ raise OperationError(space.w_TypeError,
+ "directly executed code object "
+ "may not contain free variables")
+ else:
+ if len(closure) != nfreevars:
+ raise ValueError("code object received a closure with "
+ "an unexpected number of free variables")
self.cells = [Cell() for i in range(ncellvars)] + closure
def fast2locals(self):
- PyFastScopeFrame.fast2locals(self)
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
+ PyInterpFrame.fast2locals(self)
+ freevarnames = self.code.co_cellvars + self.code.co_freevars
for name, cell in zip(freevarnames, self.cells):
try:
w_value = cell.get()
@@ -65,8 +75,8 @@
self.space.setitem(self.w_locals, w_name, w_value)
def locals2fast(self):
- PyFastScopeFrame.locals2fast(self)
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
+ PyInterpFrame.locals2fast(self)
+ freevarnames = self.code.co_cellvars + self.code.co_freevars
for name, cell in zip(freevarnames, self.cells):
w_name = self.space.wrap(name)
try:
@@ -78,11 +88,11 @@
cell.set(w_value)
def setfastscope(self, scope_w):
- PyFastScopeFrame.setfastscope(scope_w)
- if self.bytecode.co_cellvars:
+ PyInterpFrame.setfastscope(scope_w)
+ if self.code.co_cellvars:
# the first few cell vars could shadow already-set arguments,
# in the same order as they appear in co_varnames
- code = self.bytecode
+ code = self.code
argvars = code.co_varnames
cellvars = code.co_cellvars
next = 0
@@ -99,12 +109,12 @@
break # all cell vars initialized this way
def getfreevarname(self, index):
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
+ freevarnames = self.code.co_cellvars + self.code.co_freevars
return freevarnames[index]
def iscellvar(self, index):
# is the variable given by index a cell or a free var?
- return index < len(self.bytecode.co_cellvars)
+ return index < len(self.code.co_cellvars)
### extra opcodes ###
Modified: pypy/branch/builtinrefactor/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pycode.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/pycode.py Sun Aug 10 21:34:26 2003
@@ -5,9 +5,6 @@
"""
from pypy.interpreter import eval
-from pypy.interpreter.pyopcode import PyOperationalFrame
-from pypy.interpreter.pyfastscope import PyFastScopeFrame
-from pypy.interpreter.pynestedscope import PyNestedScopeFrame
# code object contants, for co_flags below
@@ -64,14 +61,12 @@
def create_frame(self, space, w_globals, closure=None):
"Create an empty PyFrame suitable for this code object."
- # select the appropriate kind of frame; see below
+ # select the appropriate kind of frame
if self.co_cellvars or self.co_freevars:
- frameclass = PyNestedScopeFrame
- elif self.co_nlocals:
- frameclass = PyFastScopeFrame
+ from pypy.interpreter.nestedscope import PyNestedScopeFrame as F
else:
- frameclass = PyOperationalFrame
- return frameclass(space, self, w_globals, closure)
+ from pypy.interpreter.pyopcode import PyInterpFrame as F
+ return F(space, self, w_globals, closure)
def signature(self):
"([list-of-arg-names], vararg-name-or-None, kwarg-name-or-None)."
@@ -89,17 +84,8 @@
kwargname = None
return argnames, varargname, kwargname
- def getargcount(self):
- count = self.co_argcount
- if self.co_flags & CO_VARARGS:
- count += 1
- if self.co_flags & CO_VARKEYWORDS:
- count += 1
- return count
-
- def getlocalvarname(self, index):
- # nb. this is duplicated in PyFastScopeFrame.getlocalvarname()
- return self.co_varnames[index]
+ def getvarnames(self):
+ return self.co_varnames
def is_generator(self):
return self.co_flags & CO_GENERATOR
Deleted: /pypy/branch/builtinrefactor/pypy/interpreter/pyfastscope.py
==============================================================================
--- /pypy/branch/builtinrefactor/pypy/interpreter/pyfastscope.py Sun Aug 10 21:34:26 2003
+++ (empty file)
@@ -1,88 +0,0 @@
-from pypy.interpreter.pyopcode import PyOperationalFrame
-
-
-UNDEFINED = object() # marker for undefined local variables
-
-
-class PyFastScopeFrame(PyOperationalFrame):
- "A PyFrame that knows about fast scopes."
-
- # this is the class that knows about "fast locals", i.e.
- # the fact that local variables are better represented as an array
- # of values accessed by index (by the LOAD_FAST, STORE_FAST and
- # DELETE_FAST opcodes).
-
- def __init__(self, space, code, w_globals, closure):
- PyOperationalFrame.__init__(self, space, code, w_globals, closure)
- self.locals_w = [UNDEFINED] * code.co_nlocals
-
- def getlocalvarname(self, index):
- return self.bytecode.co_varnames[index]
-
- def getdictlocals(self):
- self.fast2locals()
- return self.w_locals
-
- def setdictlocals(self, w_locals):
- self.w_locals = w_locals
- self.locals2fast()
-
- def setfastlocals(self, scope_w):
- self.locals_w[:len(scope_w)] = scope_w
-
- def fast2locals(self):
- # Copy values from self.locals_w to self.w_locals
- if self.w_locals is None:
- self.w_locals = self.space.newdict([])
- for name, w_value in zip(self.bytecode.co_varnames, self.locals_w):
- if w_value is not UNDEFINED:
- w_name = self.space.wrap(name)
- self.space.setitem(self.w_locals, w_name, w_value)
-
- def locals2fast(self):
- # Copy values from self.w_locals to self.locals_w
- for i in range(self.bytecode.co_nlocals):
- w_name = self.space.wrap(self.bytecode.co_varnames[i])
- try:
- w_value = self.space.getitem(self.w_locals, w_name)
- except OperationError, e:
- if not e.match(self.space, self.space.w_KeyError):
- raise
- else:
- self.locals_w[i] = w_value
-
- ### extra opcodes ###
-
- def LOAD_FAST(f, varindex):
- # access a local variable directly
- w_value = f.locals_w[varindex]
- if w_value is UNDEFINED:
- varname = f.getlocalvarname(varindex)
- message = "local variable '%s' referenced before assignment" % varname
- raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
- f.valuestack.push(w_value)
-
- def STORE_FAST(f, varindex):
- try:
- w_newvalue = f.valuestack.pop()
- f.locals_w[varindex] = w_newvalue
- except:
- print "exception: got index error"
- print " varindex:", varindex
- print " len(locals_w)", len(f.locals_w)
- import dis
- print dis.dis(f.bytecode)
- print "co_varnames", f.bytecode.co_varnames
- print "co_nlocals", f.bytecode.co_nlocals
- raise
-
- def DELETE_FAST(f, varindex):
- w_value = f.locals_w[varindex]
- if f.locals_w[varindex] is UNDEFINED:
- varname = f.getlocalvarname(varindex)
- message = "local variable '%s' referenced before assignment" % varname
- raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
- f.locals_w[varindex] = UNDEFINED
-
-
-PyFastScopeFrame.setup_dispatch_table()
Modified: pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py Sun Aug 10 21:34:26 2003
@@ -3,8 +3,8 @@
from pypy.interpreter.executioncontext import Stack
from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import app2interp
from pypy.interpreter import eval, baseobjspace
+from pypy.interpreter.gateway import noglobals
class PyFrame(eval.Frame):
@@ -15,7 +15,7 @@
Public fields:
* 'space' is the object space this frame is running in
- * 'bytecode' is the PyCode object this frame runs
+ * 'code' is the PyCode object this frame runs
* 'w_locals' is the locals dictionary to use
* 'w_globals' is the attached globals dictionary
* 'w_builtins' is the attached built-ins dictionary
@@ -24,7 +24,6 @@
def __init__(self, space, code, w_globals, closure):
eval.Frame.__init__(self, space, code, w_globals)
- self.bytecode = code # Misnomer; this is really like a code object
self.valuestack = Stack()
self.blockstack = Stack()
self.last_exception = None
@@ -81,31 +80,6 @@
w_exitvalue = e.args[0]
return w_exitvalue
- ### opcode dispatch ###
-
- # 'dispatch_table' is a class attribute: a list of functions.
- # Currently, it is always created by setup_dispatch_table in pyopcode.py
- # but it could be a custom table.
-
- def dispatch(self):
- opcode = self.nextop()
- fn = self.dispatch_table[opcode]
- if fn.has_arg:
- oparg = self.nextarg()
- fn(self, oparg)
- else:
- fn(self)
-
- def nextop(self):
- c = self.bytecode.co_code[self.next_instr]
- self.next_instr += 1
- return ord(c)
-
- def nextarg(self):
- lo = self.nextop()
- hi = self.nextop()
- return (hi<<8) + lo
-
### exception stack ###
def clean_exceptionstack(self):
@@ -171,40 +145,37 @@
# push the exception to the value stack for inspection by the
# exception handler (the code after the except:)
operationerr = unroller.args[0]
+ operationerr.normalize(frame.space)
# the stack setup is slightly different than in CPython:
# instead of the traceback, we store the unroller object,
# wrapped.
frame.valuestack.push(frame.space.wrap(unroller))
-
- s = frame.space
- w_value = operationerr.w_value
- w_type = operationerr.w_type
-## import pdb
-## pdb.set_trace()
-## print w_type, `w_value`, frame.bytecode.co_name
- self.space = s # needed for the following call
- w_res = self.normalize_exception(w_type, w_value)
- w_value = s.getitem(w_res, s.wrap(1))
-
- frame.valuestack.push(w_value)
- frame.valuestack.push(w_type)
+ frame.valuestack.push(operationerr.w_value)
+ frame.valuestack.push(operationerr.w_type)
frame.next_instr = self.handlerposition # jump to the handler
raise StopUnrolling
- def app_normalize_exception(etype, evalue):
- # mistakes here usually show up as infinite recursion, which is fun.
- if isinstance(evalue, etype):
- return etype, evalue
- if isinstance(etype, type) and issubclass(etype, Exception):
- if evalue is None:
- evalue = ()
- elif not isinstance(evalue, tuple):
- evalue = (evalue,)
- evalue = etype(*evalue)
- else:
- raise Exception, "?!" # XXX
+def app_normalize_exception(etype, evalue):
+ # XXX should really be defined as a method on OperationError,
+ # but this is not so easy because OperationError cannot be
+ # at the same time an old-style subclass of Exception and a
+ # new-style subclass of Wrappable :-(
+ # moreover, try importing gateway from errors.py and you'll see :-(
+
+ # mistakes here usually show up as infinite recursion, which is fun.
+ if isinstance(evalue, etype):
return etype, evalue
- normalize_exception = app2interp(app_normalize_exception)
+ if isinstance(etype, type) and issubclass(etype, Exception):
+ if evalue is None:
+ evalue = ()
+ elif not isinstance(evalue, tuple):
+ evalue = (evalue,)
+ evalue = etype(*evalue)
+ else:
+ raise Exception, "?!" # XXX
+ return etype, evalue
+normalize_exception = noglobals.app2interp(app_normalize_exception)
+
class FinallyBlock(FrameBlock):
"""A try:finally: block. Stores the position of the exception handler."""
@@ -286,7 +257,7 @@
"""Signals a 'return' statement.
Argument is the wrapped object to return."""
def emptystack(self, frame):
- if frame.bytecode.is_generator():
+ if frame.code.is_generator():
raise baseobjspace.NoValue
w_returnvalue = self.args[0]
raise ExitFrame(w_returnvalue)
Deleted: /pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py
==============================================================================
--- /pypy/branch/builtinrefactor/pypy/interpreter/pynestedscope.py Sun Aug 10 21:34:26 2003
+++ (empty file)
@@ -1,160 +0,0 @@
-from pypy.interpreter.pyfastscope import PyFastScopeFrame, UNDEFINED
-
-
-class Cell(object):
- "A simple container for a wrapped value."
-
- def __init__(self, w_value=UNDEFINED):
- self.w_value = w_value
-
- def clone(self):
- return self.__class__(self.w_value)
-
- def empty(self):
- return self.w_value is UNDEFINED
-
- def get(self):
- if self.w_value is UNDEFINED:
- raise ValueError, "get() from an empty cell"
- return self.w_value
-
- def set(self, w_value):
- self.w_value = w_value
-
- def delete(self):
- if self.w_value is UNDEFINED:
- raise ValueError, "delete() on an empty cell"
- self.w_value = UNDEFINED
-
- def __repr__(self):
- """ representation for debugging purposes """
- if self.w_value is UNDEFINED:
- content = ""
- else:
- content = repr(self.w_value)
- return "<%s(%s) at 0x%x>" % (self.__class__.__name__,
- content, id(self))
-
-
-class PyNestedScopeFrame(PyFastScopeFrame):
- """This class enhances a standard frame with nested scope abilities,
- i.e. handling of cell/free variables."""
-
- # Cell Vars:
- # my local variables that are exposed to my inner functions
- # Free Vars:
- # variables coming from a parent function in which i'm nested
- # 'closure' is a list of Cell instances: the received free vars.
-
- def __init__(self, space, code, w_globals, closure):
- PyFastScopeFrame.__init__(self, space, code, w_globals, closure)
- ncellvars = len(code.co_cellvars)
- nfreevars = len(code.co_freevars)
- self.cells = [Cell() for i in range(ncellvars)] + closure
-
- def fast2locals(self):
- PyFastScopeFrame.fast2locals(self)
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
- for name, cell in zip(freevarnames, self.cells):
- try:
- w_value = cell.get()
- except ValueError:
- pass
- else:
- w_name = self.space.wrap(name)
- self.space.setitem(self.w_locals, w_name, w_value)
-
- def locals2fast(self):
- PyFastScopeFrame.locals2fast(self)
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
- for name, cell in zip(freevarnames, self.cells):
- w_name = self.space.wrap(name)
- try:
- w_value = self.space.getitem(self.w_locals, w_name)
- except OperationError, e:
- if not e.match(self.space, self.space.w_KeyError):
- raise
- else:
- cell.set(w_value)
-
- def setfastscope(self, scope_w):
- PyFastScopeFrame.setfastscope(scope_w)
- if self.bytecode.co_cellvars:
- # the first few cell vars could shadow already-set arguments,
- # in the same order as they appear in co_varnames
- code = self.bytecode
- argvars = code.co_varnames
- cellvars = code.co_cellvars
- next = 0
- nextname = cellvars[0]
- for i in range(len(scope_w)):
- if argvars[i] == nextname:
- # argument i has the same name as the next cell var
- w_value = scope_w[i]
- self.cells[next] = Cell(w_value)
- next += 1
- try:
- nextname = cellvars[next]
- except IndexError:
- break # all cell vars initialized this way
-
- def getfreevarname(self, index):
- freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
- return freevarnames[index]
-
- def iscellvar(self, index):
- # is the variable given by index a cell or a free var?
- return index < len(self.bytecode.co_cellvars)
-
- ### extra opcodes ###
-
- def LOAD_CLOSURE(f, varindex):
- # nested scopes: access the cell object
- cell = f.cells[varindex]
- w_value = f.space.wrap(cell)
- f.valuestack.push(w_value)
-
- def LOAD_DEREF(f, varindex):
- # nested scopes: access a variable through its cell object
- cell = f.cells[varindex]
- try:
- w_value = cell.get()
- except ValueError:
- varname = f.getfreevarname(varindex)
- if f.iscellvar(varindex):
- message = "local variable '%s' referenced before assignment"
- w_exc_type = f.space.w_UnboundLocalError
- else:
- message = ("free variable '%s' referenced before assignment"
- " in enclosing scope")
- w_exc_type = f.space.w_NameError
- raise OperationError(w_exc_type, f.space.wrap(message % varname))
- else:
- f.valuestack.push(w_value)
-
- def STORE_DEREF(f, varindex):
- # nested scopes: access a variable through its cell object
- w_newvalue = f.valuestack.pop()
- #try:
- cell = f.cells[varindex]
- #except IndexError:
- # import pdb; pdb.set_trace()
- # raise
- cell.set(w_newvalue)
-
- def MAKE_CLOSURE(f, numdefaults):
- w_codeobj = f.valuestack.pop()
- codeobj = f.space.unwrap(w_codeobj)
- nfreevars = len(codeobj.co_freevars)
- freevars = [f.valuestack.pop() for i in range(nfreevars)]
- freevars.reverse()
- w_freevars = f.space.newtuple(freevars)
- defaultarguments = [f.valuestack.pop() for i in range(numdefaults)]
- defaultarguments.reverse()
- w_defaultarguments = f.space.newtuple(defaultarguments)
- w_func = f.space.newfunction(f.space.unwrap(w_codeobj),
- f.w_globals, w_defaultarguments, w_freevars)
- f.valuestack.push(w_func)
-
-
-PyNestedScopeFrame.setup_dispatch_table()
Modified: pypy/branch/builtinrefactor/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pyopcode.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/pyopcode.py Sun Aug 10 21:34:26 2003
@@ -30,17 +30,49 @@
f.valuestack.push(w_result)
-class PyOperationalFrame(PyFrame):
- """A PyFrame that knows about all operational Python opcodes.
- It does not know about 'fast variables' nor 'nested scopes'."""
+class PyInterpFrame(PyFrame):
+ """A PyFrame that knows about interpretation of standard Python opcodes,
+ with the exception of nested scopes."""
+
+ def __init__(self, space, code, w_globals, closure):
+ PyFrame.__init__(self, space, code, w_globals, closure,
+ code.co_nlocals) # size of fastlocals_w array
+
+ ### opcode dispatch ###
+
+ # 'dispatch_table' is a class attribute: a list of functions.
+ # Currently, it is always created by setup_dispatch_table in pyopcode.py
+ # but it could be a custom table.
+
+ def dispatch(self):
+ opcode = self.nextop()
+ fn = self.dispatch_table[opcode]
+ if fn.has_arg:
+ oparg = self.nextarg()
+ fn(self, oparg)
+ else:
+ fn(self)
+
+ def nextop(self):
+ c = self.code.co_code[self.next_instr]
+ self.next_instr += 1
+ return ord(c)
+
+ def nextarg(self):
+ lo = self.nextop()
+ hi = self.nextop()
+ return (hi<<8) + lo
### accessor functions ###
+ def getlocalvarname(self, index):
+ return self.code.co_varnames[index]
+
def getconstant(self, index):
- return self.bytecode.co_consts[index]
+ return self.code.co_consts[index]
def getname(self, index):
- return self.bytecode.co_names[index]
+ return self.code.co_names[index]
################################################################
## Implementation of the "operational" opcodes
@@ -50,10 +82,32 @@
# the 'self' argument of opcode implementations is called 'f'
# for historical reasons
+ def LOAD_FAST(f, varindex):
+ # access a local variable directly
+ w_value = f.fastlocals_w[varindex]
+ if w_value is UNDEFINED:
+ varname = f.getlocalvarname(varindex)
+ message = "local variable '%s' referenced before assignment" % varname
+ raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
+ f.valuestack.push(w_value)
+
def LOAD_CONST(f, constindex):
w_const = f.space.wrap(f.getconstant(constindex))
f.valuestack.push(w_const)
+ def STORE_FAST(f, varindex):
+ w_newvalue = f.valuestack.pop()
+ f.fastlocals_w[varindex] = w_newvalue
+ #except:
+ # print "exception: got index error"
+ # print " varindex:", varindex
+ # print " len(locals_w)", len(f.locals_w)
+ # import dis
+ # print dis.dis(f.code)
+ # print "co_varnames", f.code.co_varnames
+ # print "co_nlocals", f.code.co_nlocals
+ # raise
+
def POP_TOP(f):
f.valuestack.pop()
@@ -447,6 +501,13 @@
raise OperationError(w_exc_type, w_exc_value)
f.valuestack.push(w_value)
+ def DELETE_FAST(f, varindex):
+ if f.fastlocals_w[varindex] is UNDEFINED:
+ varname = f.getlocalvarname(varindex)
+ message = "local variable '%s' referenced before assignment" % varname
+ raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
+ f.fastlocals_w[varindex] = UNDEFINED
+
def BUILD_TUPLE(f, itemcount):
items = [f.valuestack.pop() for i in range(itemcount)]
items.reverse()
@@ -674,4 +735,4 @@
setup_dispatch_table = classmethod(setup_dispatch_table)
-PyOperationalFrame.setup_dispatch_table()
+PyInterpFrame.setup_dispatch_table()
Modified: pypy/branch/builtinrefactor/pypy/interpreter/unittest_w.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/unittest_w.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/unittest_w.py Sun Aug 10 21:34:26 2003
@@ -2,7 +2,8 @@
import sys, os
import unittest
-from pypy.interpreter.gateway import InterpretedMethod, InterpretedFunction
+#from pypy.interpreter.gateway import InterpretedMethod, InterpretedFunction
+# FIX ME FIX ME FIX ME
def make_testcase_class(space, tc_w):
# XXX this is all a bit insane (but it works)
More information about the Pypy-commit
mailing list