[Numpy-svn] r3236 - in trunk/numpy/f2py/lib: . src

numpy-svn at scipy.org numpy-svn at scipy.org
Sat Sep 30 17:03:13 EDT 2006


Author: pearu
Date: 2006-09-30 16:02:52 -0500 (Sat, 30 Sep 2006)
New Revision: 3236

Added:
   trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py
   trunk/numpy/f2py/lib/wrapper_base.py
Modified:
   trunk/numpy/f2py/lib/block_statements.py
   trunk/numpy/f2py/lib/python_wrapper.py
   trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
   trunk/numpy/f2py/lib/src/pyobj_to_long.c
   trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
   trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
   trunk/numpy/f2py/lib/typedecl_statements.py
Log:
F2PY G3: wrapping nested derived types.

Modified: trunk/numpy/f2py/lib/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/block_statements.py	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/block_statements.py	2006-09-30 21:02:52 UTC (rev 3236)
@@ -1007,6 +1007,37 @@
         s += tab + 'END TYPE ' + self.name + '\n'
         return s
 
+    # Wrapper methods:
+
+    def get_bit_size(self, _cache={}):
+        try:
+            return _cache[id(self)]
+        except KeyError:
+            s = 0
+            for name,var in self.a.components.items():
+                s += var.get_bit_size()
+            _cache[id(self)] = s
+        return s
+
+    def get_f_type(self):
+        return 'TYPE(%s)' % (self.name)
+
+    def get_c_type(self):
+        return 'f2py_type_%s_%s' % (self.name, self.get_bit_size())
+
+    def get_c_name(self):
+        return 'f2py_type_%s' % (self.name)
+
+    def get_c_struct_name(self):
+        return self.get_c_name() + '_struct'
+
+    def get_c_struct(self):
+        l = []
+        for name, var in self.a.components.items():
+            t = var.get_typedecl()
+            l.append('  %s %s;' % (t.get_c_type(), name))
+        return 'typedef struct {\n%s\n} %s;' % ('\n'.join(l), self.get_c_struct_name())
+
 TypeDecl = Type
 
 # Enum

Added: trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py
===================================================================
--- trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py	2006-09-30 21:02:52 UTC (rev 3236)
@@ -0,0 +1,129 @@
+"""
+Generate
+  int pyobj_to_<ctype>(PyObject* obj, <ctype>* value)
+  PyObject* pyobj_from_<stype>(<ctype>* value)
+functions.
+"""
+__all__ = ['pyobj_to_npy_scalar','pyobj_to_f2py_string','pyobj_from_npy_scalar']
+
+from utils import CHAR_BIT
+
+def pyobj_from_npy_int(ctype):
+    ctype_bits = int(ctype[7:])
+    itemsize = ctype_bits/CHAR_BIT
+    dtype = ctype.upper()
+    return '''\
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) {
+  return PyArray_Return(PyArray_SimpleNewFromData(0, NULL, %(dtype)s, (char*)value));
+}
+''' % (locals())
+
+def pyobj_from_f2py_type(ctype):
+    ctype_bits = int(ctype[10:])
+    raise NotImplementedError,`ctype`
+    return '''\
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) {
+  fprintf(stderr,"In pyobj_from_%(ctype)s (%%p)\\n", value);
+}
+'''
+
+def pyobj_to_npy_int(ctype):
+    ctype_bits = int(ctype[7:])
+    return '''
+/* depends: pyobj_to_long.c, pyobj_to_npy_longlong.c */
+#if NPY_BITSOF_LONG == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_long
+#else
+#if NPY_BITSOF_LONG > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+  long tmp;
+  if (pyobj_to_long(obj,&tmp)) {
+    *value = (%(ctype)s)tmp;
+    return 1;
+  }
+  return 0;
+}
+#else
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+  npy_longlong tmp;
+  if (pyobj_to_npy_longlong(obj,&tmp)) {
+    *value = (%(ctype)s)tmp;
+    return 1;
+  }
+  return 0;
+}
+#endif
+#endif
+''' % (locals())
+
+def pyobj_to_npy_float(ctype):
+    ctype_bits = int(ctype[9:])
+    return '''
+/* depends: pyobj_to_double.c */
+#if NPY_BITSOF_DOUBLE == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_double
+#else
+#if NPY_BITSOF_DOUBLE > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+  double tmp;
+  if (pyobj_to_double(obj,&tmp)) {
+    *value = (%(ctype)s)tmp;
+    return 1;
+  }
+  return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+#endif
+''' % (locals())
+
+def pyobj_to_npy_complex(ctype):
+    ctype_bits = int(ctype[11:])
+    cfloat_bits = ctype_bits/2
+    return '''
+/* depends: pyobj_to_Py_complex.c */
+#if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+  Py_complex c;
+  if (pyobj_to_Py_complex(obj,&c)) {
+    (*value).real = (npy_float%(cfloat_bits)s)c.real;
+    (*value).imag = (npy_float%(cfloat_bits)s)c.imag; 
+    return 1;
+  }
+  return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+''' % (locals())
+
+def pyobj_to_npy_scalar(ctype):
+    if ctype.startswith('npy_int'):
+        return dict(c_code=pyobj_to_npy_int(ctype))
+    elif ctype.startswith('npy_float'):
+        return dict(c_code=pyobj_to_npy_float(ctype))
+    elif ctype.startswith('npy_complex'):
+        return dict(c_code=pyobj_to_npy_complex(ctype))
+    raise NotImplementedError,`ctype`
+
+def pyobj_to_f2py_string(ctype):
+    ctype_bits = int(ctype[11:])
+    ctype_bytes = ctype_bits / CHAR_BIT
+    return dict(
+        c_code = '''
+/* depends: pyobj_to_string_len.c */
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+  return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+}
+''' % (locals()),
+        typedef = ['typedef char * f2py_string;',
+                         'typedef struct { char data[%(ctype_bytes)s]; } %(ctype); ' % (locals())],
+        header = ['#include <string.h>'],
+        )
+
+def pyobj_from_npy_scalar(ctype):
+    if ctype.startswith('npy_int'):
+        return dict(c_code=pyobj_from_npy_int(ctype))
+    raise NotImplementedError,`ctype`
+

