[pypy-svn] r72959 - in pypy/branch/cpython-extension/pypy/module/cpyext: . test

xoraxax at codespeak.net xoraxax at codespeak.net
Sat Mar 27 17:04:56 CET 2010


Author: xoraxax
Date: Sat Mar 27 17:04:54 2010
New Revision: 72959

Added:
   pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py   (contents, props changed)
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobjectdefs.py   (contents, props changed)
Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
   pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Implement slot wrappers, move code from typeobject.py to typeobjectdefs.py.

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	Sat Mar 27 17:04:54 2010
@@ -2,6 +2,7 @@
 from pypy.rlib.objectmodel import we_are_translated
 import pypy.module.cpyext.api
 from pypy.module.cpyext.state import State
+from pypy.module.cpyext.slotdefs import init_slotdefs
 
 
 class Module(MixedModule):
@@ -17,6 +18,7 @@
         state = self.space.fromcache(State)
         if not we_are_translated():
             state.api_lib = str(pypy.module.cpyext.api.build_bridge(self.space))
+            state.slotdefs = init_slotdefs(self.space)
         else:
             XXX # build an import library when translating pypy.
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py	Sat Mar 27 17:04:54 2010
@@ -43,6 +43,33 @@
         return self.space.wrap(self.__repr__())
 
 
+class W_PyCWrapperObject(Wrappable):
+    def __init__(self, space, pto, method_name, wrapper_func, doc, flags, func):
+        self.space = space
+        self.method_name = method_name
+        self.wrapper_func = wrapper_func
+        self.doc = doc
+        self.flags = flags
+        self.func = func
+        assert flags == 0
+        self.w_objclass = from_ref(space, pto)
+
+    def call(self, w_self, w_args):
+        return generic_cpy_call(self.space, self.wrapper_func, w_self, w_args, self.func)
+
+
+ at unwrap_spec(ObjSpace, W_Root, Arguments)
+def cwrapper_descr_call(space, w_self, __args__):
+    self = space.interp_w(W_PyCWrapperObject, w_self)
+    args_w, kw_w = __args__.unpack()
+    w_args = space.newtuple(args_w[1:])
+    w_self = args_w[0]
+    if kw_w:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("keywords not yet supported"))
+    return self.call(w_self, w_args)
+
+
 @unwrap_spec(ObjSpace, W_Root, Arguments)
 def cfunction_descr_call(space, w_self, __args__):
     self = space.interp_w(W_PyCFunctionObject, w_self)
@@ -51,7 +78,7 @@
     if kw_w:
         raise OperationError(space.w_TypeError,
                              space.wrap("keywords not yet supported"))
-    ret = self.call(None, space.newtuple(args_w))
+    ret = self.call(None, w_args)
     return ret
 
 @unwrap_spec(ObjSpace, W_Root, Arguments)
@@ -80,7 +107,6 @@
     'builtin_function_or_method',
     __call__ = interp2app(cfunction_descr_call),
     )
-
 W_PyCFunctionObject.typedef.acceptable_as_base_class = False
 
 W_PyCMethodObject.typedef = TypeDef(
@@ -91,13 +117,29 @@
     __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCMethodObject),
     __repr__ = interp2app(W_PyCMethodObject.descr_method_repr),
     )
-
 W_PyCMethodObject.typedef.acceptable_as_base_class = False
 
-def PyCFunction_NewEx(space, ml, w_self): # not directly the API sig
+
+W_PyCWrapperObject.typedef = TypeDef(
+    'wrapper_descriptor',
+    __call__ = interp2app(cwrapper_descr_call),
+    __get__ = interp2app(cmethod_descr_get),
+    __name__ = interp_attrproperty('method_name', cls=W_PyCWrapperObject),
+    __doc__ = interp_attrproperty('doc', cls=W_PyCWrapperObject),
+    __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCWrapperObject),
+    # XXX missing: __getattribute__, __repr__
+    )
+W_PyCWrapperObject.typedef.acceptable_as_base_class = False
+
+
+def PyCFunction_NewEx(space, ml, w_self): # not exactly the API sig
     return space.wrap(W_PyCFunctionObject(space, ml, w_self))
 
 
 def PyDescr_NewMethod(space, pto, method):
     return space.wrap(W_PyCMethodObject(space, method, pto))
 
+def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, doc, flags, func):
+    # not exactly the API sig
+    return space.wrap(W_PyCWrapperObject(space, pto, method_name,
+        wrapper_func, doc, flags, func))

