[Numpy-svn] r3250 - in trunk/numpy/f2py/lib: . parser

numpy-svn at scipy.org numpy-svn at scipy.org
Wed Oct 4 05:50:04 EDT 2006


Author: pearu
Date: 2006-10-04 04:49:54 -0500 (Wed, 04 Oct 2006)
New Revision: 3250

Added:
   trunk/numpy/f2py/lib/py_wrap.py
Modified:
   trunk/numpy/f2py/lib/main.py
   trunk/numpy/f2py/lib/parser/api.py
   trunk/numpy/f2py/lib/parser/base_classes.py
   trunk/numpy/f2py/lib/parser/block_statements.py
   trunk/numpy/f2py/lib/parser/parsefortran.py
   trunk/numpy/f2py/lib/parser/statements.py
   trunk/numpy/f2py/lib/python_wrapper.py
Log:
F2PY G3: exposed wrappers via f2py script. A working example: wrap F90 module containing derived type with scalar components.

Modified: trunk/numpy/f2py/lib/main.py
===================================================================
--- trunk/numpy/f2py/lib/main.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/main.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -12,7 +12,9 @@
 """
 
 import os
+import re
 import sys
+import tempfile
 
 try:
     from numpy import __version__ as numpy_version
@@ -44,53 +46,92 @@
 
 """
 
-from parser.api import parse, PythonModule, EndStatement
+import re
+import shutil
+from parser.api import parse, PythonModule, EndStatement, Module, Subroutine, Function
 
-def dump_signature():
-    """ Read Fortran files and dump the signatures to file or stdout.
+def get_values(sys_argv, prefix='', suffix='', strip_prefix=False, strip_suffix=False):
     """