Modified: trunk/numpy/f2py/lib/python_wrapper.py
===================================================================
--- trunk/numpy/f2py/lib/python_wrapper.py	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/python_wrapper.py	2006-09-30 21:02:52 UTC (rev 3236)
@@ -9,87 +9,8 @@
 #from typedecl_statements import intrinsic_type_spec, Character
 from utils import CHAR_BIT
 
-class WrapperBase:
+from wrapper_base import *
 
-
-    def __init__(self):
-        self.srcdir = os.path.join(os.path.dirname(__file__),'src')
-        return
-    def warning(self, message):
-        print >> sys.stderr, message
-    def info(self, message):
-        print >> sys.stderr, message
-
-    def get_resource_content(self, name, ext):
-        if name.startswith('pyobj_to_'):
-            body = self.generate_pyobj_to_ctype_c(name[9:])
-            if body is not None: return body
-        generator_mth_name = 'generate_' + name + ext.replace('.','_')
-        generator_mth = getattr(self, generator_mth_name, lambda : None)
-        body = generator_mth()
-        if body is not None:
-            return body
-        fn = os.path.join(self.srcdir,name+ext)
-        if os.path.isfile(fn):
-            f = open(fn,'r')
-            body = f.read()
-            f.close()
-            return body
-        self.warning('No such file: %r' % (fn))
-        return
-
-    def get_dependencies(self, code):
-        l = []
-        for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I):
-            for use in uses.split(','):
-                use = use.strip()
-                if not use: continue
-                l.append(use)
-        return l
-
-    def apply_attributes(self, template):
-        """
-        Apply instance attributes to template string.
-
-        Replace rules for attributes:
-        _list  - will be joined with newline
-        _clist - _list will be joined with comma
-        _elist - _list will be joined
-        ..+.. - attributes will be added
-        [..]  - will be evaluated
-        """
-        replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template))
-        d = {}
-        for name in replace_names:
-            tab = ' ' * (len(name)-len(name.lstrip()))
-            name = name.lstrip()[2:-2]
-            names = name.split('+')
-            joinsymbol = '\n'
-            attrs = None
-            for n in names:
-                realname = n.strip()
-                if n.endswith('_clist'):
-                    joinsymbol = ', '
-                    realname = realname[:-6] + '_list'
-                elif n.endswith('_elist'):
-                    joinsymbol = ''
-                    realname = realname[:-6] + '_list'
-                if hasattr(self, realname):
-                    attr = getattr(self, realname)
-                elif realname.startswith('['):
-                    attr = eval(realname)
-                else:
-                    self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname))
-                    continue
-                if attrs is None:
-                    attrs = attr
-                else:
-                    attrs += attr
-            if isinstance(attrs, list):
-                attrs = joinsymbol.join(attrs)
-            d[name] = str(attrs).replace('\n','\n'+tab)
-        return template % d
-
 class PythonWrapperModule(WrapperBase):
 
     main_template = '''\
@@ -101,21 +22,29 @@
 #define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
 #include "numpy/arrayobject.h"
 
-%(include_list)s
-%(cppmacro_list)s
+%(header_list)s
+
 %(typedef_list)s
+
+%(extern_list)s
+
+%(c_code_list)s
+
+%(capi_code_list)s
+
 %(objdecl_list)s
-%(extern_list)s
-%(c_function_list)s
-%(capi_function_list)s
+
 static PyObject *f2py_module;
+
 static PyMethodDef f2py_module_methods[] = {
   %(module_method_list)s
   {NULL,NULL,0,NULL}
 };
+
 PyMODINIT_FUNC init%(modulename)s(void) {
   f2py_module = Py_InitModule("%(modulename)s", f2py_module_methods);
-  %(initialize_interface_list)s
+  import_array();
+  %(module_init_list)s
   if (PyErr_Occurred()) {
     PyErr_SetString(PyExc_ImportError, "can\'t initialize module %(modulename)s");
     return;
@@ -133,31 +62,49 @@
     def __init__(self, modulename):
         WrapperBase.__init__(self)
         self.modulename = modulename
-        self.include_list = []
+        #self.include_list = []
+        #self.cppmacro_list = []
+        
+        self.header_list = []
         self.typedef_list = []
-        self.cppmacro_list = []
+        self.extern_list = []
         self.objdecl_list = []
-        self.c_function_list = []
-        self.extern_list = []
-        self.capi_function_list = []
+        self.c_code_list = []
+        self.capi_code_list = []
+
         self.module_method_list = []
-        self.initialize_interface_list = []
+        self.module_init_list = []
+
         self.fortran_code_list = []
 
-        self.defined_types = []
-        self.defined_macros = []
-        self.defined_c_functions = []
-        self.defined_typedefs = []
+        #self.defined_types = []
+        #self.defined_macros = []
+        #self.defined_c_functions = []
+        #self.defined_typedefs = []
+
+        self.list_names = ['header', 'typedef', 'extern', 'objdecl',
+                           'c_code','capi_code','module_method','module_init',
+                           'fortran_code']
+
         return
 
     def add(self, block):
         if isinstance(block, BeginSource):
-            for name, subblock in block.a.external_subprogram.items():
-                self.add(subblock)
+            for name, moduleblock in block.a.module.items():
+                self.add(moduleblock)
+            #for name, subblock in block.a.external_subprogram.items():
+            #    self.add(subblock)
         elif isinstance(block, (Subroutine, Function)):
             self.info('Generating interface for %s' % (block.name))
             f = PythonCAPIFunction(self, block)
-            f.fill()            
+            f.fill()
+        elif isinstance(block, Module):
+            for name,declblock in block.a.type_decls.items():
+                self.add(declblock)
+        elif isinstance(block, TypeDecl):
+            PythonCAPIDerivedType(self, block)
+        elif isinstance(block, tuple(declaration_type_spec)):
+            PythonCAPIIntrinsicType(self, block)
         else:
             raise NotImplementedError,`block.__class__.__name__`
         return
@@ -167,155 +114,306 @@
     def fortran_code(self):
         return self.apply_attributes(self.main_fortran_template)
 
-    def add_c_function(self, name):
-        if name not in self.defined_c_functions:
-            body = self.get_resource_content(name,'.c')
-            if body is None:
-                self.warning('Failed to get C function %r content.' % (name))
-                return
-            for d in self.get_dependencies(body):
-                if d.endswith('.cpp'):
-                    self.add_cppmacro(d[:-4])
-                elif d.endswith('.c'):
-                    self.add_c_function(d[:-2])
-                else:
-                    self.warning('Unknown dependence: %r.' % (d))
-            self.defined_c_functions.append(name)
-            self.c_function_list.append(body)
+    def add_subroutine(self, block):
+        raise
+        f = PythonCAPIFunction(self, block)
+        f.fill()
         return
 
-    def add_cppmacro(self, name):
-        if name not in self.defined_macros:
-            body = self.get_resource_content(name,'.cpp')
-            if body is None:
-                self.warning('Failed to get CPP macro %r content.' % (name))
-                return
-            for d in self.get_dependencies(body):
-                if d.endswith('.cpp'):
-                    self.add_cppmacro(d[:-4])
-                elif d.endswith('.c'):
-                    self.add_c_function(d[:-2])
-                else:
-                    self.warning('Unknown dependence: %r.' % (d))
-            self.defined_macros.append(name)
-            self.cppmacro_list.append(body)
-        return
 
-    def add_type(self, typedecl):
-        typewrap = TypeDecl(self, typedecl)
-        typename = typewrap.typename
-        if typename not in self.defined_types:
-            self.defined_types.append(typename)
-            typewrap.fill()
-        return typename
 
-    def add_typedef(self, name, code):
-        if name not in self.defined_typedefs:
-            self.typedef_list.append(code)
-            self.defined_types.append(name)
-        return
+        
+class PythonCAPIIntrinsicType(WrapperBase):
+    """
+    Fortran intrinsic type hooks.
+    """
+    _defined_types = []
+    def __init__(self, parent, typedecl):
+        WrapperBase.__init__(self)
+        self.name = name = typedecl.name
+        if name in self._defined_types:
+            return
+        self._defined_types.append(name)
 
-    def add_include(self, include):
-        if include not in self.include_list:
-            self.include_list.append(include)
-        return
+        self.ctype = ctype = typedecl.get_c_type()
 
-    def add_subroutine(self, block):
-        f = PythonCAPIFunction(self, block)
-        f.fill()
+        if ctype.startswith('npy_'):
+            from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar
+            d = pyobj_to_npy_scalar(ctype)
+            for v in d.values():
+                self.resolve_dependencies(parent, v)
+            for k,v in d.items():
+                l = getattr(parent, k+'_list')
+                l.append(v)
+            return
+        
+        if not ctype.startswith('f2py_type_'):
+            raise NotImplementedError,`name,ctype`
+
+        for n in parent.list_names:
+            l = getattr(parent,n + '_list')
+            l.append(self.apply_attributes(getattr(self, n+'_template','')))
+
         return
 
-    def generate_pyobj_to_ctype_c(self, ctype):
-        if ctype.startswith('npy_int'):
-            ctype_bits = int(ctype[7:])
-            return '''
-/* depends: pyobj_to_long.c, pyobj_to_npy_longlong.c */
-#if NPY_BITSOF_LONG == %(ctype_bits)s
-#define pyobj_to_%(ctype)s pyobj_to_long
-#else
-#if NPY_BITSOF_LONG > %(ctype_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  long tmp;
-  if (pyobj_to_long(obj,&tmp)) {
-    *value = (%(ctype)s)tmp;
-    return 1;
-  }
-  return 0;
+class PythonCAPIDerivedType(WrapperBase):
+    """
+    Fortran 90 derived type hooks.
+    """
+
+    header_template = '''\
+#define %(oname)sObject_Check(obj) \\
+    PyObject_TypeCheck((PyObject*)obj, &%(oname)sType)
+#define %(init_func)s_f \\
+    F_FUNC(%(init_func)s,%(INIT_FUNC)s)
+'''
+
+    typedef_template = '''\
+typedef void * %(ctype)s;
+typedef struct {
+  PyObject_HEAD
+  %(ptrstruct_list)s
+  %(ctype)s data;
+} %(oname)sObject;
+'''
+
+    extern_template = '''\
+static PyTypeObject %(oname)sType;
+'''
+
+    objdecl_template = '''\
+static PyMethodDef %(oname)s_methods[] = {
+    %(type_method_list)s
+    {NULL}  /* Sentinel */
+};
+
+static PyGetSetDef %(oname)s_getseters[] = {
+    %(type_getseters_list)s
+    {NULL}  /* Sentinel */
+};
+
+static PyTypeObject %(oname)sType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "%(name)s",                /*tp_name*/
+    sizeof(%(oname)sObject),    /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)%(oname)s_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    %(oname)s_repr,            /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /*tp_flags*/
+    "Fortran derived type %(name)s objects",        /* tp_doc */
+    0,		               /* tp_traverse */
+    0,		               /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    %(oname)s_methods,          /* tp_methods */
+    0 /*%(oname)s_members*/,    /* tp_members */
+    %(oname)s_getseters,       /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)%(oname)s_init,      /* tp_init */
+    0,                         /* tp_alloc */
+    %(oname)s_new,                 /* tp_new */
+};
+'''
+
+    module_init_template = '''\
+if (PyType_Ready(&%(oname)sType) < 0)
+  return;
+PyModule_AddObject(f2py_module, "%(name)s",
+                                (PyObject *)&%(oname)sType);
+'''
+
+    c_code_template = '''\
+static void %(init_func)s_c(
+               %(init_func_c_arg_clist)s) {
+  %(init_func_c_body_list)s
 }
-#else
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  npy_longlong tmp;
-  if (pyobj_to_npy_longlong(obj,&tmp)) {
-    *value = (%(ctype)s)tmp;
-    return 1;
-  }
-  return 0;
+'''
+
+    capi_code_template = '''\
+static void %(oname)s_dealloc(%(oname)sObject* self) {
+  PyMem_Free(self->data);
+  self->ob_type->tp_free((PyObject*)self);
 }
-#endif
-#endif
-''' % (locals())
-        elif ctype.startswith('npy_float'):
-            ctype_bits = int(ctype[9:])
-            return '''
-/* depends: pyobj_to_double.c */
-#if NPY_BITSOF_DOUBLE == %(ctype_bits)s
-#define pyobj_to_%(ctype)s pyobj_to_double
-#else
-#if NPY_BITSOF_DOUBLE > %(ctype_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  double tmp;
-  if (pyobj_to_double(obj,&tmp)) {
-    *value = (%(ctype)s)tmp;
+
+static int pyobj_to_%(ctype)s(PyObject *obj,
+                              %(ctype)s* value_ptr) {
+  if (%(oname)sObject_Check(obj)) {
+    if (!memcpy(value_ptr,((%(oname)sObject *)obj)->data, %(byte_size)s)) {
+      PyErr_SetString(PyExc_MemoryError,
+         "failed to copy %(name)s instance memory to %(ctype)s object.");
+    }
     return 1;
   }
   return 0;
 }
-#else
-#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
-#endif
-#endif
-''' % (locals())
-        elif ctype.startswith('npy_complex'):
-            ctype_bits = int(ctype[11:])
-            cfloat_bits = ctype_bits/2
-            return '''
-/* depends: pyobj_to_Py_complex.c */
-#if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  Py_complex c;
-  if (pyobj_to_Py_complex(obj,&c)) {
-    (*value).real = (npy_float%(cfloat_bits)s)c.real;
-    (*value).imag = (npy_float%(cfloat_bits)s)c.imag; 
-    return 1;
+
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value_ptr) {
+  %(oname)sObject* obj = (%(oname)sObject*)(%(oname)sType.tp_alloc(&%(oname)sType, 0));
+  if (obj == NULL)
+    return NULL;
+  obj->data = PyMem_Malloc(%(byte_size)s);
+  if (obj->data == NULL) {
+    Py_DECREF(obj);
+    return PyErr_NoMemory();
   }
-  return 0;
+  if (value_ptr) {
+    if (!memcpy(obj->data, value_ptr, %(byte_size)s)) {
+      PyErr_SetString(PyExc_MemoryError,
+         "failed to copy %(ctype)s object memory to %(name)s instance.");
+    }
+  }
+  %(init_func)s_f(%(init_func)s_c, obj, obj->data);
+  return (PyObject*)obj;
 }
-#else
-#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
-#endif
-''' % (locals())
-        elif ctype.startswith('f2py_string'):
-            ctype_bits = int(ctype[11:])
-            ctype_bytes = ctype_bits / CHAR_BIT
-            self.add_typedef('f2py_string','typedef char * f2py_string;')
-            self.add_typedef(ctype,'typedef struct { char data[%s]; } %s;' % (ctype_bytes,ctype))
-            self.add_include('#include <string.h>')
-            return '''
-/* depends: pyobj_to_string_len.c */
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+
+static PyObject * %(oname)s_new(PyTypeObject *type,
+                                PyObject *args, PyObject *kwds)
+{
+  return pyobj_from_%(ctype)s(NULL);
 }
-''' % (locals())
-        elif ctype.startswith('f2py_type_'):
-            ctype_bits = int(ctype.split('_')[-1])
-            ctype_bytes = ctype_bits / CHAR_BIT
-            self.add_typedef(ctype,'typedef struct { char data[%s]; } %s;' % (ctype_bytes,ctype))
-            return '''
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
-  return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+
+static int %(oname)s_init(%(oname)sObject *self,
+                          PyObject *capi_args, PyObject *capi_kwds)
+{
+   return !PyArg_ParseTuple(capi_args,"%(attr_format_elist)s"
+                                      %(attr_init_clist)s);
 }
-''' % (locals())
-        
+
+static PyObject * %(oname)s_as_tuple(%(oname)sObject * self) {
+  return Py_BuildValue("%(as_tuple_format_elist)s"
+                        %(as_tuple_arg_clist)s);
+}
+
+static PyObject * %(oname)s_repr(PyObject * self) {
+  PyObject* r = PyString_FromString("%(name)s(");
+  PyString_ConcatAndDel(&r, PyObject_Repr(%(oname)s_as_tuple((%(oname)sObject*)self)));
+  PyString_ConcatAndDel(&r, PyString_FromString(")"));
+  return r;
+}
+
+%(getset_func_list)s
+'''
+
+    fortran_code_template = '''\
+      subroutine %(init_func)s(init_func_c, self, obj)
+      %(use_stmt_list)s
+      external init_func_c
+!     self is %(oname)sObject
+      external self
+      %(ftype)s obj
+      call init_func_c(%(init_func_f_arg_clist)s)
+      end
+'''
+
+    #module_method_template = ''''''
+
+    _defined_types = []
+    def __init__(self, parent, typedecl):
+        WrapperBase.__init__(self)
+        name = typedecl.name
+        if name in self._defined_types:
+            return
+        self._defined_types.append(name)
+
+        self.name = name
+        self.oname = oname = 'f2py_' + name
+        self.ctype = typedecl.get_c_type()
+        self.ctype_ptrs = self.ctype + '_ptrs'
+        self.ftype = typedecl.get_f_type()
+        self.byte_size = byte_size = typedecl.get_bit_size() / CHAR_BIT
+        WrapperCPPMacro(parent, 'F_FUNC')
+
+        self.init_func_f_arg_list = ['self']
+        self.init_func_c_arg_list = ['%sObject *self' % (self.oname)]
+        self.init_func_c_body_list = []
+        self.ptrstruct_list = []
+        self.attr_decl_list = []
+        self.attr_format_list = []
+        self.attr_init_list = []
+        self.as_tuple_format_list = []
+        self.as_tuple_arg_list = []
+        self.getset_func_list = []
+        self.type_getseters_list = []
+        for n in typedecl.a.component_names:
+            v = typedecl.a.components[n]
+            t = v.get_typedecl()
+            ct = t.get_c_type()
+            on = 'f2py_' + t.name
+            parent.add(t)
+            self.ptrstruct_list.append('%s* %s_ptr;' % (ct, n))
+            self.init_func_f_arg_list.append('obj %% %s' % (n))
+            self.init_func_c_arg_list.append('\n%s * %s_ptr' % (ct, n))
+            self.init_func_c_body_list.append('''\
+if (!((void*)%(n)s_ptr >= self->data
+      && (void*)%(n)s_ptr < self->data + %(byte_size)s ))
+  fprintf(stderr,"INCONSISTENCY IN %(name)s WRAPPER: "
+                 "self->data=%%p <= %(n)s_ptr=%%p < self->data+%(byte_size)s=%%p\\n",
+                 self->data, %(n)s_ptr, self->data + %(byte_size)s);
+self->%(n)s_ptr = %(n)s_ptr;
+''' % (locals()))
+            self.attr_format_list.append('O&')
+            WrapperCCode(parent, 'pyobj_to_%s' % (ct))
+            self.attr_init_list.append('\npyobj_to_%s, self->%s_ptr' % (ct,n))
+            WrapperCCode(parent, 'pyobj_from_%s' % (ct))
+            self.as_tuple_format_list.append('O&')
+            self.as_tuple_arg_list.append('\npyobj_from_%s, self->%s_ptr' % (ct, n))
+            self.getset_func_list.append('''\
+static PyObject * %(oname)s_get_%(n)s(%(oname)sObject *self,
+                                      void *closure) {
+  return pyobj_from_%(ct)s(self->%(n)s_ptr);
+}
+static int %(oname)s_set_%(n)s(%(oname)sObject *self,
+                               PyObject *value, void *closure)
+{
+  if (value == NULL) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Cannot delete %(name)s attribute %(n)s");
+    return -1;
+  }
+  if (pyobj_to_%(ct)s(value, self->%(n)s_ptr))
+    return 0;
+  return -1;
+}
+''' % (locals()))
+            self.type_getseters_list.append('{"%(n)s",(getter)%(oname)s_get_%(n)s, (setter)%(oname)s_set_%(n)s,\n "component %(n)s",NULL},' % (locals()))
+        if self.attr_init_list: self.attr_init_list.insert(0,'')
+        if self.as_tuple_arg_list: self.as_tuple_arg_list.insert(0,'')
+        self.init_func = self.ctype + '_init'
+        self.INIT_FUNC = self.init_func.upper()
+
+        self.type_method_list = []
+        self.type_method_list.append('{"as_tuple",(PyCFunction)%(oname)s_as_tuple,METH_NOARGS,\n "Return %(name)s components as tuple."},' % (self.__dict__))
+        self.cname = typedecl.get_c_name()
+
+        self.use_stmt_list = []
+        if isinstance(typedecl.parent, Module):
+            self.use_stmt_list.append('use %s' % (typedecl.parent.name))
+
+        for n in parent.list_names:
+            l = getattr(parent,n + '_list')
+            l.append(self.apply_attributes(getattr(self, n+'_template','')))
+        return
+
 class PythonCAPIFunction(WrapperBase):
     capi_function_template = '''
 static char f2py_doc_%(function_name)s[] = "%(function_doc)s";
