[pypy-svn] rev 1003 - in pypy/trunk/src/pypy: interpreter objspace/std
arigo at codespeak.net
arigo at codespeak.net
Mon Jun 23 16:57:23 CEST 2003
Author: arigo
Date: Mon Jun 23 16:57:22 2003
New Revision: 1003
Modified:
pypy/trunk/src/pypy/interpreter/baseobjspace.py
pypy/trunk/src/pypy/objspace/std/default.py
pypy/trunk/src/pypy/objspace/std/objspace.py
pypy/trunk/src/pypy/objspace/std/typeobject.py
pypy/trunk/src/pypy/objspace/std/userobject.py
Log:
Clean-up of the interfaces between multimethods and Python special
__xxx__ methods, in both directions.
M /home/arigo/python/pypy/pypy/trunk/src/pypy/interpreter/baseobjspace.py
nonzero multimethod removed, next (iterators) made special
M /home/arigo/python/pypy/pypy/trunk/src/pypy/objspace/std/userobject.py
properly translate Python results into multimethod-like results
M /home/arigo/python/pypy/pypy/trunk/src/pypy/objspace/std/default.py
is_true falls back to len, nonzero removed
M /home/arigo/python/pypy/pypy/trunk/src/pypy/objspace/std/typeobject.py
properly export and translate multimethod results to Python
M /home/arigo/python/pypy/pypy/trunk/src/pypy/objspace/std/objspace.py
next is now a special multimethod
Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Mon Jun 23 16:57:22 2003
@@ -195,7 +195,6 @@
('and_', '&', 2, ['__and__', '__rand__']),
('or_', '|', 2, ['__or__', '__ror__']),
('xor', '^', 2, ['__xor__', '__rxor__']),
- ('nonzero', 'nonzero', 1, ['__nonzero__']),
('int', 'int', 1, ['__int__']),
('float', 'float', 1, ['__float__']),
('inplace_add', '+=', 2, ['__iadd__']),
@@ -219,7 +218,6 @@
('ge', '>=', 2, ['__ge__', '__le__']),
('contains', 'contains', 2, ['__contains__']),
('iter', 'iter', 1, ['__iter__']),
- ('next', 'next', 1, ['next']), # iterator interface
('call', 'call', 3, ['__call__']),
('get', 'get', 3, ['__get__']),
('set', 'set', 2, ['__set__']),
@@ -288,4 +286,5 @@
# newslice(w_start,w_stop,w_end) -> w_slice (w_end may be a real None)
# newfunction(...) -> w_function
# newmodule(w_name) -> w_module
+# next(w_iter) -> w_value or raise NoValue
#
Modified: pypy/trunk/src/pypy/objspace/std/default.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/default.py (original)
+++ pypy/trunk/src/pypy/objspace/std/default.py Mon Jun 23 16:57:22 2003
@@ -35,10 +35,15 @@
def not__ANY(space, w_obj):
return space.newbool(not space.is_true(w_obj))
-# everything is True unless otherwise specified
+
+# __nonzero__ falls back to __len__
def is_true__ANY(space, w_obj):
- return True
+ try:
+ w_len = space.len.perform_call((w_obj,))
+ except FailedToImplement:
+ return True # everything is True unless otherwise specified
+ return space.is_true(space.ne(w_len, space.newint(0)))
# in-place operators fall back to their non-in-place counterpart
@@ -73,8 +78,6 @@
def issubtype__ANY_ANY(space, w_one, w_two):
# XXX -- mwh
return space.newbool(0)
-
-def nonzero__ANY(space, w_obj):
- return space.newbool(space.is_true(w_obj))
+ # XXX why is it there ? -- Armin
register_all(vars())
Modified: pypy/trunk/src/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/objspace.py (original)
+++ pypy/trunk/src/pypy/objspace/std/objspace.py Mon Jun 23 16:57:22 2003
@@ -277,6 +277,7 @@
is_data_descr = MultiMethod('is_data_descr', 1, []) # returns an unwrapped bool
getdict = MultiMethod('getdict', 1, []) # get '.__dict__' attribute
+ next = MultiMethod('next', 1, []) # iterator interface
def is_(self, w_one, w_two):
# XXX this is a hopefully temporary speed hack:
Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/typeobject.py (original)
+++ pypy/trunk/src/pypy/objspace/std/typeobject.py Mon Jun 23 16:57:22 2003
@@ -18,15 +18,6 @@
def __init__(w_self, space):
W_Object.__init__(w_self, space)
w_self.w_tpname = space.wrap(w_self.typename)
- w_self.multimethods = {}
- # import all multimethods of the type class and of the objspace
- for multimethod in (hack_out_multimethods(w_self.__class__) +
- hack_out_multimethods(space.__class__)):
- for i in range(len(multimethod.specialnames)):
- # each PyMultimethodCode embeds a multimethod
- name = multimethod.specialnames[i]
- code = PyMultimethodCode(multimethod, w_self.__class__, i)
- w_self.multimethods[name] = code
def getbases(w_self):
parents = w_self.staticbases
@@ -58,10 +49,11 @@
def lookup_exactly_here(w_self, w_key):
space = w_self.space
+ multimethods = getmultimethods(space.__class__, w_self.__class__)
key = space.unwrap(w_key)
assert isinstance(key, str)
try:
- code = w_self.multimethods[key]
+ code = multimethods[key]
except KeyError:
raise KeyError # pass on the KeyError
if code.slice().is_empty():
@@ -83,6 +75,33 @@
result.append(value)
return result
+AllSlicedMultimethods = {}
+
+def getmultimethods(spaceclass, typeclass):
+ try:
+ multimethods = AllSlicedMultimethods[spaceclass, typeclass]
+ except KeyError:
+ multimethods = AllSlicedMultimethods[spaceclass, typeclass] = {}
+ # import all multimethods of the type class and of the objspace
+ for multimethod in (hack_out_multimethods(typeclass) +
+ hack_out_multimethods(spaceclass)):
+ for i in range(len(multimethod.specialnames)):
+ # each PyMultimethodCode embeds a multimethod
+ name = multimethod.specialnames[i]
+ if name in multimethods:
+ # conflict between e.g. __lt__ and
+ # __lt__-as-reversed-version-of-__gt__
+ code = multimethods[name]
+ if code.bound_position < i:
+ continue
+ code = PyMultimethodCode(multimethod, typeclass, i)
+ multimethods[name] = code
+ # add some more multimethods with a special interface
+ code = NextMultimethodCode(spaceclass.next, typeclass)
+ multimethods['next'] = code
+ code = NonZeroMultimethodCode(spaceclass.is_true, typeclass)
+ multimethods['__nonzero__'] = code
+ return multimethods
class PyMultimethodCode(pycode.PyBaseCode):
@@ -104,7 +123,7 @@
def slice(self):
return self.basemultimethod.slice(self.typeclass, self.bound_position)
- def eval_code(self, space, w_globals, w_locals):
+ def do_call(self, space, w_globals, w_locals):
"""Call the multimethod, ignoring all implementations that do not
have exactly the expected type at the bound_position."""
multimethod = self.slice()
@@ -113,20 +132,38 @@
w_arg = space.getitem(w_locals, space.wrap('x%d'%(i+1)))
dispatchargs.append(w_arg)
dispatchargs = tuple(dispatchargs)
+ return multimethod.get(space).perform_call(dispatchargs)
+
+ def eval_code(self, space, w_globals, w_locals):
+ "Call the multimethods, translating back information to Python."
try:
- w_result = multimethod.get(space).perform_call(dispatchargs)
+ w_result = self.do_call(space, w_globals, w_locals)
except FailedToImplement, e:
if e.args:
raise OperationError(*e.args)
else:
return space.w_NotImplemented
- except NoValue:
- raise OperationError(space.w_StopIteration, space.w_None)
- # XXX hack to accept real Nones from operations with no return value
+ # we accept a real None from operations with no return value
if w_result is None:
w_result = space.w_None
return w_result
+class NextMultimethodCode(PyMultimethodCode):
+
+ def eval_code(self, space, w_globals, w_locals):
+ "Call the next() multimethod."
+ try:
+ return self.do_call(space, w_globals, w_locals)
+ except NoValue:
+ raise OperationError(space.w_StopIteration, space.w_None)
+
+class NonZeroMultimethodCode(PyMultimethodCode):
+
+ def eval_code(self, space, w_globals, w_locals):
+ "Call the is_true() multimethods."
+ result = self.do_call(space, w_globals, w_locals)
+ return space.newbool(result)
+
def call__Type_ANY_ANY(space, w_type, w_args, w_kwds):
w_newobject = space.new(w_type, w_args, w_kwds)
Modified: pypy/trunk/src/pypy/objspace/std/userobject.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/userobject.py (original)
+++ pypy/trunk/src/pypy/objspace/std/userobject.py Mon Jun 23 16:57:22 2003
@@ -100,51 +100,72 @@
else:
return 1
-# register an implementation for all multimethods that define special names
-def user_specialmethod(space, *args_w):
- # args_w is in the standard multimethod order
- # we need it in the Python-friendly order (i.e. swapped for __rxxx__)
- args_w = list(args_w)
- w_userobj = args_w.pop(g_bound_position)
- w_args = space.newtuple(args_w)
- w_key = space.wrap(g_method_name)
- mro = space.getattr(w_userobj.w_type, space.wrap('__mro__'))
- mro = space.unpacktuple(mro)
- for w_base in mro:
- if not isinstance(w_base, W_UserType):
- continue
- try:
- w_function = w_base.lookup_exactly_here(w_key)
- except KeyError:
- continue
- w_method = space.get(w_function, w_userobj, w_base)
- w_result = space.call(w_method, w_args, space.newdict([]))
- # XXX hack to accept real Nones from operations with no return value
- if w_result is None:
- return space.w_None
- elif space.is_true(space.is_(w_result, space.w_NotImplemented)):
+
+class SpecialMethod:
+ """An implementation for a multimethod that looks for a user-defined
+ special __xxx__ method."""
+
+ def __init__(self, method_name, bound_position=0):
+ self.method_name = method_name
+ self.bound_position = bound_position
+
+ def do_call(self, space, args_w):
+ # args_w is in the standard multimethod order
+ # we need it in the Python-friendly order (i.e. swapped for __rxxx__)
+ args_w = list(args_w)
+ w_userobj = args_w.pop(self.bound_position)
+ w_args = space.newtuple(args_w)
+ w_key = space.wrap(self.method_name)
+ w_mro = space.getattr(w_userobj.w_type, space.wrap('__mro__'))
+ mro = space.unpacktuple(w_mro)
+ for w_base in mro:
+ if not isinstance(w_base, W_UserType):
+ continue
+ try:
+ w_function = w_base.lookup_exactly_here(w_key)
+ except KeyError:
+ continue
+ w_method = space.get(w_function, w_userobj, w_base)
+ return space.call(w_method, w_args, space.newdict([]))
+ raise FailedToImplement
+
+ def normal_call(self, space, *args_w):
+ "Call a user-defined __xxx__ method and convert the result back."
+ w_result = self.do_call(space, args_w)
+ # interpret 'NotImplemented' as meaning not implemented (duh).
+ if space.is_true(space.is_(w_result, space.w_NotImplemented)):
raise FailedToImplement
- else:
- return w_result
- raise FailedToImplement
+ return w_result
+
+ def next_call(self, space, *args_w):
+ "For .next()."
+ # don't accept NotImplemented nor a real None, but catch StopIteration
+ try:
+ return self.do_call(space, args_w)
+ except OperationError, e:
+ if not e.match(self.space, self.space.w_StopIteration):
+ raise
+ raise NoValue
+
+ def nonzero_call(self, space, *args_w):
+ "For __nonzero__()."
+ # accept any object and return its truth value
+ # XXX if the user returns another custom object he can
+ # force the interpreter into an infinite loop
+ w_result = self.do_call(space, args_w)
+ return space.is_true(w_result)
+
import new
for multimethod in typeobject.hack_out_multimethods(StdObjSpace):
for i in range(len(multimethod.specialnames)):
- # a hack to avoid nested scopes is to give the function
- # a custom globals dictionary
-
- g = {'W_UserType' : W_UserType,
- 'FailedToImplement': FailedToImplement,
- '__builtins__' : __builtins__,
- 'g_method_name' : multimethod.specialnames[i],
- 'g_bound_position' : i}
- f = new.function(user_specialmethod.func_code, g,
- 'user_%s' % multimethod.specialnames[i])
-
+ f = SpecialMethod(multimethod.specialnames[i], i).normal_call
signature = [W_ANY] * multimethod.arity
signature[i] = W_UserObject
multimethod.register(f, *signature)
+next__User = SpecialMethod('next').next_call
+is_true__User = SpecialMethod('nonzero').nonzero_call
+
register_all(vars())
More information about the Pypy-commit
mailing list