-    # get signature output
-    i = sys.argv.index('-h')
-    if len(sys.argv)-1==i:
-        signature_output = 'stdout'
-    else:
-        signature_output = sys.argv[i+1]
-        del sys.argv[i+1]
-    del sys.argv[i]
+    Return a list of values with pattern
+      <prefix><value><suffix>.
+    The corresponding items will be removed from sys_argv.
+    """
+    match = re.compile(prefix + r'.*' + suffix + '\Z').match
+    ret = [item for item in sys_argv if match(item)]
+    [sys_argv.remove(item) for item in ret]
+    if strip_prefix and prefix:
+        i = len(prefix)
+        ret = [item[i:] for item in ret]
+    if strip_suffix and suffix:
+        i = len(suffix)
+        ret = [item[:-i] for item in ret]
+    return ret
 
-    # get module name
+def get_option(sys_argv, option, default_return = None):
+    """
+    Return True if sys_argv has <option>.
+    If <option> is not in sys_argv, return default_return.
+    <option> (when present) will be removed from sys_argv.
+    """
     try:
-        i = sys.argv.index('-m')
+        i = sys_argv.index(option)
     except ValueError:
-        i = None
-        module_name = 'unknown'
-    if i is not None:
-        if len(sys.argv)-1==i:
-            module_name = 'unspecified'
-        else:
-            module_name = sys.argv[i+1]
-            del sys.argv[i+1]
-        del sys.argv[i]
+        return default_return
+    del sys_argv[i]
+    return True
 
+def get_option_value(sys_argv, option, default_value = None, default_return = None):
+    """
+    Return <value> from
+      sys_argv = [...,<option>,<value>,...]
+    list.
+    If <option> is the last element, return default_value.
+    If <option> is not in sys_argv, return default_return.
+    Both <option> and <value> (when present) will be removed from sys_argv.
+    """
+    try:
+        i = sys_argv.index(option)
+    except ValueError:
+        return default_return
+    if len(sys_argv)-1==i:
+        del sys_argv[i]
+        return default_value
+    value = sys_argv[i+1]
+    del sys_argv[i+1]
+    del sys_argv[i]
+    return value
+
+def get_signature_output(sys_argv):
+    return get_option_value(sys_argv,'-h','stdout')
+
+def dump_signature(sys_argv):
+    """ Read Fortran files and dump the signatures to file or stdout.
+    XXX: Not well tested.
+    """
+    signature_output = get_signature_output(sys_argv)
+
     # initialize output stream
     if signature_output in ['stdout','stderr']:
         output_stream = getattr(sys, signature_output)
+        modulename = get_option_value(sys_argv,'-m','untitled','unknown')
     else:
+        name,ext = os.path.splitext(signature_output)
+        if ext != '.pyf':
+            signature_output += '.pyf'
         if os.path.isfile(signature_output):
-            try:
-                i = sys.argv.index('--overwrite-signature')
-                del sys.argv[i]
-            except ValueError:
+            overwrite = get_option(sys_argv, '--overwrite-signature', False)
+            if not overwrite:
                 print >> sys.stderr, 'Signature file %r exists. Use --overwrite-signature to overwrite.' % (signature_output)
                 sys.exit()
+        modulename = get_option_value(sys_argv,'-m',os.path.basename(name),os.path.basename(name))
         output_stream = open(signature_output,'w')
 
     flag = 'file'
-    file_names = []
+    file_names = [] 
     only_names = []
     skip_names = []
     options = []
-    for word in sys.argv[1:]:
+    for word in sys_argv[1:]:
         if word=='': pass
         elif word=='only:': flag = 'only'
         elif word=='skip:': flag = 'skip'
@@ -99,15 +140,22 @@
         else:
             {'file': file_names,'only': only_names, 'skip': skip_names}[flag].append(word)
 
+    if options:
+        sys.stderr.write('Unused options: %s\n' % (', '.join(options)))
+
     output_stream.write('''!    -*- f90 -*-
 ! Note: the context of this file is case sensitive.
 ''')
     output_stream.write('PYTHON MODULE %s\n' % (module_name))
     output_stream.write('  INTERFACE\n\n')
     for filename in file_names:
+        if not os.path.isfile(filename):
+            sys.stderr.write('No or not a file %r. Skipping.\n' % (filename))
+            continue
+        sys.stderr.write('Parsing %r..\n' % (filename))
         block = parse(filename)
-        output_stream.write('! File: %s, source mode = %s\n' % (filename, block.reader.mode))
-        if isinstance(block.content[0],PythonModule):
+        output_stream.write('! File: %s, source mode = %r\n' % (filename, block.reader.mode))
+        if block.content and isinstance(block.content[0],PythonModule):
             for subblock in block.content[0].content[0].content:
                 if isinstance(subblock, EndStatement):
                     break
@@ -121,23 +169,165 @@
         output_stream.close()
     return
 
-def build_extension():
-    raise NotImplementedError,'build_extension'
+def build_extension(sys_argv):
+    """
+    Build wrappers to Fortran 90 modules and external subprograms.
+    """
+    modulename = get_option_value(sys_argv,'-m','untitled','unknown')
 
-def main():
+    build_dir = get_option_value('--build-dir','.',None)
+    if build_dir is None:
+        build_dir = tempfile.mktemp()
+        clean_build_dir = True
+    else:
+        clean_build_dir = False
+    if not os.path.exists(build_dir): os.makedirs(build_dir)
+
+    include_dirs = get_values(sys_argv,'-I',strip_prefix=True)
+    library_dirs = get_values(sys_argv,'-L',strip_prefix=True)
+    libraries = get_values(sys_argv,'-l',strip_prefix=True)
+    _define_macros = get_values(sys_argv,'-D',strip_prefix=True)
+    undef_macros = get_values(sys_argv,'-U',strip_prefix=True)
+    extra_objects = get_values(sys_argv,'','[.](o|a|so|dll|dynlib|sl)')
+
+    define_macros = []
+    for item in _define_macros:
+        name_value = item.split('=',1)
+        if len(name_value)==1:
+            name_value.append(None)
+        if len(name_value)==2:
+            define_macros.append(tuple(name_value))
+        else:
+            print 'Invalid use of -D:',name_value
+
+    pyf_files = get_values(sys_argv,'','[.]pyf')
+    fortran_files = get_values(sys_argv,'','[.](f|f90|F90|F)')
+    c_files = get_values(sys_argv,'','[.](c|cpp|C|CPP|c[+][+])')
+
+    fc_flags = get_values(sys_argv,'--fcompiler=')
+
+    options = get_values(sys_argv,'-')
+    if options:
+        sys.stderr.write('Unused options: %s\n' % (', '.join(options)))
+
+    if pyf_files:
+        parse_files = pyf_files
+    else:
+        parse_files = fortran_files + c_files
+
+    f90_modules = []
+    external_subprograms = []
+
+    for filename in parse_files:
+        if not os.path.isfile(filename):
+            sys.stderr.write('No or not a file %r. Skipping.\n' % (filename))
+            continue
+        sys.stderr.write('Parsing %r..\n' % (filename))
+        for block in parse(filename, include_dirs=include_dirs).content:
+            if isinstance(block, Module):
+                f90_modules.append(block)
+            elif isinstance(block, (Subroutine, Function)):
+                external_subprograms.append(block)
+            else:
+                sys.stderr.write("Unhandled structure: %r\n" % (block.__class__))
+
+    from py_wrap import PythonWrapperModule
+    def configuration(parent_package='', top_path=None):
+        from numpy.distutils.misc_util import Configuration
+        config = Configuration('',parent_package,top_path)
+        flibname = modulename + '_fortran_f2py'
+        if fortran_files:
+            config.add_library(flibname,
+                               sources = fortran_files)
+            libraries.insert(0,flibname)
+
+        for block in f90_modules:
+            wrapper = PythonWrapperModule(block.name)
+            wrapper.add(block)
+            c_code = wrapper.c_code()
+            f_code = wrapper.fortran_code()
+            c_fn = os.path.join(build_dir,'%smodule.c' % (block.name))
+            f_fn = os.path.join(build_dir,'%s_f_wrappers_f2py.f' % (block.name))
+            f = open(c_fn,'w')
+            f.write(c_code)
+            f.close()
+            f = open(f_fn,'w')
+            f.write(f_code)
+            f.close()
+            f_lib = '%s_f_wrappers_f2py' % (block.name)
+            config.add_library(f_lib,
+                               sources = [f_fn])
+            config.add_extension(block.name,
+                                 sources=[c_fn] + c_files,
+                                 libraries = [f_lib] + libraries,
+                                 define_macros = define_macros,
+                                 undef_macros = undef_macros,
+                                 include_dirs = include_dirs,
+                                 extra_objects = extra_objects,
+                                 )
+        if external_subprograms:
+            wrapper = PythonWrapper(modulename)
+            for block in external_subprograms:
+                wrapper.add(block)
+            c_code = wrapper.c_code()
+            f_code = wrapper.fortran_code()
+            c_fn = os.path.join(temp_dir,'%smodule.c' % (modulename))
+            f_fn = os.path.join(temp_dir,'%s_f_wrappers_f2py.f' % (modulename))
+            f = open(c_fn,'w')
+            f.write(c_code)
+            f.close()
+            f = open(f_fn,'w')
+            f.write(f_code)
+            f.close()
+            f_lib = '%s_f_wrappers_f2py' % (modulename)
+            config.add_library(f_lib,
+                               sources = [f_fn])
+            config.add_extension(modulename,
+                                 sources=[c_fn] + c_files,
+                                 libraries = [f_lib] + libraries,
+                                 define_macros = define_macros,
+                                 undef_macros = undef_macros,
+                                 include_dirs = include_dirs,
+                                 extra_objects = extra_objects,
+                                 )
+        return config
+
+    old_sys_argv = sys.argv[:]
+    new_sys_argv = [sys.argv[0]] + ['build',
+                                   '--build-temp',build_dir,
+                                   '--build-base',build_dir,
+                                   '--build-platlib','.']
+    if fc_flags:
+        new_sys_argv += ['config_fc'] + fc_flags
+    sys.argv[:] = new_sys_argv
+
+    sys.stderr.write('setup arguments: %r' % (' '.join(sys.argv)))
+
+    from numpy.distutils.core import setup
+    setup(configuration=configuration)
+
+    sys.argv[:] = old_sys_argv
+
+    if clean_build_dir and os.path.exists(build_dir):
+        sys.stderr.write('Removing build directory %s\n'%(build_dir))
+        shutil.rmtree(build_dir)
+    return
+
+def main(sys_argv = None):
     """ Main function of f2py script.
     """
-    if '--help-link' in sys.argv[1:]:
-        sys.argv.remove('--help-link')
+    if sys_argv is None:
+        sys_argv = sys.argv[1:]
+    if '--help-link' in sys_argv:
+        sys_argv.remove('--help-link')
         from numpy.distutils.system_info import show_all
         show_all()
         return
-    if '-c' in sys.argv[1:]:
-        i = sys.argv.index('-c')
-        del sys.argv[i]
-        build_extension()
+    if '-c' in sys_argv:
+        sys_argv.remove('-c')
+        build_extension(sys_argv)
         return
-    if '-h' in sys.argv[1:]:
-        dump_signature()
+    if '-h' in sys_argv:
+        dump_signature(sys_argv)
         return
     print >> sys.stdout, __usage__

Modified: trunk/numpy/f2py/lib/parser/api.py
===================================================================
--- trunk/numpy/f2py/lib/parser/api.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/parser/api.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -30,9 +30,24 @@
                          and the directory of file name.
     """
     import os