@@ -412,15 +510,15 @@
         self.parent.pyarg_format_list.append('O&')
         self.parent.keyword_list.append('"%s"' % (self.name))
 
-        self.grand_parent.add_c_function('pyobj_to_%s' % (self.ctype))
         return
 
-class TypeDecl(WrapperBase):
+
+class TypeDecl2(WrapperBase):
     cppmacro_template = '''\
 #define initialize_%(typename)s_interface F_FUNC(initialize_%(typename)s_interface_f,INITIALIZE_%(TYPENAME)s_INTERFACE_F)\
 '''
     typedef_template = '''\
-typedef struct { char data[%(byte_size)s] } %(ctype)s;
+typedef struct { char data[%(byte_size)s]; } %(ctype)s;
 typedef %(ctype)s (*create_%(typename)s_functype)(void);
 typedef void (*initialize_%(typename)s_interface_functype)(create_%(typename)s_functype);\
 '''
@@ -449,6 +547,14 @@
          call init_c(create_%(typename)s_object_f)
        end
 '''
+    pyobj_to_type_template = '''
+    static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+      if (PyTuple_Check(obj)) {
+        return 0;
+      }
+    return 0;
+    }
+'''
 
     def __init__(self, parent, typedecl):
         WrapperBase.__init__(self)
@@ -464,12 +570,17 @@
 
     def fill(self):
         ctype =self.typedecl.get_c_type()
-        if ctype.startswith('npy_'):
-            pass
-        elif ctype.startswith('f2py_string'):
-            pass
-        elif ctype.startswith('f2py_type'):
-            pass
+        if ctype.startswith('npy_') or ctype.startswith('f2py_string'):
+            # wrappers are defined via pyobj_to_* functions
+            self.parent.add_c_function('pyobj_to_%s' % (self.ctype))
+            return
+        if ctype.startswith('f2py_type'):
+            return
+            self.parent.add_typedef(ctype,
+                                    self.apply_attributes('typedef struct { char data[%(byte_size)s]; } %(ctype)s;'))
+            self.parent.add_c_function(self.apply_attributes('pyobj_to_%(ctype)s'),
+                                       self.apply_attributes(self.pyobj_to_type_template)
+                                       )
         else:
             self.parent.typedef_list.append(self.apply_attributes(self.typedef_template))
             self.parent.objdecl_list.append(self.apply_attributes(self.objdecl_template))
@@ -490,9 +601,13 @@
     stmt = str2stmt("""
     module rat
       integer :: i
+      type info
+        integer flag
+      end type info
       type rational
         integer n
-        integer*8 d
+        integer d
+        type(info) i
       end type rational
     end module rat
     subroutine foo(a)
@@ -508,16 +623,20 @@
 
     foo_code = """! -*- f90 -*-
       module rat
+        type info
+          integer flag
+        end type info
         type rational
-          integer d,n
+          integer n,d
+          type(info) i
         end type rational
       end module rat
-      subroutine foo(a,b,c)
+      subroutine foo(a,b)
         use rat
         integer a
-        character*5 b
-        type(rational) c
-        print*,'a=',a,b,c
+        !character*5 b
+        type(rational) b
+        print*,'a=',a,b
       end
 """
 
@@ -556,8 +675,31 @@
     setup(configuration=configuration)
 ''')
     f.close()
