[pypy-svn] r26043 - in pypy/dist/pypy/translator/llvm/wrapable: . test

ericvrp at codespeak.net ericvrp at codespeak.net
Thu Apr 20 16:18:07 CEST 2006


Author: ericvrp
Date: Thu Apr 20 16:17:39 2006
New Revision: 26043

Added:
   pypy/dist/pypy/translator/llvm/wrapable/
   pypy/dist/pypy/translator/llvm/wrapable/__init__.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/libllvm.cpp
   pypy/dist/pypy/translator/llvm/wrapable/libllvm.h
   pypy/dist/pypy/translator/llvm/wrapable/llvm.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/llvm_helper.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/setup.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/test/
   pypy/dist/pypy/translator/llvm/wrapable/test/test_llvm.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/wrap_llvm.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/wrapable.py   (contents, props changed)
   pypy/dist/pypy/translator/llvm/wrapable/wrapper.py   (contents, props changed)
Log:
Code I have been working on for to long without staying in contact with the
other PyPy developers.

It's purpose is to use C++ libraries with (r)ctypes.
The code will generate .h, .cpp and .py files out of a class specification.

This specs look similar to boost.Python . From my experience with prior
project I know that C++ header files with all it's inline function, templates,
etc. quickly become to complicated to handle automaticly. Even with a tool such
as gccxml there are often no clear cut solutions. That is the why.

As an example you can look at wrap_llvm.py , which when executed creates libllvm.h
libllvm.cpp (the C API) and llvm.py (the Python classes which mimic the C++ API's
behaviour)

A pointer to the original C++ object is stored in the 'instance' attribute of the
Python class. Whenever one of these Python objects is used as a parameter ctypes
automatically uses the objects 'instance' attribute instead. (see wrapper.py from_param)
I am no sure if we (can) support this in rctypes as well, otherwise this tool could
do it for us.

I hope this code can be of use and that I did not isolate me too much for too long!



Added: pypy/dist/pypy/translator/llvm/wrapable/__init__.py
==============================================================================

Added: pypy/dist/pypy/translator/llvm/wrapable/libllvm.cpp
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/libllvm.cpp	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,116 @@
+// llvm.cpp
+
+#include "libllvm.h"
+
+// Helper functions (mostly for casting returnvalues and parameters)
+char* as_c_string(std::string str) {
+    return (char*)str.c_str();
+}
+
+std::string as_std_string(char* p) {
+    return std::string(p);
+}
+
+std::vector<GenericValue>   as_vector_GenericValue(GenericValue* gv) {
+    std::vector<GenericValue>   gvv;
+    gvv.push_back(*gv);
+    return gvv;
+}
+
+// ExecutionEngine
+ExecutionEngine* ExecutionEngine_create(ModuleProvider* P0,long P1) {
+    return (ExecutionEngine*)ExecutionEngine::create(P0,P1);
+}
+
+Module& ExecutionEngine_getModule(ExecutionEngine* P0) {
+    return (Module&)P0->getModule();
+}
+
+void ExecutionEngine_freeMachineCodeForFunction(ExecutionEngine* P0,Function* P1) {
+    return (void)P0->freeMachineCodeForFunction(P1);
+}
+
+GenericValue ExecutionEngine_runFunction(ExecutionEngine* P0,Function* P1,GenericValue* P2) {
+    return (GenericValue)P0->runFunction(P1,as_vector_GenericValue(P2));
+}
+
+
+// ModuleProvider
+
+// ExistingModuleProvider
+ExistingModuleProvider* ExistingModuleProvider___init__(Module* P0) {
+    return new ExistingModuleProvider(P0);
+}
+
+
+// Function
+void Function_eraseFromParent(Function* P0) {
+    return (void)P0->eraseFromParent();
+}
+
+FunctionType* Function_getFunctionType(Function* P0) {
+    return (FunctionType*)P0->getFunctionType();
+}
+
+
+// FunctionType
+
+// GenericValue
+
+// TypeID
+
+// Type
+TypeID* Type_getTypeID(Type* P0) {
+    return (TypeID*)P0->getTypeID();
+}
+
+Type* Type_getContainedType(Type* P0,long P1) {
+    return (Type*)P0->getContainedType(P1);
+}
+
+char* Type_getDescription(Type* P0) {
+    return (char*)as_c_string(P0->getDescription());
+}
+
+
+// Module
+Module* Module___init__(char* P0) {
+    return new Module(as_std_string(P0));
+}
+
+char* Module_getModuleIdentifier(Module* P0) {
+    return (char*)as_c_string(P0->getModuleIdentifier());
+}
+
+void Module_setModuleIdentifier(Module* P0,char* P1) {
+    return (void)P0->setModuleIdentifier(P1);
+}
+
+char* Module_getTargetTriple(Module* P0) {
+    return (char*)as_c_string(P0->getTargetTriple());
+}
+
+void Module_setTargetTriple(Module* P0,char* P1) {
+    return (void)P0->setTargetTriple(P1);
+}
+
+char* Module_getModuleInlineAsm(Module* P0) {
+    return (char*)as_c_string(P0->getModuleInlineAsm());
+}
+
+void Module_setModuleInlineAsm(Module* P0,char* P1) {
+    return (void)P0->setModuleInlineAsm(P1);
+}
+
+Function* Module_getNamedFunction(Module* P0,char* P1) {
+    return (Function*)P0->getNamedFunction(P1);
+}
+
+Function* Module_getOrInsertFunction(Module* P0,char* P1,FunctionType* P2) {
+    return (Function*)P0->getOrInsertFunction(P1,P2);
+}
+
+
+
+
+// end of llvm.cpp

