[pypy-svn] r44557 - in pypy/dist/pypy/translator/cli: . test

antocuni at codespeak.net antocuni at codespeak.net
Wed Jun 27 14:48:42 CEST 2007


Author: antocuni
Date: Wed Jun 27 14:48:41 2007
New Revision: 44557

Modified:
   pypy/dist/pypy/translator/cli/silverpython.py
   pypy/dist/pypy/translator/cli/test/test_silverpython.py
Log:
add the possibility to export classes.

A class is exported is its __init__ is marked with @export. Individual
methods can also be @exported, useful for methods that can't be
reached by one of the entrypoints.

To force the annotator to analyze a given method, we generates a dummy
function which call that method. Better approached are welcome.



Modified: pypy/dist/pypy/translator/cli/silverpython.py
==============================================================================
--- pypy/dist/pypy/translator/cli/silverpython.py	(original)
+++ pypy/dist/pypy/translator/cli/silverpython.py	Wed Jun 27 14:48:41 2007
@@ -9,6 +9,7 @@
 import new
 import types
 import os.path
+import inspect
 
 from pypy.translator.driver import TranslationDriver
 from pypy.translator.cli.entrypoint import DllEntryPoint
@@ -18,6 +19,9 @@
         self.name = name
         self.namespace = namespace
         self.functions = functions # [(function, annotation), ...]
+        self.driver = TranslationDriver()
+        self.driver.config.translation.ootype.mangle = False
+        self.driver.setup_library(self)
 
     def add_function(self, func, inputtypes):
         self.functions.append((func, inputtypes))
@@ -31,11 +35,7 @@
         for func, _ in self.functions:
             if not hasattr(func, '_namespace_'):
                 func._namespace_ = self.namespace
-        driver = TranslationDriver()
-        driver.config.translation.ootype.mangle = False
-        driver.setup_library(self)
-        driver.proceed(['compile_cli'])
-        return driver
+        self.driver.proceed(['compile_cli'])
 
 class export(object):
     def __new__(self, *args, **kwds):
@@ -57,25 +57,76 @@
             func._namespace_ = self.namespace
         return func
 
+def is_exported(obj):
+    return isinstance(obj, (types.FunctionType, types.UnboundMethodType)) \
+           and hasattr(obj, '_inputtypes_')
+
 def collect_entrypoints(dic):
     entrypoints = []
     for item in dic.itervalues():
-        if isinstance(item, types.FunctionType) and hasattr(item, '_inputtypes_'):
+        if is_exported(item):
             entrypoints.append((item, item._inputtypes_))
+        elif isinstance(item, types.ClassType) or isinstance(item, type):
+            entrypoints += collect_class_entrypoints(item)
+    return entrypoints
+
+def collect_class_entrypoints(cls):
+    try:
+        __init__ = cls.__init__
+        if not is_exported(__init__):
+            return []
+    except AttributeError:
+        return []
+
+    entrypoints = [(wrap_init(cls, __init__), __init__._inputtypes_)]
+    for item in cls.__dict__.itervalues():
+        if item is not __init__.im_func and is_exported(item):
+            inputtypes = (cls,) + item._inputtypes_
+            entrypoints.append((wrap_method(item), inputtypes))
     return entrypoints
 
+def getarglist(meth):
+    arglist, starargs, kwargs, defaults = inspect.getargspec(meth)
+    assert starargs is None, '*args not supported yet'
+    assert kwargs is None, '**kwds not supported yet'
+    assert defaults is None, 'default values not supported yet'
+    return arglist
+
+def wrap_init(cls, meth):
+    arglist = getarglist(meth)[1:] # discard self
+    args = ', '.join(arglist)
+    source = 'def __internal__ctor(%s): return %s(%s)' % (
+        args, cls.__name__, args)
+    mydict = {cls.__name__: cls}
+    print source
+    exec source in mydict
+    return mydict['__internal__ctor']
+
+def wrap_method(meth, is_init=False):
+    arglist = getarglist(meth)
+    name = '__internal__%s' % meth.func_name
+    selfvar = arglist[0]
+    args = ', '.join(arglist)
+    params = ', '.join(arglist[1:])
+    source = 'def %s(%s): return %s.%s(%s)' % (
+        name, args, selfvar, meth.func_name, params)
+    mydict = {}
+    print source
+    exec source in mydict
+    return mydict[name]
+
+
 def compile_dll(filename):
     _, name = os.path.split(filename)
     dllname, _ = os.path.splitext(name)
-
     module = new.module(dllname)
-    execfile(filename, module.__dict__)
-    entrypoints = collect_entrypoints(module.__dict__)
     namespace = module.__dict__.get('_namespace_', dllname)
-    
-    dll = DllDef(dllname, namespace, entrypoints)
-    driver = dll.compile()
-    driver.copy_cli_dll()
+    execfile(filename, module.__dict__)
+
+    dll = DllDef(dllname, namespace)
+    dll.functions = collect_entrypoints(module.__dict__)
+    dll.compile()
+    dll.driver.copy_cli_dll()
 
 def main(argv):
     if len(argv) != 2:

Modified: pypy/dist/pypy/translator/cli/test/test_silverpython.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_silverpython.py	(original)
+++ pypy/dist/pypy/translator/cli/test/test_silverpython.py	Wed Jun 27 14:48:41 2007
@@ -1,6 +1,7 @@
 from pypy.tool import udir
 from pypy.translator.cli.rte import Target
-from pypy.translator.cli.silverpython import DllDef, export, collect_entrypoints
+from pypy.translator.cli.silverpython import DllDef, export, collect_entrypoints,\
+     collect_class_entrypoints
 from pypy.translator.cli.test.runtest import CliFunctionWrapper, CliTest
 
 TEMPLATE = """
@@ -82,3 +83,42 @@
         mydict = dict(foo=foo, bar=bar, x=42)
         entrypoints = collect_entrypoints(mydict)
         assert entrypoints == [(foo, (int, float))]
+
+    def test_collect_class_entrypoints(self):
+        class NotExported:
+            def __init__(self):
+                pass
+            
+        class MyClass:
+            @export
+            def __init__(self):
+                pass
+            @export(int)
+            def foo(self, x):
+                return x
+
+        assert collect_class_entrypoints(NotExported) == []
+        entrypoints = collect_class_entrypoints(MyClass)
+        assert len(entrypoints) == 2
+        assert entrypoints[0][1] == () # __init__ inputtypes
+        assert entrypoints[1][1] == (MyClass, int) # foo inputtypes
+        
+    def test_compile_class(self):
+        class MyClass:
+            @export(int)
+            def __init__(self, x):
+                self.x = x
+            @export(int, int)
+            def add(self, y, z):
+                return self.x + y + z
+        MyClass.__module__ = 'Test' # put the class in the Test namespace
+
+        entrypoints = collect_entrypoints({'MyClass': MyClass})
+        dll = DllDef('test', 'Test', entrypoints)
+        dll.compile()
+        res = self._csharp('test', """
+            Test.MyClass obj = new Test.MyClass();
+            obj.__init___variant0(39);
+            Console.WriteLine(obj.add_variant0(1, 2));
+        """)
+        assert res == 42



More information about the Pypy-commit mailing list