-    print get_char_bit()
+    #print get_char_bit()
     os.system('python foo_setup.py config_fc --fcompiler=gnu95 build build_ext --inplace')
     import foo
-    print dir(foo)
-    foo.foo(2,"abcdefg")
+    #print foo.__doc__
+    #print dir(foo)
+    #print foo.info.__doc__
+    #print foo.rational.__doc__
+    #print dir(foo.rational)
+    i = foo.info(7)
+    #print i #,i.as_tuple()
+    #print 'i.flag=',i.flag
+    r = foo.rational(2,3,i)
+    print r
+    j = r.i
+    print 'r.i.flag=',(r.i).flag
+    print 'j.flag=',j.flag
+    #print 'r=',r
+    sys.exit()
+    n,d,ii = r.as_tuple()
+    n += 1
+    print n,d
+    print r
+    #foo.foo(2,r)
+    print r.n, r.d
+    r.n = 5
+    print r
+    r.n -= 1
+    print r

Modified: trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c	2006-09-30 21:02:52 UTC (rev 3236)
@@ -33,7 +33,8 @@
     }
   }
   if (!PyErr_Occurred()) {
-    PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C Py_complex.");
+    PyErr_SetString(PyExc_TypeError,
+		    "Failed to convert python object to C Py_complex.");
   }
   return 0;
 }