Added: pypy/dist/pypy/translator/llvm/wrapable/libllvm.h
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/libllvm.h	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,63 @@
+#ifndef __llvm_H__
+#define __llvm_H__
+
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/Function.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Type.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+
+using namespace llvm;
+#define TypeID int
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ExecutionEngine
+ExecutionEngine* ExecutionEngine_create(ModuleProvider*,long);
+Module& ExecutionEngine_getModule(ExecutionEngine*);
+void ExecutionEngine_freeMachineCodeForFunction(ExecutionEngine*,Function*);
+GenericValue ExecutionEngine_runFunction(ExecutionEngine*,Function*,GenericValue*);
+
+// ModuleProvider
+
+// ExistingModuleProvider
+ExistingModuleProvider* ExistingModuleProvider___init__(Module*);
+
+// Function
+void Function_eraseFromParent(Function*);
+FunctionType* Function_getFunctionType(Function*);
+
+// FunctionType
+
+// GenericValue
+
+// TypeID
+
+// Type
+TypeID* Type_getTypeID(Type*);
+Type* Type_getContainedType(Type*,long);
+char* Type_getDescription(Type*);
+
+// Module
+Module* Module___init__(char*);
+char* Module_getModuleIdentifier(Module*);
+void Module_setModuleIdentifier(Module*,char*);
+char* Module_getTargetTriple(Module*);
+void Module_setTargetTriple(Module*,char*);
+char* Module_getModuleInlineAsm(Module*);
+void Module_setModuleInlineAsm(Module*,char*);
+Function* Module_getNamedFunction(Module*,char*);
+Function* Module_getOrInsertFunction(Module*,char*,FunctionType*);
+
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif  // __llvm_H__

