aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pypy/interpreter/gateway.py')
-rw-r--r--pypy/interpreter/gateway.py348
1 files changed, 0 insertions, 348 deletions
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
deleted file mode 100644
index 027239f8fd..0000000000
--- a/pypy/interpreter/gateway.py
+++ /dev/null
@@ -1,348 +0,0 @@
-"""
-
-Gateway between app-level and interpreter-level:
-* BuiltinCode (call interp-level code from app-level)
-* Gateway (a space-independent gateway to a Code object)
-* app2interp (embed an app-level function into an interp-level callable)
-* interp2app (publish an interp-level object to be visible from app-level)
-* exportall (mass-call interp2app on a whole dict of objects)
-* importall (mass-call app2interp on a whole dict of objects)
-
-"""
-
-import types, sys
-from pypy.interpreter.error import OperationError
-from pypy.interpreter import eval, pycode
-from pypy.interpreter.function import Function, Method
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.argument import Arguments
-from pypy.tool.cache import Cache
-
-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, ismethod=None, spacearg=None):
- "NOT_RPYTHON"
- # '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
- self.docstring = func.__doc__
- # extract the signature from the (CPython-level) code object
- tmp = pycode.PyCode(None)
- tmp._from_code(func.func_code)
- # signature-based hacks: renaming arguments from w_xyz to xyz.
- # Currently we enforce the following signature tricks:
- # * the first arg must be either 'self' or 'space'
- # * 'w_' prefixes for the rest
- # * '_w' suffix for the optional '*' argument
- # * alternatively a final '__args__' means an Arguments()
- # Not exactly a clean approach XXX.
- argnames, varargname, kwargname = tmp.signature()
- argnames = list(argnames)
- lookslikemethod = argnames[:1] == ['self']
- if ismethod is None:
- ismethod = lookslikemethod
- if spacearg is None:
- spacearg = not lookslikemethod
- self.ismethod = ismethod
- self.spacearg = spacearg
- if spacearg:
- del argnames[0]
-
- assert kwargname is None, (
- "built-in function %r should not take a ** argument" % func)
-
- self.generalargs = argnames[-1:] == ['__args__']
- self.starargs = varargname is not None
- assert not (self.generalargs and self.starargs), (
- "built-in function %r has both __args__ and a * argument" % func)
- if self.generalargs:
- del argnames[-1]
- varargname = "args"
- kwargname = "keywords"
- elif self.starargs:
- assert varargname.endswith('_w'), (
- "argument *%s of built-in function %r should end in '_w'" %
- (varargname, func))
- varargname = varargname[:-2]
-
- for i in range(ismethod, len(argnames)):
- a = argnames[i]
- assert a.startswith('w_'), (
- "argument %s of built-in function %r should "
- "start with 'w_'" % (a, func))
- argnames[i] = a[2:]
-
- self.sig = argnames, varargname, kwargname
- self.minargs = len(argnames)
- if self.starargs:
- self.maxargs = sys.maxint
- else:
- self.maxargs = self.minargs
-
- def create_frame(self, space, w_globals, closure=None):
- return BuiltinFrame(space, self, w_globals)
-
- def signature(self):
- return self.sig
-
- def getdocstring(self):
- return self.docstring
-
-
-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 setfastscope(self, scope_w):
- argarray = list(scope_w)
- if self.code.generalargs:
- w_kwds = argarray.pop()
- w_args = argarray.pop()
- argarray.append(Arguments.frompacked(self.space, w_args, w_kwds))
- elif self.code.starargs:
- w_args = argarray.pop()
- argarray += self.space.unpacktuple(w_args)
- if self.code.ismethod:
- argarray[0] = self.space.unwrap(argarray[0])
- self.argarray = argarray
-
- def getfastscope(self):
- raise OperationError(self.space.w_TypeError,
- self.space.wrap("cannot get fastscope of a BuiltinFrame"))
-
- def run(self):
- argarray = self.argarray
- if self.code.spacearg:
- w_result = self.code.func(self.space, *argarray)
- else:
- w_result = self.code.func(*argarray)
- if w_result is None:
- w_result = self.space.w_None
- return w_result
-
-
-class Gateway(Wrappable):
- """General-purpose utility for the interpreter-level to create callables
- that transparently invoke code objects (and thus possibly interpreted
- app-level code)."""
-
- # This is similar to a Function object, but not bound to a particular
- # object space. During the call, the object space is either given
- # explicitly as the first argument (for plain function), or is read
- # from 'self.space' for methods.
-
- # after initialization the following attributes should be set
- # name
- # code
- # _staticglobals
- # _staticdefs
-
- NOT_RPYTHON_ATTRIBUTES = ['_staticglobals', '_staticdefs']
-
- def __spacebind__(self, space):
- # to wrap a Gateway, we first make a real Function object out of it
- # and the result is a wrapped version of this Function.
- return self.get_function(space)
-
- def get_function(self, space):
- return space.loadfromcache(self,
- Gateway.build_all_functions,
- self.getcache(space))
-
- def build_all_functions(self, space):
- "NOT_RPYTHON"
- # the construction is supposed to be done only once in advance,
- # but must be done lazily when needed only, because
- # 1) it depends on the object space
- # 2) the w_globals must not be built before the underlying
- # _staticglobals is completely initialized, because
- # w_globals must be built only once for all the Gateway
- # instances of _staticglobals
- if self._staticglobals is None:
- w_globals = None
- else:
- # is there another Gateway in _staticglobals for which we
- # already have a w_globals for this space ?
- cache = self.getcache(space)
- for value in self._staticglobals.itervalues():
- if isinstance(value, Gateway):
- if value in cache.content:
- # yes, we share its w_globals
- fn = cache.content[value]
- w_globals = fn.w_func_globals
- break
- else:
- # no, we build all Gateways in the _staticglobals now.
- w_globals = build_dict(self._staticglobals, space)
- return self._build_function(space, w_globals)
-
- def getcache(self, space):
- return space._gatewaycache
-
- def _build_function(self, space, w_globals):
- "NOT_RPYTHON"
- cache = self.getcache(space)
- try:
- return cache.content[self]
- except KeyError:
- defs = self.getdefaults(space) # needs to be implemented by subclass
- fn = Function(space, self.code, w_globals, defs, forcename = self.name)
- cache.content[self] = fn
- return fn
-
- def get_method(self, obj):
- # to get the Gateway as a method out of an instance, we build a
- # Function and get it.
- # the object space is implicitely fetched out of the instance
- if isinstance(self.code, BuiltinCode):
- assert self.code.ismethod, (
- 'global built-in function %r used as method' %
- self.code.func)
- space = obj.space
- fn = self.get_function(space)
- w_obj = space.wrap(obj)
- return Method(space, space.wrap(fn),
- w_obj, space.type(w_obj))
-
-
-class app2interp(Gateway):
- """Build a Gateway that calls 'app' at app-level."""
- def __init__(self, app, app_name=None):
- "NOT_RPYTHON"
- Gateway.__init__(self)
- # app must be a function whose name starts with 'app_'.
- if not isinstance(app, types.FunctionType):
- raise TypeError, "function expected, got %r instead" % app
- if app_name is None:
- if not app.func_name.startswith('app_'):
- raise ValueError, ("function name must start with 'app_'; "
- "%r does not" % app.func_name)
- app_name = app.func_name[4:]
- self.name = app_name
- self.code = pycode.PyCode(None)
- self.code._from_code(app.func_code)
- self._staticglobals = app.func_globals
- self._staticdefs = list(app.func_defaults or ())
-
- def getdefaults(self, space):
- "NOT_RPYTHON"
- return [space.wrap(val) for val in self._staticdefs]
-
- def __call__(self, space, *args_w):
- # to call the Gateway as a non-method, 'space' must be explicitly
- # supplied. We build the Function object and call it.
- fn = self.get_function(space)
- return space.call_function(space.wrap(fn), *args_w)
-
- def __get__(self, obj, cls=None):
- "NOT_RPYTHON"
- if obj is None:
- return self
- else:
- space = obj.space
- w_method = space.wrap(self.get_method(obj))
- def helper_method_caller(*args_w):
- return space.call_function(w_method, *args_w)
- return helper_method_caller
-
-class interp2app(Gateway):
- """Build a Gateway that calls 'f' at interp-level."""
- def __init__(self, f, app_name=None):
- "NOT_RPYTHON"
- Gateway.__init__(self)
- # f must be a function whose name does NOT starts with 'app_'
- if not isinstance(f, types.FunctionType):
- raise TypeError, "function expected, got %r instead" % f
- if app_name is None:
- if f.func_name.startswith('app_'):
- raise ValueError, ("function name %r suspiciously starts "
- "with 'app_'" % f.func_name)
- app_name = f.func_name
- self.code = BuiltinCode(f)
- self.name = app_name
- self._staticdefs = list(f.func_defaults or ())
- self._staticglobals = None
-
- def getdefaults(self, space):
- "NOT_RPYTHON"
- return self._staticdefs
-
-def exportall(d, temporary=False):
- """NOT_RPYTHON: Publish every function from a dict."""
- if temporary:
- i2a = interp2app_temp
- else:
- i2a = interp2app
- for name, obj in d.items():
- if isinstance(obj, types.FunctionType):
- # names starting in 'app_' are supposedly already app-level
- if name.startswith('app_'):
- continue
- # ignore tricky functions with another interp-level meaning
- if name in ('__init__', '__new__'):
- continue
- # ignore names in '_xyz'
- if name.startswith('_') and not name.endswith('_'):
- continue
- if 'app_'+name not in d:
- d['app_'+name] = i2a(obj, name)
-
-def export_values(space, dic, w_namespace):
- "NOT_RPYTHON"
- for name, w_value in dic.items():
- if name.startswith('w_'):
- if name == 'w_dict':
- w_name = space.wrap('__dict__')
- elif name == 'w_name':
- w_name = space.wrap('__name__')
- else:
- w_name = space.wrap(name[2:])
- space.setitem(w_namespace, w_name, w_value)
-
-def importall(d, temporary=False):
- """NOT_RPYTHON: Import all app_-level functions as Gateways into a dict."""
- if temporary:
- a2i = app2interp_temp
- else:
- a2i = app2interp
- for name, obj in d.items():
- if name.startswith('app_') and name[4:] not in d:
- if isinstance(obj, types.FunctionType):
- d[name[4:]] = a2i(obj, name[4:])
-
-def build_dict(d, space):
- """NOT_RPYTHON:
- Search all Gateways and put them into a wrapped dictionary."""
- w_globals = space.newdict([])
- for value in d.itervalues():
- if isinstance(value, Gateway):
- fn = value._build_function(space, w_globals)
- w_name = space.wrap(value.name)
- w_object = space.wrap(fn)
- space.setitem(w_globals, w_name, w_object)
- if hasattr(space, 'w_sys'): # give them 'sys' if it exists already
- space.setitem(w_globals, space.wrap('sys'), space.w_sys)
- return w_globals
-
-
-#
-# the next gateways are to be used only for
-# temporary/initialization purposes
-class app2interp_temp(app2interp):
- "NOT_RPYTHON"
- def getcache(self, space):
- return self.__dict__.setdefault(space, Cache())
- # ^^^^^
- # armin suggested this
-
-class interp2app_temp(interp2app):
- "NOT_RPYTHON"
- def getcache(self, space):
- return self.__dict__.setdefault(space, Cache())