Modified: trunk/numpy/f2py/lib/src/pyobj_to_long.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_long.c	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_long.c	2006-09-30 21:02:52 UTC (rev 3236)
@@ -25,7 +25,8 @@
     Py_DECREF(tmp);
   }
   if (!PyErr_Occurred()) {
-    PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C long.");
+    PyErr_SetString(PyExc_TypeError,
+                    "Failed to convert python object to C long.");
   }
   return 0;
 }

Modified: trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c	2006-09-30 21:02:52 UTC (rev 3236)
@@ -29,7 +29,8 @@
     Py_DECREF(tmp);
   }
   if (!PyErr_Occurred()) {
-    PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C npy_longlong.");
+    PyErr_SetString(PyExc_TypeError,
+		    "Failed to convert python object to C npy_longlong.");
   }
   return 0;
 }

Modified: trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_string_len.c	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_string_len.c	2006-09-30 21:02:52 UTC (rev 3236)
@@ -4,7 +4,8 @@
       return 1;
   }
   if (!PyErr_Occurred()) {
-    PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C f2py_string.");
+    PyErr_SetString(PyExc_TypeError,
+		    "Failed to convert python object to C f2py_string.");
   }
   return 0;
 }

Modified: trunk/numpy/f2py/lib/typedecl_statements.py
===================================================================
--- trunk/numpy/f2py/lib/typedecl_statements.py	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/typedecl_statements.py	2006-09-30 21:02:52 UTC (rev 3236)
@@ -470,14 +470,10 @@
         raise NotImplementedError,`self.__class__.__name__`
 
     def get_bit_size(self):