+    import re
     from readfortran import FortranFileReader, FortranStringReader
     from parsefortran import FortranParser
     if os.path.isfile(input):
+        name,ext = os.path.splitext(input)
+        if ext.lower() in ['.c']:
+            # get signatures from C file comments starting with `/*f2py` and ending with `*/`.
+            # TODO: improve parser to take line number offset making line numbers in
+            #       parser messages correct.
+            f2py_c_comments = re.compile('/[*]\s*f2py\s.*[*]/',re.I | re.M)
+            f = open(filename,'r')
+            c_input = ''
+            for s1 in f2py_c_comments.findall(f.read()):
+                c_input += s1[2:-2].lstrip()[4:] + '\n'
+            f.close()
+            if isfree is None: isfree = True
+            if isstrict is None: isstrict = True
+            return parse(c_input, isfree, isstrict, include_dirs)
         reader = FortranFileReader(input,
                                    include_dirs = include_dirs)
         if isfree is None: isfree = reader.isfree

Modified: trunk/numpy/f2py/lib/parser/base_classes.py
===================================================================
--- trunk/numpy/f2py/lib/parser/base_classes.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/parser/base_classes.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -122,6 +122,14 @@
         self.init = None
         return
 
+    def __repr__(self):
+        l = []
+        for a in ['name','typedecl','dimension','bounds','length','attributes','intent','bind','check','init']:
+            v = getattr(self,a)
+            if v:
+                l.append('%s=%r' % (a,v))
+        return 'Variable: ' + ', '.join(l)
+
     def get_bit_size(self):
         typesize = self.typedecl.get_bit_size()
         if self.is_pointer():