Added: pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py	Sat Mar 27 17:04:54 2010
@@ -0,0 +1,306 @@
+import re
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import generic_cpy_call, cpython_api, \
+        PyObject
+from pypy.module.cpyext.typeobjectdefs import unaryfunc, wrapperfunc
+from pypy.module.cpyext.state import State
+from pypy.interpreter.error import OperationError, operationerrfmt
+
+space = None
+
+def is_wrapper_func(func):
+    deco = cpython_api([PyObject, PyObject, rffi.VOIDP_real], PyObject, external=False)
+    return deco(func)
+
+def check_num_args(space, ob, n):
+    from pypy.module.cpyext.tupleobject import PyTuple_CheckExact, \
+            PyTuple_GET_SIZE
+    if not PyTuple_CheckExact(space, ob):
+        raise OperationError(space.w_SystemError,
+            "PyArg_UnpackTuple() argument list is not a tuple")
+    if n == PyTuple_GET_SIZE(space, ob):
+        return
+    raise operationerrfmt(space.w_TypeError,
+        "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob))
+
+def wrap_binaryfunc_l(space, w_self, w_args, func):
+    pass
+
+def wrap_binaryfunc_r(space, w_self, w_args, func):
+    pass
+
+ at is_wrapper_func
+def wrap_unaryfunc(space, w_self, w_args, func):
+    func_unary = rffi.cast(unaryfunc, func)
+    check_num_args(space, w_args, 0)
+    return generic_cpy_call(space, func_unary, w_self)
+
+
+PyWrapperFlag_KEYWORDS = 1
+
+# adopted from typeobject.c
+def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
+    wrapper = globals().get(WRAPPER, None)
+    if wrapper is not None:
+        wrapper = wrapper.api_func.get_llhelper(space)
+    else:
+        wrapper = lltype.nullptr(wrapperfunc.TO)
+    slotname = ("c_" + SLOT).split(".")
+    return (NAME, slotname, FUNCTION, wrapper, DOC, FLAGS)
+
+def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)
+
+ETSLOT = TPSLOT
+
+def SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return ETSLOT(NAME, "tp_as_sequence.c_" + SLOT, FUNCTION, WRAPPER, DOC)
+def MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return ETSLOT(NAME, "tp_as_mapping.c_" + SLOT, FUNCTION, WRAPPER, DOC)
+def NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER, DOC)
+def UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER,
+            "x." + NAME + "() <==> " + DOC)
+def IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, WRAPPER,
+            "x." + NAME + "(y) <==> x" + DOC + "y")
+def BINSLOT(NAME, SLOT, FUNCTION, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, wrap_binaryfunc_l, \
+            "x." + NAME + "(y) <==> x" + DOC + "y")
+def RBINSLOT(NAME, SLOT, FUNCTION, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, wrap_binaryfunc_r, \
+            "x." + NAME + "(y) <==> y" + DOC + "x")
+def BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, wrap_binaryfunc_l, \
+            "x." + NAME + "(y) <==> " + DOC)
+def RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC):
+    return ETSLOT(NAME, "tp_as_number.c_" + SLOT, FUNCTION, wrap_binaryfunc_r, \
+            "x." + NAME + "(y) <==> " + DOC)
+
+# TODO remove all casts
+slotdef_replacements = (
+        ("\s+", " "),
+        ("static [^{]*{", "("),
+        ("};", ")"),
+        (r"(?P<start> +..SLOT\([^,]*, )(?P<fname>[^,]*), (?P<slotcname>[^,]*), (?P<wname>[^,]*)", r"\g<start>'\g<fname>', '\g<slotcname>', '\g<wname>'"),
+        (r"(?P<start> *R?[^ ]{3}SLOT(NOTINFIX)?\([^,]*, )(?P<fname>[^,]*), (?P<slotcname>[^,]*)", r"\g<start>'\g<fname>', '\g<slotcname>'"),
+        ("'NULL'", "None"),
+        ("{NULL}", ""),
+        ("\),", "),\n"),
+    )
+
+"""
+    /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
+       The logic in abstract.c always falls back to nb_add/nb_multiply in
+       this case.  Defining both the nb_* and the sq_* slots to call the
+       user-defined methods has unexpected side-effects, as shown by
+       test_descr.notimplemented() */
+"""
+# Instructions for update:
+# Copy new slotdefs from typeobject.c
+# Remove comments
+# Done
+slotdefs = """
+static slotdef slotdefs[] = {
+	SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
+	       "x.__len__() <==> len(x)"),
+	SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
+	  "x.__add__(y) <==> x+y"),
+	SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
+	  "x.__mul__(n) <==> x*n"),
+	SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
+	  "x.__rmul__(n) <==> n*x"),
+	SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
+	       "x.__getitem__(y) <==> x[y]"),
+	SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc,
+	       "x.__getslice__(i, j) <==> x[i:j]\n\
+	       \n\
+	       Use of negative indices is not supported."),
+	SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
+	       "x.__setitem__(i, y) <==> x[i]=y"),
+	SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
+	       "x.__delitem__(y) <==> del x[y]"),
+	SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
+	       wrap_ssizessizeobjargproc,
+	       "x.__setslice__(i, j, y) <==> x[i:j]=y\n\
+	       \n\
+	       Use  of negative indices is not supported."),
+	SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice,
+	       "x.__delslice__(i, j) <==> del x[i:j]\n\
+	       \n\
+	       Use of negative indices is not supported."),
+	SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
+	       "x.__contains__(y) <==> y in x"),
+	SQSLOT("__iadd__", sq_inplace_concat, NULL,
+	  wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
+	SQSLOT("__imul__", sq_inplace_repeat, NULL,
+	  wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
+
+	MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
+	       "x.__len__() <==> len(x)"),
+	MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
+	       wrap_binaryfunc,
+	       "x.__getitem__(y) <==> x[y]"),
+	MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
+	       wrap_objobjargproc,
+	       "x.__setitem__(i, y) <==> x[i]=y"),
+	MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
+	       wrap_delitem,
+	       "x.__delitem__(y) <==> del x[y]"),
+
+	BINSLOT("__add__", nb_add, slot_nb_add,
+		"+"),
+	RBINSLOT("__radd__", nb_add, slot_nb_add,
+		 "+"),
+	BINSLOT("__sub__", nb_subtract, slot_nb_subtract,
+		"-"),
+	RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract,
+		 "-"),
+	BINSLOT("__mul__", nb_multiply, slot_nb_multiply,
+		"*"),
+	RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply,
+		 "*"),
+	BINSLOT("__div__", nb_divide, slot_nb_divide,
+		"/"),
+	RBINSLOT("__rdiv__", nb_divide, slot_nb_divide,
+		 "/"),
+	BINSLOT("__mod__", nb_remainder, slot_nb_remainder,
+		"%"),
+	RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder,
+		 "%"),
+	BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod,
+		"divmod(x, y)"),
+	RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod,
+		 "divmod(y, x)"),
+	NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc,
+	       "x.__pow__(y[, z]) <==> pow(x, y[, z])"),
+	NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r,
+	       "y.__rpow__(x[, z]) <==> pow(x, y[, z])"),
+	UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"),
+	UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"),
+	UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc,
+	       "abs(x)"),
+	UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred,
+	       "x != 0"),
+	UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"),
+	BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"),
+	RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"),
+	BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"),
+	RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"),
+	BINSLOT("__and__", nb_and, slot_nb_and, "&"),
+	RBINSLOT("__rand__", nb_and, slot_nb_and, "&"),
+	BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"),
+	RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"),
+	BINSLOT("__or__", nb_or, slot_nb_or, "|"),
+	RBINSLOT("__ror__", nb_or, slot_nb_or, "|"),
+	NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc,
+	       "x.__coerce__(y) <==> coerce(x, y)"),
+	UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc,
+	       "int(x)"),
+	UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc,
+	       "long(x)"),
+	UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
+	       "float(x)"),
+	UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc,
+	       "oct(x)"),
+	UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
+	       "hex(x)"),
+	NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, 
+	       "x[y:z] <==> x[y.__index__():z.__index__()]"),
+	IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
+	       wrap_binaryfunc, "+"),
+	IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
+	       wrap_binaryfunc, "-"),
+	IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
+	       wrap_binaryfunc, "*"),
+	IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
+	       wrap_binaryfunc, "/"),
+	IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
+	       wrap_binaryfunc, "%"),
+	IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
+	       wrap_binaryfunc, "**"),
+	IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
+	       wrap_binaryfunc, "<<"),
+	IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
+	       wrap_binaryfunc, ">>"),
+	IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
+	       wrap_binaryfunc, "&"),
+	IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
+	       wrap_binaryfunc, "^"),
+	IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
+	       wrap_binaryfunc, "|"),
+	BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
+	RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
+	BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"),
+	RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"),
+	IBSLOT("__ifloordiv__", nb_inplace_floor_divide,
+	       slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
+	IBSLOT("__itruediv__", nb_inplace_true_divide,
+	       slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
+
+	TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
+	       "x.__str__() <==> str(x)"),
+	TPSLOT("__str__", tp_print, NULL, NULL, ""),
+	TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
+	       "x.__repr__() <==> repr(x)"),
+	TPSLOT("__repr__", tp_print, NULL, NULL, ""),
+	TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc,
+	       "x.__cmp__(y) <==> cmp(x,y)"),
+	TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
+	       "x.__hash__() <==> hash(x)"),
+	FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+	       "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
+	TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
+	       wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
+	TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
+	TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
+	TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
+	TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
+	       "x.__setattr__('name', value) <==> x.name = value"),
+	TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
+	TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
+	       "x.__delattr__('name') <==> del x.name"),
+	TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
+	TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
+	       "x.__lt__(y) <==> x<y"),
+	TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
+	       "x.__le__(y) <==> x<=y"),
+	TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
+	       "x.__eq__(y) <==> x==y"),
+	TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
+	       "x.__ne__(y) <==> x!=y"),
+	TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
+	       "x.__gt__(y) <==> x>y"),
+	TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
+	       "x.__ge__(y) <==> x>=y"),
+	TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
+	       "x.__iter__() <==> iter(x)"),
+	TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next,
+	       "x.next() -> the next value, or raise StopIteration"),
+	TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
+	       "descr.__get__(obj[, type]) -> value"),
+	TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
+	       "descr.__set__(obj, value)"),
+	TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
+	       wrap_descr_delete, "descr.__delete__(obj)"),
+	FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
+	       "x.__init__(...) initializes x; "
+	       "see x.__class__.__doc__ for signature",
+	       PyWrapperFlag_KEYWORDS),
+	TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
+	TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
+	{NULL}
+};
+"""
+for regex, repl in slotdef_replacements:
+    slotdefs = re.sub(regex, repl, slotdefs)
+def init_slotdefs(space_):
+    global space
+    space = space_
+    try:
+        return eval(slotdefs)
+    finally:
+        space = None
+

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	Sat Mar 27 17:04:54 2010
@@ -66,6 +66,16 @@
     {NULL}  /* Sentinel */
 };
 