Added: pypy/dist/pypy/translator/llvm/wrapable/llvm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/llvm.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,154 @@
+# llvm.py
+
+from wrapper import Wrapper
+from ctypes import *
+import llvm_helper
+
+
+llvm = cdll.load('libllvm.so')
+STRING = c_char_p
+
+class ExecutionEngine(Wrapper):
+    def __init__(P0,P1,P2=False):
+       P0.instance = llvm_helper.ExecutionEngine___init__(P0,P1,P2)
+
+    def create(P0,P1=False):
+        return llvm.ExecutionEngine_create(P0,P1)
+    create = staticmethod(create)
+
+    def getModule(P0):
+        return llvm.ExecutionEngine_getModule(P0)
+
+    def freeMachineCodeForFunction(P0,P1):
+        return llvm.ExecutionEngine_freeMachineCodeForFunction(P0,P1)
+
+    def runFunction(P0,P1,P2):
+        return llvm.ExecutionEngine_runFunction(P0,P1,P2)
+
+class ModuleProvider(Wrapper):
+    pass
+
+class ExistingModuleProvider(Wrapper):
+    def __init__(P0,P1):
+       P0.instance = llvm.ExistingModuleProvider___init__(P1)
+
+class Function(Wrapper):
+    def eraseFromParent(P0):
+        return llvm.Function_eraseFromParent(P0)
+
+    def getFunctionType(P0):
+        return llvm.Function_getFunctionType(P0)
+
+class FunctionType(Wrapper):
+    pass
+
+class GenericValue(Wrapper):
+    pass
+
+class TypeID(Wrapper):
+    pass
+
+class Type(Wrapper):
+    def getTypeID(P0):
+        return llvm.Type_getTypeID(P0)
+
+    def getContainedType(P0,P1):
+        return llvm.Type_getContainedType(P0,P1)
+
+    def getDescription(P0):
+        return llvm.Type_getDescription(P0)
+
+class Module(Wrapper):
+    def __init__(P0,P1='mymodule'):
+       P0.instance = llvm.Module___init__(P1)
+
+    def getModuleIdentifier(P0):
+        return llvm.Module_getModuleIdentifier(P0)
+
+    def setModuleIdentifier(P0,P1='myothermodule'):
+        return llvm.Module_setModuleIdentifier(P0,P1)
+
+    def getTargetTriple(P0):
+        return llvm.Module_getTargetTriple(P0)
+
+    def setTargetTriple(P0,P1):
+        return llvm.Module_setTargetTriple(P0,P1)
+
+    def getModuleInlineAsm(P0):
+        return llvm.Module_getModuleInlineAsm(P0)
+
+    def setModuleInlineAsm(P0,P1):
+        return llvm.Module_setModuleInlineAsm(P0,P1)
+
+    def getNamedFunction(P0,P1):
+        return llvm.Module_getNamedFunction(P0,P1)
+
+    def getOrInsertFunction(P0,P1,P2):
+        return llvm.Module_getOrInsertFunction(P0,P1,P2)
+
+    def n_functions(P0):
+        return llvm_helper.n_functions(P0)
+
+    def function_exists(P0,P1='myfunction'):
+        return llvm_helper.function_exists(P0,P1)
+
+llvm.ExecutionEngine_create.restype  = ExecutionEngine
+llvm.ExecutionEngine_create.argtypes = [ModuleProvider,c_long]
+
+llvm.ExecutionEngine_getModule.restype  = Module
+llvm.ExecutionEngine_getModule.argtypes = [ExecutionEngine]
+
+llvm.ExecutionEngine_freeMachineCodeForFunction.restype  = None
+llvm.ExecutionEngine_freeMachineCodeForFunction.argtypes = [ExecutionEngine,Function]
+
+llvm.ExecutionEngine_runFunction.restype  = GenericValue
+llvm.ExecutionEngine_runFunction.argtypes = [ExecutionEngine,Function,GenericValue]
+
+llvm.ExistingModuleProvider___init__.restype  = ExistingModuleProvider
+llvm.ExistingModuleProvider___init__.argtypes = [Module]
+
+llvm.Function_eraseFromParent.restype  = None
+llvm.Function_eraseFromParent.argtypes = [Function]
+
+llvm.Function_getFunctionType.restype  = FunctionType
+llvm.Function_getFunctionType.argtypes = [Function]
+
+llvm.Type_getTypeID.restype  = TypeID
+llvm.Type_getTypeID.argtypes = [Type]
+
+llvm.Type_getContainedType.restype  = Type
+llvm.Type_getContainedType.argtypes = [Type,c_long]
+
+llvm.Type_getDescription.restype  = STRING
+llvm.Type_getDescription.argtypes = [Type]
+
+llvm.Module___init__.restype  = Module
+llvm.Module___init__.argtypes = [STRING]
+
+llvm.Module_getModuleIdentifier.restype  = STRING
+llvm.Module_getModuleIdentifier.argtypes = [Module]
+
+llvm.Module_setModuleIdentifier.restype  = None
+llvm.Module_setModuleIdentifier.argtypes = [Module,STRING]
+
+llvm.Module_getTargetTriple.restype  = STRING
+llvm.Module_getTargetTriple.argtypes = [Module]
+
+llvm.Module_setTargetTriple.restype  = None
+llvm.Module_setTargetTriple.argtypes = [Module,STRING]
+
+llvm.Module_getModuleInlineAsm.restype  = STRING
+llvm.Module_getModuleInlineAsm.argtypes = [Module]
+
+llvm.Module_setModuleInlineAsm.restype  = None
+llvm.Module_setModuleInlineAsm.argtypes = [Module,STRING]
+
+llvm.Module_getNamedFunction.restype  = Function
+llvm.Module_getNamedFunction.argtypes = [Module,STRING]
+
+llvm.Module_getOrInsertFunction.restype  = Function
+llvm.Module_getOrInsertFunction.argtypes = [Module,STRING,FunctionType]
+
+
+
+# end of llvm.py