@@ -372,7 +380,7 @@
             attr = getattr(self, n, None)
             if not attr: continue
             if hasattr(attr, 'torepr'):
-                r = attr.torepr(depht-1,incrtab)
+                r = attr.torepr(depth-1,incrtab)
             else:
                 r = repr(attr)
             l.append(ttab + '%s=%s' % (n, r))

Modified: trunk/numpy/f2py/lib/parser/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/parser/block_statements.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/parser/block_statements.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -34,7 +34,7 @@
     def get_type_by_name(self, name):
         implicit_rules = self.a.implicit_rules
         if implicit_rules is None:
-            raise AnalyzeError,'Implicit rules mapping is null'
+            raise AnalyzeError,'Implicit rules mapping is null while getting %r type' % (name)
         l = name[0].lower()
         if implicit_rules.has_key(l):
             return implicit_rules[l]
@@ -86,8 +86,9 @@
                     return stmt
         return
 
-    def topyf(self):
-        pass
+    def topyf(self, tab='  '):
+        sys.stderr.write('HasUseStmt.topyf not implemented\n')
+        return ''
 
 class HasVariables:
 
@@ -160,7 +161,7 @@
                 if isinstance(known_attributes,(list, tuple)):
                     if uattr not in known_attributes:
                         self.warning('unknown attribute %r' % (attr))