+static PyObject *
+foo_repr(PyObject *self)
+{
+    PyObject *format;
+
+    format = PyString_FromString("<Foo>");
+    if (format == NULL) return NULL;
+    return format;
+}
+
 
 static PyTypeObject footype = {
 	PyVarObject_HEAD_INIT(NULL, 0)
@@ -78,7 +88,7 @@
 	0,                        /*tp_getattr*/
 	0,			  /*tp_setattr*/
 	0,			  /*tp_compare*/
-	0,			  /*tp_repr*/
+	foo_repr,			  /*tp_repr*/
     0,			  /*tp_as_number*/
 	0,                        /*tp_as_sequence*/
 	0,			  /*tp_as_mapping*/

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	Sat Mar 27 17:04:54 2010
@@ -19,3 +19,5 @@
         assert not "im_func" in dir(module.fooType.copy)
         assert module.fooType.copy.__objclass__ is module.fooType
         assert "copy" in repr(module.fooType.copy)
+        assert repr(module.fooType) == "<type 'foo.foo'>"
+        assert repr(obj2) == "<Foo>"

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	Sat Mar 27 17:04:54 2010
@@ -1,7 +1,6 @@
 import sys
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
 from pypy.rpython.annlowlevel import llhelper
 from pypy.interpreter.gateway import ObjSpace, W_Root
 from pypy.interpreter.gateway import interp2app, unwrap_spec
@@ -12,149 +11,15 @@
 from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct, \
     PyObject, PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, \
     Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, make_ref, \
-    PyStringObject, ADDR, from_ref
+    PyStringObject, ADDR, from_ref, generic_cpy_call
 from pypy.interpreter.module import Module
-from pypy.module.cpyext.modsupport import PyMethodDef, convert_method_defs
+from pypy.module.cpyext.modsupport import  convert_method_defs
 from pypy.module.cpyext.state import State
-from pypy.module.cpyext.methodobject import generic_cpy_call
+from pypy.module.cpyext.methodobject import PyDescr_NewWrapper
 from pypy.module.cpyext.macros import Py_INCREF, Py_DECREF, Py_XDECREF
-
-PyTypeObject = lltype.ForwardReference()
-PyTypeObjectPtr = lltype.Ptr(PyTypeObject)
-PyCFunction = Ptr(FuncType([PyObject, PyObject], PyObject))
-P, FT, PyO = Ptr, FuncType, PyObject
-PyOPtr = Ptr(lltype.Array(PyO, hints={'nolength': True}))
-
-
-# XXX
-PyNumberMethods = PySequenceMethods = PyMappingMethods = \
-                  PyBufferProcs = PyMemberDef = rffi.VOIDP.TO
-
-freefunc = P(FT([rffi.VOIDP_real], Void))
-destructor = P(FT([PyO], Void))
-printfunc = P(FT([PyO, rffi.VOIDP_real, rffi.INT_real], rffi.INT))
-getattrfunc = P(FT([PyO, rffi.CCHARP], PyO))
-getattrofunc = P(FT([PyO, PyO], PyO))
-setattrfunc = P(FT([PyO, rffi.CCHARP, PyO], rffi.INT_real))
-setattrofunc = P(FT([PyO, PyO, PyO], rffi.INT_real))
-cmpfunc = P(FT([PyO, PyO], rffi.INT_real))
-reprfunc = P(FT([PyO], PyO))
-hashfunc = P(FT([PyO], lltype.Signed))
-richcmpfunc = P(FT([PyO, PyO, rffi.INT_real], PyO))
-getiterfunc = P(FT([PyO], PyO))
-iternextfunc = P(FT([PyO], PyO))
-descrgetfunc = P(FT([PyO, PyO, PyO], PyO))
-descrsetfunc = P(FT([PyO, PyO, PyO], rffi.INT_real))
-initproc = P(FT([PyO, PyO, PyO], rffi.INT_real))
-newfunc = P(FT([PyTypeObjectPtr, PyO, PyO], PyO))
-allocfunc = P(FT([PyTypeObjectPtr, Py_ssize_t], PyO))
-unaryfunc = P(FT([PyO], PyO))
-binaryfunc = P(FT([PyO, PyO], PyO))
-ternaryfunc = P(FT([PyO, PyO, PyO], PyO))
-inquiry = P(FT([PyO], rffi.INT_real))
-lenfunc = P(FT([PyO], Py_ssize_t))
-coercion = P(FT([PyOPtr, PyOPtr], rffi.INT_real))
-intargfunc = P(FT([PyO, rffi.INT_real], PyO))
-intintargfunc = P(FT([PyO, rffi.INT_real, rffi.INT], PyO))
-ssizeargfunc = P(FT([PyO, Py_ssize_t], PyO))
-ssizessizeargfunc = P(FT([PyO, Py_ssize_t, Py_ssize_t], PyO))
-intobjargproc = P(FT([PyO, rffi.INT_real, PyO], rffi.INT))
-intintobjargproc = P(FT([PyO, rffi.INT_real, rffi.INT, PyO], rffi.INT))
-ssizeobjargproc = P(FT([PyO, Py_ssize_t, PyO], rffi.INT_real))
-ssizessizeobjargproc = P(FT([PyO, Py_ssize_t, Py_ssize_t, PyO], rffi.INT_real))
-objobjargproc = P(FT([PyO, PyO, PyO], rffi.INT_real))
-
-objobjproc = P(FT([PyO, PyO], rffi.INT_real))
-visitproc = P(FT([PyO, rffi.VOIDP_real], rffi.INT_real))
-traverseproc = P(FT([PyO, visitproc, rffi.VOIDP_real], rffi.INT_real))
-
-getter = P(FT([PyO, rffi.VOIDP_real], PyO))
-setter = P(FT([PyO, PyO, rffi.VOIDP_real], rffi.INT_real))
-
-PyGetSetDef = cpython_struct("PyGetSetDef", (
-	("name", rffi.CCHARP),
-    ("get", getter),
-    ("set", setter),
-    ("doc", rffi.CCHARP),
-    ("closure", rffi.VOIDP_real),
-))
-
-PyTypeObjectFields = []
-PyTypeObjectFields.extend(PyVarObjectFields)
-PyTypeObjectFields.extend([
-    ("tp_name", rffi.CCHARP), # For printing, in format "<module>.<name>"
-    ("tp_basicsize", Py_ssize_t), ("tp_itemsize", Py_ssize_t), # For allocation
-
-    # Methods to implement standard operations
-    ("tp_dealloc", destructor),
-    ("tp_print", printfunc),
-    ("tp_getattr", getattrfunc),
-    ("tp_setattr", setattrfunc),
-    ("tp_compare", cmpfunc),
-    ("tp_repr", reprfunc),
-
-    # Method suites for standard classes
-    ("tp_as_number", Ptr(PyNumberMethods)),
-    ("tp_as_sequence", Ptr(PySequenceMethods)),
-    ("tp_as_mapping", Ptr(PyMappingMethods)),
-
-    # More standard operations (here for binary compatibility)
-    ("tp_hash", hashfunc),
-    ("tp_call", ternaryfunc),
-    ("tp_str", reprfunc),
-    ("tp_getattro", getattrofunc),
-    ("tp_setattro", setattrofunc),
-
-    # Functions to access object as input/output buffer
-    ("tp_as_buffer", Ptr(PyBufferProcs)),
-
-    # Flags to define presence of optional/expanded features
-    ("tp_flags", lltype.Signed),
-
-    ("tp_doc", rffi.CCHARP), # Documentation string
-
-    # Assigned meaning in release 2.0
-    # call function for all accessible objects
-    ("tp_traverse", traverseproc),
-
-    # delete references to contained objects
-    ("tp_clear", inquiry),
-
-    # Assigned meaning in release 2.1
-    # rich comparisons 
-    ("tp_richcompare", richcmpfunc),
-
-    # weak reference enabler
-    ("tp_weaklistoffset", Py_ssize_t),
-
-    # Added in release 2.2
-    # Iterators
-    ("tp_iter", getiterfunc),
-    ("tp_iternext", iternextfunc),
-
-    # Attribute descriptor and subclassing stuff
-    ("tp_methods", Ptr(PyMethodDef)),
-    ("tp_members", Ptr(PyMemberDef)),
-    ("tp_getset", Ptr(PyGetSetDef)),
-    ("tp_base", Ptr(PyTypeObject)),
-    ("tp_dict", PyObject),
-    ("tp_descr_get", descrgetfunc),
-    ("tp_descr_set", descrsetfunc),
-    ("tp_dictoffset", Py_ssize_t),  # can be ignored in PyPy
-    ("tp_init", initproc),
-    ("tp_alloc", allocfunc),
-    ("tp_new", newfunc),
-    ("tp_free", freefunc), # Low-level free-memory routine
-    ("tp_is_gc", inquiry), # For PyObject_IS_GC
-    ("tp_bases", PyObject),
-    ("tp_mro", PyObject), # method resolution order
-    ("tp_cache", PyObject),
-    ("tp_subclasses", PyObject),
-    ("tp_weaklist", PyObject),
-    ("tp_del", destructor),
-    ])
-cpython_struct("PyTypeObject", PyTypeObjectFields, PyTypeObject)
-
+from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr, PyTypeObject, \
+        PyGetSetDef
+from pypy.module.cpyext.slotdefs import slotdefs
 
 
 class W_GetSetPropertyEx(GetSetProperty): # XXX fix this to be rpython
@@ -194,21 +59,46 @@
             w_descr = PyDescr_NewGetSet(space, getset, pto)
             dict_w[name] = w_descr
 
+def add_operators(space, dict_w, pto):
+    # XXX support PyObject_HashNotImplemented
+    state = space.fromcache(State)
+    for method_name, slot_name, _, wrapper_func, doc, flags in state.slotdefs: # XXX use UI
+        if method_name in dict_w or wrapper_func is None:
+            continue
+        # XXX is this rpython?
+        if len(slot_name) == 1:
+            func = getattr(pto, slot_name[0])
+        else:
+            assert len(slot_name) == 2
+            struct = getattr(pto, slot_name[0])
+            if not struct:
+                continue
+            func = getattr(struct, slot_name[1])
+        func_voidp = rffi.cast(rffi.VOIDP_real, func)
+        if not func:
+            continue
+        dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
+                doc, flags, func_voidp)
+
 
 class W_PyCTypeObject(W_TypeObject):
     def __init__(self, space, pto):
         self.pto = pto
         bases_w = []
         dict_w = {}
