[pypy-svn] r24990 - in pypy/dist/pypy/translator/c: . test

tismer at codespeak.net tismer at codespeak.net
Sat Mar 25 08:25:12 CET 2006


Author: tismer
Date: Sat Mar 25 08:25:03 2006
New Revision: 24990

Modified:
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/genc.py
   pypy/dist/pypy/translator/c/pyobj.py
   pypy/dist/pypy/translator/c/test/test_wrapping.py
Log:
finally after lots of tiny hassles, here is a working implementation of
a generated extension module that exposes its classes and can really be used.

sigh :=)

The next thing to do should be to get rid of PyCObject and use a special
descendant of type object, instead.

Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Sat Mar 25 08:25:03 2006
@@ -18,7 +18,8 @@
 
 class LowLevelDatabase(object):
 
-    def __init__(self, translator=None, standalone=False, gcpolicy=None, thread_enabled=False):
+    def __init__(self, translator=None, standalone=False, gcpolicy=None, thread_enabled=False,
+                 instantiators={}):
         self.translator = translator
         self.standalone = standalone
         self.structdefnodes = {}
@@ -34,7 +35,7 @@
         self.infs = []
         self.namespace = CNameManager()
         if not standalone:
-            self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator)
+            self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator, instantiators)
         if gcpolicy is None:
             from pypy.translator.c import gc
             gcpolicy = gc.RefcountingGcPolicy

Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/dist/pypy/translator/c/genc.py	Sat Mar 25 08:25:03 2006
@@ -33,10 +33,11 @@
         self.libraries = libraries
         self.exports = {}
 
-    def build_database(self, exports=[]):
+    def build_database(self, exports=[], instantiators={}):
         translator = self.translator
         db = LowLevelDatabase(translator, standalone=self.standalone, 
-                              gcpolicy=self.gcpolicy, thread_enabled=self.thread_enabled)
+                              gcpolicy=self.gcpolicy, thread_enabled=self.thread_enabled,
+                              instantiators=instantiators)
 
         if self.stackless:
             from pypy.translator.c.stackless import StacklessData
@@ -50,8 +51,7 @@
         # need (we call this for its side-effects of db.get())
         list(db.gcpolicy.gc_startup_code())
 
-        # XXX the following has the side effect to generate
-        # some needed things. Find out why.
+        # build entrypoint and eventually other things to expose
         pf = self.getentrypointptr()
         pfname = db.get(pf)
         self.exports[self.entrypoint.func_name] = pf

Modified: pypy/dist/pypy/translator/c/pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/c/pyobj.py	(original)
+++ pypy/dist/pypy/translator/c/pyobj.py	Sat Mar 25 08:25:03 2006
@@ -5,9 +5,10 @@
 from pypy.objspace.flow.model import Variable, Constant
 from pypy.translator.gensupp import builtin_base
 from pypy.translator.c.support import log
+from pypy.translator.c.wrapper import gen_wrapper
 
 from pypy.rpython.rarithmetic import r_int, r_uint
-from pypy.rpython.lltypesystem.lltype import pyobjectptr, LowLevelType
+from pypy.rpython.lltypesystem.lltype import pyobjectptr
 
 # XXX maybe this can be done more elegantly:
 # needed to convince should_translate_attr