-                elif known_attributes(uattr):
+                elif not known_attributes(uattr):
                     self.warning('unknown attribute %r' % (attr))
                 attributes.append(uattr)
         return
@@ -266,6 +267,7 @@
                         module_provides = {}, # all symbols that are public and so
                                               # can be imported via USE statement
                                               # by other blocks
+                        module_interface = {}
                         )
 
     known_attributes = ['PUBLIC', 'PRIVATE']
@@ -281,6 +283,9 @@
     def get_provides(self):
         return self.a.module_provides
 
+    def get_interface(self):
+        return self.a.module_interface
+
     def analyze(self):
         content = self.content[:]
 
@@ -310,9 +315,11 @@
     def topyf(self, tab=''):
         s = tab + 'MODULE '+self.name + '\n'
         s +=  HasImplicitStmt.topyf(self, tab=tab+'  ')
-        s +=  HasAttributesStmt.topyf(self, tab=tab+'  ')
+        s +=  HasAttributes.topyf(self, tab=tab+'  ')
         s +=  HasTypeDecls.topyf(self, tab=tab+'  ')
         s +=  HasVariables.topyf(self, tab=tab+'  ')
+        for name, stmt in self.a.module_interface.items():
+            s += stmt.topyf(tab=tab+'    ')
         s +=  tab + '  CONTAINS\n'
         for name, stmt in self.a.module_subprogram.items():
             s += stmt.topyf(tab=tab+'    ')