Added: pypy/dist/pypy/translator/llvm/wrapable/llvm_helper.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/llvm_helper.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,16 @@
+#Module helper methods
+def n_functions(self): #TODO
+    return 0
+
+def function_exists(self, name):  #TODO
+    return False
+
+#ExecutionEngine helper methods
+def ExecutionEngine___init__(self, mp, ForceInterpreter=False):
+    return self.create(mp, ForceInterpreter)
+
+def delete(self, fnname):
+    mod = self.getModule()
+    f = mod.getNamedFunction(fnname)    # XXX handle fnname not found?
+    self.freeMachineCodeForFunction(f)  # still no-op on march 27th 2006
+    f.eraseFromParent()

Added: pypy/dist/pypy/translator/llvm/wrapable/setup.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/setup.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+from distutils.extension import Extension
+from os import popen
+import sys
+
+
+if len(sys.argv) <= 1:
+    print 'usage: setup.py <module_name> .... (the usual setup.py options)'
+    sys.exit()
+module_name = sys.argv[1]
+del sys.argv[1]
+
+cxxflags = popen('llvm-config --cxxflags').readline().split()
+ldflags  = popen('llvm-config --ldflags').readline().split()
+libs     = popen('llvm-config --libs all').readline().split()
+
+opts = dict(name=module_name,
+            sources=[module_name + '.cpp'],
+            libraries=[],
+            include_dirs =["include"] + [f[2:] for f in cxxflags if f.startswith('-I')],
+            library_dirs =[f[2:] for f in ldflags  if f.startswith('-L')],
+            define_macros=[(f[2:], None) for f in cxxflags if f.startswith('-D')],
+            extra_objects=libs)
+
+ext_modules = Extension(**opts)
+
+setup(name=opts['name'], ext_modules=[ext_modules])

Added: pypy/dist/pypy/translator/llvm/wrapable/test/test_llvm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/test/test_llvm.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,99 @@
+import py
+from pypy.translator.llvm.wrapable.llvm import *
+
+
+#XXX The tests below were shamefully never written when writing the rest of the code and
+#    should therefor be filled in by Eric asap.
+
+def test_misc():
+    print 'Module("mine")'
+    mod = Module('mine')
+    print 'mod=', mod
+    print 'mod.instance=', mod.instance
+    print
+    assert mod.n_functions() == 0
+
+    print 'ExistingModuleProvider(mod)'
+    mp = ExistingModuleProvider(mod)
+    print 'mp=', mp
+    print 'mp.instance=', mp.instance
+    print
+
+    ee = ExecutionEngine(mp)
+    #ee = ExecutionEngine.create(mp)    #same
+    print 'ee=', ee
+    #print 'ee.instance=', ee.instance  #can't do here because ee.create is staticmethod
+    mod2 = ee.getModule()
+    print mod2
+
+    print 'mod.getModuleIdentifier()'
+    modId = mod.getModuleIdentifier()
+    print 'modId=', modId
+    assert modId == 'mine'
+    assert modId == mod2.getModuleIdentifier()
+
+def test_wrapable_create():
+    pass
+
+def test_global_function():
+    pass
+
+def test_class():
+    pass
+
+def test_class_ctor():
+    pass
+
+def test_class_dtor():
+    pass
+
+def test_method():
+    pass
+
+def test_staticmethod():
+    pass
+
+def test_staticmethod_as_factory(): #self.instance can not be set in this case
+    pass
+
+def test_classmethod():
+    pass
+
+def test_include():
+    pass
+
+def test_include_py():
+    pass
+
+def test_call_pymethod():
+    pass
+
+def test_call_pyctor():
+    pass
+
+def test_call_pystaticmethod():
+    pass
+
+def test_call_pyclassmethod():
+    pass
+
+def test_call_pyfunction():
+    pass
+
+def test_cpp_cast():
+    pass
+
+def test_py_cast():
+    pass
+
+def test_enum():
+    pass
+
+def test_structure():
+    pass
+
+def test_ref_ptr_inst():
+    pass
+
+def test_default_arguments():
+    pass