@@ -24,7 +25,7 @@
     reconstruct them.
     """
 
-    def __init__(self, namespace, getvalue, translator=None):
+    def __init__(self, namespace, getvalue, translator=None, instantiators={}):
         self.namespace = namespace
         self.getvalue = getvalue
         self.translator = translator
@@ -38,6 +39,7 @@
         self.debugstack = ()  # linked list of nested nameof()
         self.wrappers = {}    # {'pycfunctionvariable': ('name', 'wrapperfn')}
         self.import_hints = IMPORT_HINTS
+        self.instantiators = instantiators
 
     def nameof(self, obj, debug=None):
         if debug:
@@ -167,6 +169,9 @@
     def skipped_function(self, func):
         # debugging only!  Generates a placeholder for missing functions
         # that raises an exception when called.
+
+        # XXX this is broken after the translationcontext change!
+        # the frozen attribute is gone. What to do?
         if self.translator.frozen:
             warning = 'NOT GENERATING'
         else:
@@ -208,7 +213,6 @@
         if self.shouldskipfunc(func):
             return self.skipped_function(func)
 
-        from pypy.translator.c.wrapper import gen_wrapper
         fwrapper = gen_wrapper(func, self.translator)
         pycfunctionobj = self.uniquename('gfunc_' + func.__name__)
         self.wrappers[pycfunctionobj] = func.__name__, self.getvalue(fwrapper)
@@ -336,6 +340,9 @@
         return name
 
     def nameof_classobj(self, cls):
+        if cls in self.instantiators:
+            return self.wrap_exported_class(cls)
+
         if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'):
             raise Exception, "%r should never be reached" % (cls,)
 
@@ -345,7 +352,7 @@
         if issubclass(cls, Exception):
             # if cls.__module__ == 'exceptions':
             # don't rely on this, py.magic redefines AssertionError
-            if getattr(__builtin__,cls.__name__,None) is cls:
+            if getattr(__builtin__, cls.__name__, None) is cls:
                 name = self.uniquename('gexc_' + cls.__name__)
                 self.initcode_python(name, cls.__name__)
                 return name
@@ -521,3 +528,41 @@
         co = compile(source, '<initcode>', 'exec')
         del source
         return marshal.dumps(co), originalsource
+
+    # ____________________________________________________________-
+    # addition for true extension module building
+
+    def wrap_exported_class(self, cls):
+        metaclass = "type"
+        name = self.uniquename('gwcls_' + cls.__name__)
+        basenames = [self.nameof(base) for base in cls.__bases__]
+        def initclassobj():
+            content = cls.__dict__.items()
+            content.sort()
+            for key, value in content:
+                if key.startswith('__'):
+                    if key in ['__module__', '__doc__', '__dict__',
+                               '__weakref__', '__repr__', '__metaclass__']:
+                        continue
+                if self.shouldskipfunc(value):
+                    log.WARNING("skipped class function: %r" % value)
+                    continue
+                yield '%s.%s = property(lambda self:%s.__get__(self.__self__))' % (
+                    name, key, self.nameof(value))
+
+        baseargs = ", ".join(basenames)
+        if baseargs:
+            baseargs = '(%s)' % baseargs
+            
+        # fishing for the instantiator
+        instantiator = self.nameof(self.instantiators[cls])
+        a = self.initcode.append
+        a('class %s%s:'                     % (name, baseargs) )
+        a('    __metaclass__ = type')
+        a('    __slots__ = ["__self__"] # for PyCObject')
+        a('    def __new__(cls, *args, **kwds):')
+        a('        inst = object.__new__(cls)')
+        a('        inst.__self__ = %s()'    % instantiator)
+        a('        return inst')
+        self.later(initclassobj())
+        return name

Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_wrapping.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_wrapping.py	Sat Mar 25 08:25:03 2006
@@ -4,6 +4,7 @@
 from pypy.rpython import extregistry
 from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.objectmodel import instantiate
 
 P = False  # debug printing
 
@@ -18,7 +19,7 @@
     missing = [object] * (func.func_code.co_argcount - len(argstypelist))
     return missing + argstypelist
 
-def getcompiled(func, view=conftest.option.view, inline_threshold=1,
+def get_compiled_module(func, view=conftest.option.view, inline_threshold=1,
                 use_boehm=False, exports=[]):
     from pypy.translator.translator import TranslationContext
     from pypy.translator.backendopt.all import backend_optimizations
@@ -34,10 +35,15 @@
         t.viewcg()
     rtyper = t.buildrtyper()
     bk = rtyper.annotator.bookkeeper
+    instantiators = {}
     for obj in exports:
         if isinstance(obj, type):
-            cdef = bk.getuniqueclassdef(obj)
-            bk.needs_generic_instantiate[cdef] = True
+            cls = obj
+            def make():
+                return instantiate(cls)
+            make.__name__ = cls.__name__ + '__new__'
+            t.annotator.build_types(make, [])
+            instantiators[cls] = make
     rtyper.specialize()
     if view:
         t.viewcg()
@@ -53,13 +59,17 @@
 
     cbuilder = CExtModuleBuilder(t, func, gcpolicy=gcpolicy)
     # explicit build of database
-    db = cbuilder.build_database(exports=exports)
+    db = cbuilder.build_database(exports=exports, instantiators=instantiators)
     cbuilder.generate_source(db)
     cbuilder.compile()
 
     if view:
         t.viewcg()
-    return getattr(cbuilder.import_module(), func.__name__)
+    return cbuilder.import_module()
+
+def getcompiled(func, *args, **kwds):
+    module = get_compiled_module(func, *args, **kwds)
+    return getattr(module, func.__name__)
 
 # _______________________________________________-
 # stubs for special annotation/rtyping
@@ -230,9 +240,10 @@
     if P: print ret
     assert ret[0] == 1
 
-# exposing and using classes. almost ready, missing spots in the python delegation
+# exposing and using classes from a generasted extension module
 def test_expose_classes():
-    f = getcompiled(democlass_helper2, use_boehm=not True, exports=[
+    m = get_compiled_module(democlass_helper2, use_boehm=not True, exports=[
         DemoClass, DemoSubclass, DemoNotAnnotated])
-    res = f(2, 3)
-    if P: print 55*'-', res
+    obj = m.DemoClass(2, 3)
+    res = obj.demo()
+    assert res == DemoClass(2, 3).demo()



More information about the Pypy-commit mailing list