-        type_decl = self.get_type_decl(self.name)
-        s = 0
-        for name,var in type_decl.a.components.items():
-            s += var.get_bit_size()
-        return s
+        return self.get_type_decl(self.name).get_bit_size()
 
     def get_c_type(self):
-        return 'f2py_type_%s_%s' % (self.name, self.get_bit_size())
+        return self.get_type_decl(self.name).get_c_type()
     
 TypeStmt = Type
 

Added: trunk/numpy/f2py/lib/wrapper_base.py
===================================================================
--- trunk/numpy/f2py/lib/wrapper_base.py	2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/wrapper_base.py	2006-09-30 21:02:52 UTC (rev 3236)
@@ -0,0 +1,162 @@
+
+import os
+import sys
+import re
+__all__ = ['WrapperBase','WrapperCPPMacro','WrapperCCode']
+
+class WrapperBase:
+
+    def __init__(self):
+        self.srcdir = os.path.join(os.path.dirname(__file__),'src')
+        return
+    def warning(self, message):
+        print >> sys.stderr, message
+    def info(self, message):
+        print >> sys.stderr, message
+
+    def get_resource_content(self, name, ext):
+        if name.startswith('pyobj_to_'):
+            try:
+                return self.generate_pyobj_to_ctype_c(name[9:])
+            except NotImplementedError:
+                pass
+        elif name.startswith('pyobj_from_'):
+            try:
+                return self.generate_pyobj_from_ctype_c(name[11:])
+            except NotImplementedError:
+                pass
+        generator_mth_name = 'generate_' + name + ext.replace('.','_')
+        generator_mth = getattr(self, generator_mth_name, lambda : None)
+        body = generator_mth()
+        if body is not None:
+            return body
+        fn = os.path.join(self.srcdir,name+ext)
+        if os.path.isfile(fn):
+            f = open(fn,'r')
+            body = f.read()
+            f.close()
+            return body
+        self.warning('No such file: %r' % (fn))
+        return
+
+    def get_dependencies(self, code):
+        l = []
+        for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I):
+            for use in uses.split(','):
+                use = use.strip()
+                if not use: continue
+                l.append(use)
+        return l
+
+    def resolve_dependencies(self, parent, body):
+        assert isinstance(body, str),type(body)
+        for d in self.get_dependencies(body):
+            if d.endswith('.cpp'):
+                WrapperCPPMacro(parent, d[:-4])
+            elif d.endswith('.c'):
+                WrapperCCode(parent, d[:-2])
+            else:
+                self.warning('Unknown dependence: %r.' % (d))        
+        return
+
+    def apply_attributes(self, template):
+        """
+        Apply instance attributes to template string.
+
+        Replace rules for attributes:
+        _list  - will be joined with newline
+        _clist - _list will be joined with comma
+        _elist - _list will be joined
+        ..+.. - attributes will be added
+        [..]  - will be evaluated
+        """
+        replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template))
+        d = {}
+        for name in replace_names:
+            tab = ' ' * (len(name)-len(name.lstrip()))
+            name = name.lstrip()[2:-2]
+            names = name.split('+')
+            joinsymbol = '\n'
+            attrs = None
+            for n in names:
+                realname = n.strip()
+                if n.endswith('_clist'):
+                    joinsymbol = ', '
+                    realname = realname[:-6] + '_list'
+                elif n.endswith('_elist'):
+                    joinsymbol = ''
+                    realname = realname[:-6] + '_list'
+                if hasattr(self, realname):
+                    attr = getattr(self, realname)
+                elif realname.startswith('['):
+                    attr = eval(realname)
+                else:
+                    self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname))
+                    continue
+                if attrs is None:
+                    attrs = attr
+                else:
+                    attrs += attr
+            if isinstance(attrs, list):
+                attrs = joinsymbol.join(attrs)
+            d[name] = str(attrs).replace('\n','\n'+tab)
+        return template % d
+
+class WrapperCPPMacro(WrapperBase):
+    """
+    CPP macros
+    """
+    _defined_macros = []
+    def __init__(self, parent, name):
+        WrapperBase.__init__(self)
+        if name in self._defined_macros:
+            return
+        self._defined_macros.append(name)
+
+        body = self.get_resource_content(name,'.cpp')
+        if body is None:
+            self.warning('Failed to get CPP macro %r content.' % (name))
+            return
+        self.resolve_dependencies(parent, body)
+        parent.header_list.append(body)
+        return
+
+class WrapperCCode(WrapperBase):
+    """
+    C code
+    """
+    _defined_codes = []
+    def __init__(self, parent, name):
+        WrapperBase.__init__(self)
+        if name in self._defined_codes:
+            return
+        self._defined_codes.append(name)
+
+        body = self.get_resource_content(name,'.c')
+        if body is None:
+            self.warning('Failed to get C code %r content.' % (name))
+            return
+        if isinstance(body, dict):
+            for k,v in body.items():
+                self.resolve_dependencies(parent, v)
+            for k,v in body.items():
+                l = getattr(parent,k+'_list')
+                l.append(v)
+        else:
+            self.resolve_dependencies(parent, body)
+            parent.c_code_list.append(body)
+        return
+
+    def generate_pyobj_to_ctype_c(self, ctype):
+        from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar, pyobj_to_f2py_string
+        if ctype.startswith('npy_'):
+            return pyobj_to_npy_scalar(ctype)
+        elif ctype.startswith('f2py_string'):
+            return pyobj_to_f2py_string(ctype)
+        raise NotImplementedError,`ctype`
+
+    def generate_pyobj_from_ctype_c(self, ctype):
+        from generate_pyobj_tofrom_funcs import pyobj_from_npy_scalar
+        if ctype.startswith('npy_'):
+            return pyobj_from_npy_scalar(ctype)
+        raise NotImplementedError,`ctype`




More information about the Numpy-svn mailing list