Added: pypy/dist/pypy/translator/llvm/wrapable/wrap_llvm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/wrap_llvm.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+from wrapable import *
+from ctypes import *
+
+
+# All the classes we wrap in the module...
+Global                 = Wglobal()
+ExecutionEngine        = Wclass('ExecutionEngine'       , [])
+ModuleProvider         = Wclass('ModuleProvider'        , [])
+ExistingModuleProvider = Wclass('ExistingModuleProvider', [ModuleProvider])
+Function               = Wclass('Function'              , [])
+FunctionType           = Wclass('FunctionType'          , [])
+GenericValue           = Wclass('GenericValue'          , [])
+TypeID                 = Enum('TypeID'                  , [])
+Type                   = Wclass('Type'                  , [])
+Module                 = Wclass('Module'                , [])
+
+# Helper functions
+as_c_string = CppCast('as_c_string', STRING)
+as_std_string = CppCast('as_std_string', STRING)
+as_vector_GenericValue = CppCast('as_vector_GenericValue', GenericValue)
+
+# All the functions (XXX not working/output yet)
+Global\
+    .add(Wfunction(None , 'ParseAssemblyString', [Module, STRING]))\
+    .add(Wfunction(c_int, 'verifyModule'       , [Module]))
+
+# All the methods each class contains...
+ExecutionEngine\
+    .add(Wctor(ExecutionEngine, [ModuleProvider,c_int], [False],\
+               'llvm_helper.ExecutionEngine___init__'))\
+    .add(Wstaticmethod(ExecutionEngine, 'create', [ModuleProvider,c_int], [False]))\
+    .add(Wmethod(Ref(Module)         , 'getModule', []))\
+    .add(Wmethod(None                , 'freeMachineCodeForFunction', [Function]))\
+    .add(Wmethod(Inst(GenericValue)  , 'runFunction', [Function,as_vector_GenericValue]))
+
+ExistingModuleProvider\
+    .add(Wctor(ExistingModuleProvider, [Module]))
+
+Function\
+    .add(Wmethod(None        , 'eraseFromParent', []))\
+    .add(Wmethod(FunctionType, 'getFunctionType', []))
+    
+Type\
+    .add(Wmethod(TypeID      , 'getTypeID', []))\
+    .add(Wmethod(Type        , 'getContainedType', [c_int]))\
+    .add(Wmethod(as_c_string , 'getDescription', []))
+
+Module\
+    .add(Wctor(Module, [as_std_string], ['mymodule']))\
+    .add(Wmethod(as_c_string , 'getModuleIdentifier', []))\
+    .add(Wmethod(None        , 'setModuleIdentifier', [STRING], ['myothermodule']))\
+    .add(Wmethod(as_c_string , 'getTargetTriple', []))\
+    .add(Wmethod(None        , 'setTargetTriple', [STRING]))\
+    .add(Wmethod(as_c_string , 'getModuleInlineAsm', []))\
+    .add(Wmethod(None        , 'setModuleInlineAsm', [STRING]))\
+    .add(Wmethod(Function    , 'getNamedFunction', [STRING]))\
+    .add(Wmethod(Function    , 'getOrInsertFunction', [STRING, FunctionType]))\
+    .add(Wmethod(c_int       , 'llvm_helper.n_functions', []))\
+    .add(Wmethod(c_int       , 'llvm_helper.function_exists', [STRING], ['myfunction']))
+
+# Create the module...
+Wroot('llvm')\
+    .include('llvm/Module.h')\
+    .include('llvm/ModuleProvider.h')\
+    .include('llvm/Function.h')\
+    .include('llvm/DerivedTypes.h')\
+    .include('llvm/Type.h')\
+    .include('llvm/Analysis/Verifier.h')\
+    .include('llvm/ExecutionEngine/ExecutionEngine.h')\
+    .include('llvm/ExecutionEngine/GenericValue.h')\
+    .include('llvm_helper.py')\
+    .add(Global)\
+    .add(ExecutionEngine)\
+    .add(ModuleProvider)\
+    .add(ExistingModuleProvider)\
+    .add(Function)\
+    .add(FunctionType)\
+    .add(GenericValue)\
+    .add(TypeID)\
+    .add(Type)\
+    .add(Module)\
+    .create()