@@ -400,7 +407,7 @@
     blocktype = 'interface'
 
 class Interface(BeginStatement, HasImplicitStmt, HasUseStmt,
-                HasModuleProcedures
+                HasModuleProcedures, HasAttributes
                 ):
     """
     INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
@@ -423,6 +430,8 @@
 
     a = AttributeHolder(interface_provides = {})
 
+    known_attributes = ['PUBLIC','PRIVATE']
+
     def get_classes(self):
         l = intrinsic_type_spec + interface_specification
         if self.reader.mode=='pyf':
@@ -455,22 +464,36 @@
             if isinstance(stmt, self.end_stmt_cls):
                 break
             stmt.analyze()
-            assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__`
+            #assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__`
         if content:
             self.show_message('Not analyzed content: %s' % content)
 
-        parent_provides = self.parent.get_provides()
-        if parent_provides is not None:
-            if self.is_public():
-                if parent_provides.has_key(self.name):
-                    self.warning('interface name conflict with %s, overriding.' % (self.name))
-                parent_provides[self.name] = self
-    
+        if self.parent.a.variables.has_key(self.name):
+            var = self.parent.a.variables.pop(self.name)
+            self.update_attributes(var.attributes)
+
+        parent_interface = self.parent.get_interface()
+        if parent_interface.has_key(self.name):
+            p = parent_interface[self.name]
+            last = p.content.pop()
+            assert isinstance(last,EndInterface),`last.__class__`
+            p.content += self.content
+            p.update_attributes(self.a.attributes)
+        else:
+            parent_interface[self.name] = self
         return
 
     def is_public(self):
-        return True # TODO: need review.
+        return 'PUBLIC' in self.a.attributes
 
+    def topyf(self, tab=''):
+        s = tab + self.tostr() + '\n'
+        s +=  HasImplicitStmt.topyf(self, tab=tab+'  ')
+        s +=  HasAttributes.topyf(self, tab=tab+'  ')
+        s +=  HasUseStmt.topyf(self, tab=tab+'  ')
+        s += tab + 'END' + self.tostr() + '\n'
+        return s        
+
 # Subroutine
 
 class SubProgramStatement(BeginStatement, ProgramBlock,
@@ -927,7 +950,7 @@
                         component_names = [], # specifies component order for sequence types
                         components = {}
                         )
-    known_attributes = re.compile(r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z').match
+    known_attributes = re.compile(r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z',re.I).match
 
     def process_item(self):
         line = self.item.get_line()[4:].lstrip()

Modified: trunk/numpy/f2py/lib/parser/parsefortran.py
===================================================================
--- trunk/numpy/f2py/lib/parser/parsefortran.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/parser/parsefortran.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -66,10 +66,10 @@
                 message = reader.format_message('FATAL ERROR',
                                                 'while processing line',
                                                 reader.linecount, reader.linecount)
-                reader.show_message(message, sys.stdout)
+                reader.show_message(message, sys.stderr)
                 reader = reader.reader
-            traceback.print_exc(file=sys.stdout)
-            self.reader.show_message(red_text('STOPPED PARSING'), sys.stdout)
+            traceback.print_exc(file=sys.stderr)
+            self.reader.show_message(red_text('STOPPED PARSING'), sys.stderr)
             return
         return
 
@@ -84,8 +84,12 @@
             self.block.analyze()
         except AnalyzeError:
             pass
-        except:
-            raise
+        except Exception, msg:
+            if str(msg) != '123454321':
+                traceback.print_exc(file=sys.stderr)
+                self.reader.show_message(red_text('FATAL ERROR: STOPPED ANALYSING %r CONTENT' % (self.reader.source) ), sys.stderr)
+                sys.exit(123454321)
+            return
         self.is_analyzed = True
         return
 

Modified: trunk/numpy/f2py/lib/parser/statements.py
===================================================================
--- trunk/numpy/f2py/lib/parser/statements.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/parser/statements.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -900,8 +900,8 @@
 
         module = modules[self.name]
         use_provides = self.parent.a.use_provides
+        print use
         
-        
         return
 
 class Exit(Statement):

Added: trunk/numpy/f2py/lib/py_wrap.py
===================================================================
--- trunk/numpy/f2py/lib/py_wrap.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/py_wrap.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -0,0 +1,410 @@
+__all__ = ['PythonWrapperModule']
+
+import re
+import os
+import sys
+
+from parser.api import *
+from wrapper_base import *
+
+class PythonWrapperModule(WrapperBase):
+
+    main_template = '''\
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+#include "Python.h"
+
+#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
+#include "numpy/arrayobject.h"
+#include "numpy/arrayscalars.h"
+
+%(header_list)s
+
+%(typedef_list)s
+
+%(extern_list)s
+
+%(c_code_list)s
+
+%(capi_code_list)s
+
+%(objdecl_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);
+  import_array();
+  %(module_init_list)s
+  if (PyErr_Occurred()) {
+    PyErr_SetString(PyExc_ImportError, "can\'t initialize module %(modulename)s");
+    return;
+  }
+}
+#ifdef __cplusplus
+}
+#endif
+'''
+
+    main_fortran_template = '''\
+! -*- f90 -*-
+%(fortran_code_list)s
+'''
+    def __init__(self, modulename):
+        WrapperBase.__init__(self)
+        self.modulename = modulename
+        
+        self.header_list = []
+        self.typedef_list = []
+        self.extern_list = []
+        self.objdecl_list = []
+        self.c_code_list = []
+        self.capi_code_list = []
+
+        self.module_method_list = []
+        self.module_init_list = []
+
+        self.fortran_code_list = []
+
+        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, 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()
+        elif isinstance(block, Module):
+            for name,declblock in block.a.type_decls.items():
+                self.add(declblock)
+        elif isinstance(block, TypeDecl):
+            self.info('Generating interface for %s' % (block.name))
+            PythonCAPIDerivedType(self, block)
+        elif isinstance(block, tuple(declaration_type_spec)):
+            self.info('Generating interface for %s' % (block.name))
+            PythonCAPIIntrinsicType(self, block)
+        else:
+            raise NotImplementedError,`block.__class__.__name__`
+        return
+    
+    def c_code(self):
+        return self.apply_attributes(self.main_template)
+    def fortran_code(self):
+        return self.apply_attributes(self.main_fortran_template)
+
+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)
+
+        self.ctype = ctype = typedecl.get_c_type()
+
+        if ctype.startswith('npy_'):
+            WrapperCCode(parent, 'pyobj_from_%s' % (ctype))
+            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
+
+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
+}
+'''
+
+    capi_code_template = '''\
+static void %(oname)s_dealloc(%(oname)sObject* self) {
+  if (self->data)
+    PyMem_Free(self->data);
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+static int pyobj_to_%(ctype)s(PyObject *obj,
+                              %(ctype)s* value_ptr) {
+  int return_value = 0;
+#if defined(F2PY_DEBUG_PYOBJ_TOFROM)
+  fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj))));
+#endif
+  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.");
+    } else {
+      return_value = 1;
+    }
+  }
+#if defined(F2PY_DEBUG_PYOBJ_TOFROM)
+  fprintf(stderr,"pyobj_to_%(ctype)s: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred());
+#endif
+  return return_value;
+}
+
+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();
+  }
+  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;
+}
+
+static PyObject * %(oname)s_new(PyTypeObject *type,
+                                PyObject *args, PyObject *kwds)
+{
+  return pyobj_from_%(ctype)s(NULL);
+}
+
+static int %(oname)s_init(%(oname)sObject *self,
+                          PyObject *capi_args, PyObject *capi_kwds)
+{
+   int return_value = 0;
+#if defined(F2PY_DEBUG_PYOBJ_TOFROM)
+  fprintf(stderr,"%(oname)s_init()\\n");
+#endif
+   if (!PyArg_ParseTuple(capi_args,"%(attr_format_elist)s"
+                                   %(attr_init_clist)s))
+      return_value = -1;                             
+#if defined(F2PY_DEBUG_PYOBJ_TOFROM)
+  fprintf(stderr,"%(oname)s_init: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred());
+#endif
+   return return_value;
+}
+
+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

Modified: trunk/numpy/f2py/lib/python_wrapper.py
===================================================================
--- trunk/numpy/f2py/lib/python_wrapper.py	2006-10-03 15:52:44 UTC (rev 3249)
+++ trunk/numpy/f2py/lib/python_wrapper.py	2006-10-04 09:49:54 UTC (rev 3250)
@@ -7,10 +7,6 @@
 
 from parser.api import *
 
-#from block_statements import *
-#from typedecl_statements import intrinsic_type_spec, Character
-#from utils import CHAR_BIT
-
 from wrapper_base import *
 
 class PythonWrapperModule(WrapperBase):
@@ -65,8 +61,6 @@
     def __init__(self, modulename):
         WrapperBase.__init__(self)
         self.modulename = modulename
-        #self.include_list = []
-        #self.cppmacro_list = []
         
         self.header_list = []
         self.typedef_list = []
@@ -80,11 +74,6 @@
 
         self.fortran_code_list = []
 
-        #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']




More information about the Numpy-svn mailing list