+
+        add_operators(space, dict_w, pto)
         convert_method_defs(space, dict_w, pto.c_tp_methods, pto)
         convert_getset_defs(space, dict_w, pto.c_tp_getset, pto)
         # XXX missing: convert_member_defs
+
         full_name = rffi.charp2str(pto.c_tp_name)
         module_name, extension_name = full_name.split(".", 1)
         dict_w["__module__"] = space.wrap(module_name)
+
         W_TypeObject.__init__(self, space, extension_name,
             bases_w or [space.w_object], dict_w)
-        self.__flags__ = _CPYTYPE
+        self.__flags__ = _CPYTYPE # mainly disables lookup optimizations
 
 class W_PyCObject(Wrappable):
     def __init__(self, space):

Added: pypy/branch/cpython-extension/pypy/module/cpyext/typeobjectdefs.py
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobjectdefs.py	Sat Mar 27 17:04:54 2010
@@ -0,0 +1,223 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
+from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct, \
+    PyObject, PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, \
+    Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, make_ref, \
+    PyStringObject, ADDR, from_ref
+from pypy.module.cpyext.modsupport import PyMethodDef
+
+
+PyTypeObject = lltype.ForwardReference()
+PyTypeObjectPtr = lltype.Ptr(PyTypeObject)
+PyCFunction = Ptr(FuncType([PyObject, PyObject], PyObject))
+P, FT, PyO = Ptr, FuncType, PyObject
+PyOPtr = Ptr(lltype.Array(PyO, hints={'nolength': True}))
+
+
+# XXX
+PyBufferProcs = PyMemberDef = rffi.VOIDP.TO
+
+freefunc = P(FT([rffi.VOIDP_real], Void))
+destructor = P(FT([PyO], Void))
+printfunc = P(FT([PyO, rffi.VOIDP_real, rffi.INT_real], rffi.INT))
+getattrfunc = P(FT([PyO, rffi.CCHARP], PyO))
+getattrofunc = P(FT([PyO, PyO], PyO))
+setattrfunc = P(FT([PyO, rffi.CCHARP, PyO], rffi.INT_real))
+setattrofunc = P(FT([PyO, PyO, PyO], rffi.INT_real))
+cmpfunc = P(FT([PyO, PyO], rffi.INT_real))
+reprfunc = P(FT([PyO], PyO))
+hashfunc = P(FT([PyO], lltype.Signed))
+richcmpfunc = P(FT([PyO, PyO, rffi.INT_real], PyO))
+getiterfunc = P(FT([PyO], PyO))
+iternextfunc = P(FT([PyO], PyO))
+descrgetfunc = P(FT([PyO, PyO, PyO], PyO))
+descrsetfunc = P(FT([PyO, PyO, PyO], rffi.INT_real))
+initproc = P(FT([PyO, PyO, PyO], rffi.INT_real))
+newfunc = P(FT([PyTypeObjectPtr, PyO, PyO], PyO))
+allocfunc = P(FT([PyTypeObjectPtr, Py_ssize_t], PyO))
+unaryfunc = P(FT([PyO], PyO))
+binaryfunc = P(FT([PyO, PyO], PyO))
+ternaryfunc = P(FT([PyO, PyO, PyO], PyO))
+inquiry = P(FT([PyO], rffi.INT_real))
+lenfunc = P(FT([PyO], Py_ssize_t))
+coercion = P(FT([PyOPtr, PyOPtr], rffi.INT_real))
+intargfunc = P(FT([PyO, rffi.INT_real], PyO))
+intintargfunc = P(FT([PyO, rffi.INT_real, rffi.INT], PyO))
+ssizeargfunc = P(FT([PyO, Py_ssize_t], PyO))
+ssizessizeargfunc = P(FT([PyO, Py_ssize_t, Py_ssize_t], PyO))
+intobjargproc = P(FT([PyO, rffi.INT_real, PyO], rffi.INT))
+intintobjargproc = P(FT([PyO, rffi.INT_real, rffi.INT, PyO], rffi.INT))
+ssizeobjargproc = P(FT([PyO, Py_ssize_t, PyO], rffi.INT_real))
+ssizessizeobjargproc = P(FT([PyO, Py_ssize_t, Py_ssize_t, PyO], rffi.INT_real))
+objobjargproc = P(FT([PyO, PyO, PyO], rffi.INT_real))
+
+objobjproc = P(FT([PyO, PyO], rffi.INT_real))
+visitproc = P(FT([PyO, rffi.VOIDP_real], rffi.INT_real))
+traverseproc = P(FT([PyO, visitproc, rffi.VOIDP_real], rffi.INT_real))
+
+getter = P(FT([PyO, rffi.VOIDP_real], PyO))
+setter = P(FT([PyO, PyO, rffi.VOIDP_real], rffi.INT_real))
+
+wrapperfunc = P(FT([PyO, PyO, rffi.VOIDP_real], PyO))
+wrapperfunc_kwds = P(FT([PyO, PyO, rffi.VOIDP_real, PyO], PyO))
+
+
+PyGetSetDef = cpython_struct("PyGetSetDef", (
+	("name", rffi.CCHARP),
+    ("get", getter),
+    ("set", setter),
+    ("doc", rffi.CCHARP),
+    ("closure", rffi.VOIDP_real),
+))
+
+PyNumberMethods = cpython_struct("PyNumberMethods", (
+    ("nb_add", binaryfunc),
+    ("nb_subtract", binaryfunc),
+    ("nb_multiply", binaryfunc),
+    ("nb_divide", binaryfunc),
+    ("nb_remainder", binaryfunc),
+    ("nb_divmod", binaryfunc),
+    ("nb_power", ternaryfunc),
+    ("nb_negative", unaryfunc),
+    ("nb_positive", unaryfunc),
+    ("nb_absolute", unaryfunc),
+    ("nb_nonzero", inquiry),
+    ("nb_invert", unaryfunc),
+    ("nb_lshift", binaryfunc),
+    ("nb_rshift", binaryfunc),
+    ("nb_and", binaryfunc),
+    ("nb_xor", binaryfunc),
+    ("nb_or", binaryfunc),
+    ("nb_coerce", coercion),
+    ("nb_int", unaryfunc),
+    ("nb_long", unaryfunc),
+    ("nb_float", unaryfunc),
+    ("nb_oct", unaryfunc),
+    ("nb_hex", unaryfunc),
+    ("nb_inplace_add", binaryfunc),
+    ("nb_inplace_subtract", binaryfunc),
+    ("nb_inplace_multiply", binaryfunc),
+    ("nb_inplace_divide", binaryfunc),
+    ("nb_inplace_remainder", binaryfunc),
+    ("nb_inplace_power", ternaryfunc),
+    ("nb_inplace_lshift", binaryfunc),
+    ("nb_inplace_rshift", binaryfunc),
+    ("nb_inplace_and", binaryfunc),
+    ("nb_inplace_xor", binaryfunc),
+    ("nb_inplace_or", binaryfunc),
+
+    ("nb_floor_divide", binaryfunc),
+    ("nb_true_divide", binaryfunc),
+    ("nb_inplace_floor_divide", binaryfunc),
+    ("nb_inplace_true_divide", binaryfunc),
+
+    ("nb_index", unaryfunc),
+))
+
+PySequenceMethods = cpython_struct("PySequenceMethods", (
+    ("sq_length", lenfunc),
+    ("sq_concat", binaryfunc),
+    ("sq_repeat", ssizeargfunc),
+    ("sq_item", ssizeargfunc),
+    ("sq_slice", ssizessizeargfunc),
+    ("sq_ass_item", ssizeobjargproc),
+    ("sq_ass_slice", ssizessizeobjargproc),
+    ("sq_contains", objobjproc),
+    ("sq_inplace_concat", binaryfunc),
+    ("sq_inplace_repeat", ssizeargfunc),
+))
+
+PyMappingMethods = cpython_struct("PyMappingMethods", (
+    ("mp_length", lenfunc),
+    ("mp_subscript", binaryfunc),
+    ("mp_ass_subscript", objobjargproc),
+))
+
+"""
+PyBufferProcs = cpython_struct("PyBufferProcs", (
+    ("bf_getreadbuffer", readbufferproc),
+    ("bf_getwritebuffer", writebufferproc),
+    ("bf_getsegcount", segcountproc),
+    ("bf_getcharbuffer", charbufferproc),
+    ("bf_getbuffer", getbufferproc),
+    ("bf_releasebuffer", releasebufferproc),
+))
+"""
+
+PyTypeObjectFields = []
+PyTypeObjectFields.extend(PyVarObjectFields)
+PyTypeObjectFields.extend([
+    ("tp_name", rffi.CCHARP), # For printing, in format "<module>.<name>"
+    ("tp_basicsize", Py_ssize_t), ("tp_itemsize", Py_ssize_t), # For allocation
+
+    # Methods to implement standard operations
+    ("tp_dealloc", destructor),
+    ("tp_print", printfunc),
+    ("tp_getattr", getattrfunc),
+    ("tp_setattr", setattrfunc),
+    ("tp_compare", cmpfunc),
+    ("tp_repr", reprfunc),
+
+    # Method suites for standard classes
+    ("tp_as_number", Ptr(PyNumberMethods)),
+    ("tp_as_sequence", Ptr(PySequenceMethods)),
+    ("tp_as_mapping", Ptr(PyMappingMethods)),
+
+    # More standard operations (here for binary compatibility)
+    ("tp_hash", hashfunc),
+    ("tp_call", ternaryfunc),
+    ("tp_str", reprfunc),
+    ("tp_getattro", getattrofunc),
+    ("tp_setattro", setattrofunc),
+
+    # Functions to access object as input/output buffer
+    ("tp_as_buffer", Ptr(PyBufferProcs)),
+
+    # Flags to define presence of optional/expanded features
+    ("tp_flags", lltype.Signed),
+
+    ("tp_doc", rffi.CCHARP), # Documentation string
+
+    # Assigned meaning in release 2.0
+    # call function for all accessible objects
+    ("tp_traverse", traverseproc),
+
+    # delete references to contained objects
+    ("tp_clear", inquiry),
+
+    # Assigned meaning in release 2.1
+    # rich comparisons 
+    ("tp_richcompare", richcmpfunc),
+
+    # weak reference enabler
+    ("tp_weaklistoffset", Py_ssize_t),
+
+    # Added in release 2.2
+    # Iterators
+    ("tp_iter", getiterfunc),
+    ("tp_iternext", iternextfunc),
+
+    # Attribute descriptor and subclassing stuff
+    ("tp_methods", Ptr(PyMethodDef)),
+    ("tp_members", Ptr(PyMemberDef)),
+    ("tp_getset", Ptr(PyGetSetDef)),
+    ("tp_base", Ptr(PyTypeObject)),
+    ("tp_dict", PyObject),
+    ("tp_descr_get", descrgetfunc),
+    ("tp_descr_set", descrsetfunc),
+    ("tp_dictoffset", Py_ssize_t),  # can be ignored in PyPy
+    ("tp_init", initproc),
+    ("tp_alloc", allocfunc),
+    ("tp_new", newfunc),
+    ("tp_free", freefunc), # Low-level free-memory routine
+    ("tp_is_gc", inquiry), # For PyObject_IS_GC
+    ("tp_bases", PyObject),
+    ("tp_mro", PyObject), # method resolution order
+    ("tp_cache", PyObject),
+    ("tp_subclasses", PyObject),
+    ("tp_weaklist", PyObject),
+    ("tp_del", destructor),
+    ])
+cpython_struct("PyTypeObject", PyTypeObjectFields, PyTypeObject)
+
+



More information about the Pypy-commit mailing list