Added: pypy/dist/pypy/translator/llvm/wrapable/wrapable.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/wrapable.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,396 @@
+import types
+from ctypes import *
+
+STRING = c_char_p
+
+def log(msg):
+    print msg
+    pass
+
+
+class T(object):
+    def __init__(self, item):
+        self.item = item
+class Inst(T):  pass
+class Ref(T):   pass
+#class Ptr(T):   pass
+
+
+class Cast(object):
+    def __init__(self, cppfunc, item):
+        self.cppfunc = cppfunc
+        self.item    = item
+class CppCast(Cast):    pass
+#class PyCast(Cast):     pass
+
+
+class _CTypesInfo(object):
+    def __init__(self, ctypesname, cppname):
+        self.ctypesname = ctypesname
+        self.cppname    = cppname
+
+_ctypesinfo = {
+    None            : _CTypesInfo('None'       , 'void'),
+    c_char          : _CTypesInfo('c_char'     , 'char'),
+    c_byte          : _CTypesInfo('c_byte'     , 'char'),
+    c_ubyte         : _CTypesInfo('c_ubyte'    , 'unsigned char'),
+    c_short         : _CTypesInfo('c_short'    , 'short'),
+    c_ushort        : _CTypesInfo('c_ushort'   , 'unsigned short'),
+    c_int           : _CTypesInfo('c_int'      , 'int'),
+    c_uint          : _CTypesInfo('c_uint'     , 'unsigned int'),
+    c_long          : _CTypesInfo('c_long'     , 'long'),
+    c_ulong         : _CTypesInfo('c_ulong'    , 'unsigned long'),
+    c_longlong      : _CTypesInfo('c_longlong' , 'long long'),
+    c_ulonglong     : _CTypesInfo('c_ulonglong', 'unsigned long long'),
+    c_float         : _CTypesInfo('c_float'    , 'float'),
+    c_double        : _CTypesInfo('c_double'   , 'double'),
+    c_char_p        : _CTypesInfo('STRING'     , 'char*'),
+    c_wchar_p       : _CTypesInfo('c_wchar_p'  , 'wchar_t*'),
+    c_void_p        : _CTypesInfo('c_void_p'   , 'void*'),
+    }
+
+def _ctypes_type(t):
+    if isinstance(t, Cast):
+        t = t.item
+    if t in _ctypesinfo:
+        return _ctypesinfo[t].ctypesname
+    if isinstance(t, Wclass):
+        return t.name
+    if isinstance(t, (Inst, Ref)) and isinstance(t.item, Wclass):
+        return t.item.name
+    raise TypeError('unknown type %s' % t)
+
+
+def _cpp_type(t):
+    if isinstance(t, Cast):
+        t = t.item
+    if t in _ctypesinfo:
+        return _ctypesinfo[t].cppname
+    if isinstance(t, Wclass):
+        return t.name + '*'
+    if isinstance(t, Inst):
+        return t.item.name
+    if isinstance(t, Ref) and isinstance(t.item, Wclass):
+        return t.item.name + '&'
+    raise TypeError('unknown type %s' % t)
+h_type = _cpp_type
+
+
+class _Witem(object):
+    def __init__(self):
+        self.items = []
+
+    def add(self, item):
+        self.items.append(item)
+        return self
+
+    def header(self):
+        pass
+
+    def cpp(self):
+        pass
+
+    def py(self):
+        pass
+
+    def finish_declaration(self, parent_item):
+        for item in self.items:
+            item.finish_declaration(self)
+
+
+class Wfunction(_Witem):
+    def __init__(self, ret, name, param):
+        super(Wfunction, self).__init__()
+        self.ret   = ret
+        self.name  = name
+        self.param = param
+
+
+class Wmethod(_Witem):
+    def __init__(self, ret, name, param, defaults=[]):
+        super(Wmethod, self).__init__()
+        self.ret   = ret
+        self.name  = name
+        self.param = param
+        self.defaults = defaults
+        self._self_was_added = False
+
+    def finish_declaration(self, parent_item):
+        super(Wmethod, self).finish_declaration(parent_item)
+        if not self._self_was_added and not isinstance(self, Wstaticmethod):
+            self.param.insert(0, parent_item)
+            self._self_was_added = True
+
+    def _is_pyfunc(self):
+        return '.' in self.name
+
+    def _plain_name(self):
+        if self._is_pyfunc():
+            return self.name.split('.',1)[1]
+        return self.name
+
+    def _callee_name(self, namespace, funcname):
+        if self._is_pyfunc():
+            return self.name
+        return '%s.%s_%s' % (namespace, funcname, self.name)
+
+
+class Wstaticmethod(Wmethod):
+    pass
+
+
+class Wctor(Wmethod):    #Wrapped constructor
+    #XXX I don't like the fact that the returntype needs to be specified.
+    #    We need to somehow keep a link to the parent!
+    #    (maybe set a parent attribute in the .add methods?)
+    def __init__(self, ret, param, defaults=[], name='__init__'):
+        #note: The order is different from Wmethod because name would seldomly be supplied.
+        #      Probably this will only happen when a Python function should be called instead.
+        super(Wctor, self).__init__(ret, name, param, defaults)
+
+
+class Wclass(_Witem):
+    def __init__(self, name, parents=[]):
+        super(Wclass, self).__init__()
+        self.name     = name
+        self.parents  = parents
+Enum = Wclass #XXX temporary hack
+
+
+class Wglobal(_Witem):
+    pass
+
+
+class Wroot(_Witem):    #root wrapable object
+
+    header_template = '''#ifndef __%(name)s_H__
+#define __%(name)s_H__
+
+%(includes)s
+using namespace %(namespace)s;
+#define TypeID int
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+%(code)s
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif  // __%(name)s_H__
+'''
+
+    cpp_template = '''// %(name)s.cpp
+
+#include "lib%(name)s.h"
+
+// Helper functions (mostly for casting returnvalues and parameters)
+char* as_c_string(std::string str) {
+    return (char*)str.c_str();
+}
+
+std::string as_std_string(char* p) {
+    return std::string(p);
+}
+
+std::vector<GenericValue>   as_vector_GenericValue(GenericValue* gv) {
+    std::vector<GenericValue>   gvv;
+    gvv.push_back(*gv);
+    return gvv;
+}
+
+%(code)s
+
+// end of %(name)s.cpp
+'''
+
+    py_template = '''# %(name)s.py
+
+from wrapper import Wrapper
+from ctypes import *
+%(includes)s
+
+%(name)s = cdll.load('lib%(name)s.so')
+STRING = c_char_p
+
+%(code)s
+
+# end of %(name)s.py
+'''
+
+    def __init__(self, name):
+        super(Wroot, self).__init__()
+        self.name     = name
+        self.includes = []
+        log('Creating %s module' % name)
+
+    def include(self, include):
+        self.includes.append(include)
+        return self #to allow chaining
+
+    def header(self):
+        name = self.name
+        code = ''
+
+        includes = ''
+        for include in self.includes:
+            if include.endswith('.h'):
+                includes += '#include "%s"\n' % include
+
+        namespace = self.name   #XXX
+
+        for item in self.items:
+            if isinstance(item, Wglobal):
+                continue
+            code += '// %s\n' % item.name
+            for method in item.items:
+                if method._is_pyfunc():
+                    continue
+                restype  = h_type(method.ret)
+                argtypes = [h_type(p) for p in method.param]
+                if isinstance(method, Wctor):
+                    del argtypes[0]
+                code += '%s %s_%s(%s);\n' % (restype, item.name, method.name, ','.join(argtypes))
+            code += '\n'
+
+        return self.header_template % locals()
+
+    def _casted_arg(self, i, arg):
+        if isinstance(arg, CppCast):
+            return '%s(P%d)' % (arg.cppfunc, i)
+        return 'P%d' % i
+
+    def cpp(self):
+        name = self.name
+        code = ''
+        for item in self.items:
+            if isinstance(item, Wglobal):
+                continue
+            code += '// %s\n' % item.name
+            for method in item.items:
+                if method._is_pyfunc():
+                    continue
+                restype  = _cpp_type(method.ret)
+                param    = method.param[isinstance(method, Wctor):]
+                argtypes = ['%s P%d' % (_cpp_type(p),i) for i,p in enumerate(param)]
+                code += '%s %s_%s(%s) {\n' % (restype, item.name, method.name, ','.join(argtypes))
+                #for i,p in enumerate(method.param):
+                #    code += '    %s p%d = (%s)P%d;\n' % (_cpp_type(p), i, _cpp_type(p), i)
+                retcast = '(%s)' % restype
+                if isinstance(method.ret, CppCast):
+                    retcast_pre  = '%s(' % method.ret.cppfunc
+                    retcast_post = ')'
+                else:
+                    retcast_pre  = ''
+                    retcast_post = ''
+                if isinstance(method, Wstaticmethod):
+                    args  = [self._casted_arg(i,p) for i,p in enumerate(method.param)]
+                    code += '    return %s%s%s::%s(%s)%s;\n}\n\n' % \
+                        (retcast, retcast_pre, item.name, method.name,
+                         ','.join(args), retcast_post)
+                elif isinstance(method, Wctor):
+                    #args = [self._casted_arg(i+1,p) for i,p in enumerate(method.param[1:])]
+                    args = [self._casted_arg(i,p) for i,p in enumerate(param)]
+                    code += '    return %snew %s(%s)%s;\n}\n\n' % \
+                        (retcast_pre, item.name, ','.join(args), retcast_post)
+                else:
+                    args = [self._casted_arg(i+1,p) for i,p in enumerate(method.param[1:])]
+                    code += '    return %s%sP0->%s(%s)%s;\n}\n\n' % \
+                        (retcast, retcast_pre, method.name,
+                         ','.join(args), retcast_post)
+            code += '\n'
+        return self.cpp_template % locals()
+
+    def py(self):
+        name = self.name
+        code = ''
+
+        includes = ''
+        for include in self.includes:
+            if include.endswith('.py'):
+                includes += 'import %s\n' % include[:-3]
+
+        # output classes, methods, etc.
+        for item in self.items:
+            if isinstance(item, Wglobal):
+                continue
+            code += 'class %s(Wrapper):\n' % item.name
+            for method in item.items:
+                param = ['P%d' % i for i,p in enumerate(method.param)]
+                plain_name  = method._plain_name()
+                callee_name = method._callee_name(self.name, item.name)
+                params = ''
+                for i, p in enumerate(param):
+                    if params:
+                        params += ','
+                    params += p
+                    n = len(method.defaults) - len(param) + i
+                    if n >= 0:
+                        params += '=' + repr(method.defaults[n])
+                if isinstance(method, Wctor):
+                    #We made sure the header and cpp file constructors don't get the python 'self'.
+                    #Now we have to make sure we only pass 'self' to python helpers.
+                    code += '    def __init__(%s):\n' % params
+                    code += '       P0.instance = %s(%s)\n' % (
+                        callee_name, ','.join(param[not method._is_pyfunc():]))
+                else:
+                    code += '    def %s(%s):\n' % (plain_name, params)
+                    code += '        return %s(%s)\n' % (
+                        callee_name, ','.join(param))
+                if isinstance(method, Wstaticmethod):
+                    code += '    %s = staticmethod(%s)\n' % (plain_name, plain_name)
+                code += '\n'
+            if not item.items:
+                code += '    pass\n\n'
+
+        # output return and parameter (c)types
+        for item in self.items:
+            if isinstance(item, Wglobal):
+                continue
+            for method in item.items:
+                if method._is_pyfunc():
+                    continue
+                n = int(isinstance(method, Wctor))
+                restype  = _ctypes_type(method.ret)
+                argtypes = ','.join([_ctypes_type(p) for p in method.param[n:]])
+                if isinstance(method, Wstaticmethod):
+                    im_func = ''
+                else:
+                    im_func = 'im_func.'
+                code += 'llvm.%s_%s.restype  = %s\n'     % (
+                    item.name, method.name, restype)
+                code += 'llvm.%s_%s.argtypes = [%s]\n\n' % (
+                    item.name, method.name, argtypes)
+
+        return self.py_template % locals()
+
+    def create_files(self):
+        log('Creating ' + self.name + '.py')
+        f = open(self.name + '.py', 'w')
+        code = self.py()
+        f.write(code)
+        f.close()
+
+        log('Creating lib' + self.name + '.h')
+        f = open('lib' + self.name + '.h', 'w')
+        code = self.header()
+        f.write(code)
+        f.close()
+
+        log('Creating lib' + self.name + '.cpp')
+        f = open('lib' + self.name + '.cpp', 'w')
+        code = self.cpp()
+        f.write(code)
+        f.close()
+
+    def create_library(self):
+        from os import system
+        system('python setup.py lib%s build_ext -i' % self.name)
+
+    def create(self):
+        self.finish_declaration(None)
+        self.create_files()
+        self.create_library()

Added: pypy/dist/pypy/translator/llvm/wrapable/wrapper.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/llvm/wrapable/wrapper.py	Thu Apr 20 16:17:39 2006
@@ -0,0 +1,19 @@
+from ctypes import c_int
+
+
+class Wrapper(c_int):   #c_int because it needs to be a ctypes datatype for from_param to work
+    def from_param(cls, p):
+        try:
+            return p.instance
+        except:
+            #XXX This might happen if we use a staticmethod (factory) to create a function.
+            #    In that case we have no 'self' to store the instance in.
+            #    An example of this can be found in wrap_llvm.py/ExecutionEngine.create
+            return p
+    from_param = classmethod(from_param)
+
+    #def errcheck(retval, function, arguments):
+    #    print 'Wrapper.errcheck: retval(instance)=%s, function=%s %s, arguments=%s' % (retval,function,dir(function.__class__),arguments)
+    #    self.instance = retval
+    #    return retval
+    #errcheck = staticmethod(errcheck)



More information about the Pypy-commit mailing list