diff options
| author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-04 09:49:54 +0000 |
|---|---|---|
| committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-04 09:49:54 +0000 |
| commit | c620acddd34a07edd6f33baad0adfad6e8cf1bd5 (patch) | |
| tree | 3413710782a3f16711c4935cde86fbb5e69c35dd /numpy/f2py | |
| parent | ac93e95702a9047b774b4cdd1838c9e1b1f70739 (diff) | |
| download | numpy-c620acddd34a07edd6f33baad0adfad6e8cf1bd5.tar.gz | |
F2PY G3: exposed wrappers via f2py script. A working example: wrap F90 module containing derived type with scalar components.
Diffstat (limited to 'numpy/f2py')
| -rw-r--r-- | numpy/f2py/lib/main.py | 272 | ||||
| -rw-r--r-- | numpy/f2py/lib/parser/api.py | 15 | ||||
| -rw-r--r-- | numpy/f2py/lib/parser/base_classes.py | 10 | ||||
| -rw-r--r-- | numpy/f2py/lib/parser/block_statements.py | 55 | ||||
| -rw-r--r-- | numpy/f2py/lib/parser/parsefortran.py | 14 | ||||
| -rw-r--r-- | numpy/f2py/lib/parser/statements.py | 2 | ||||
| -rw-r--r-- | numpy/f2py/lib/py_wrap.py | 410 | ||||
| -rw-r--r-- | numpy/f2py/lib/python_wrapper.py | 11 |
8 files changed, 714 insertions, 75 deletions
diff --git a/numpy/f2py/lib/main.py b/numpy/f2py/lib/main.py index 64b9447f5..c5b40cf35 100644 --- a/numpy/f2py/lib/main.py +++ b/numpy/f2py/lib/main.py @@ -12,7 +12,9 @@ Created: Oct 2006 """ import os +import re import sys +import tempfile try: from numpy import __version__ as numpy_version @@ -44,53 +46,92 @@ Options """ -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 @@ def dump_signature(): 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 @@ def dump_signature(): 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') + + 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(): +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__ diff --git a/numpy/f2py/lib/parser/api.py b/numpy/f2py/lib/parser/api.py index 0a7346095..4b3ea88fa 100644 --- a/numpy/f2py/lib/parser/api.py +++ b/numpy/f2py/lib/parser/api.py @@ -30,9 +30,24 @@ def parse(input, isfree=None, isstrict=None, include_dirs = None): 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 diff --git a/numpy/f2py/lib/parser/base_classes.py b/numpy/f2py/lib/parser/base_classes.py index 7feafd74f..76a26b666 100644 --- a/numpy/f2py/lib/parser/base_classes.py +++ b/numpy/f2py/lib/parser/base_classes.py @@ -122,6 +122,14 @@ class Variable: 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 @@ class Statement: 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)) diff --git a/numpy/f2py/lib/parser/block_statements.py b/numpy/f2py/lib/parser/block_statements.py index 223d7659c..e5596d12a 100644 --- a/numpy/f2py/lib/parser/block_statements.py +++ b/numpy/f2py/lib/parser/block_statements.py @@ -34,7 +34,7 @@ class HasImplicitStmt: 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 @@ class HasUseStmt: 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 @@ class HasAttributes: 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 @@ class Module(BeginStatement, HasAttributes, 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 @@ class Module(BeginStatement, HasAttributes, 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 @@ class Module(BeginStatement, HasAttributes, 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 @@ class EndInterface(EndStatement): blocktype = 'interface' class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, - HasModuleProcedures + HasModuleProcedures, HasAttributes ): """ INTERFACE [<generic-spec>] | ABSTRACT INTERFACE @@ -423,6 +430,8 @@ class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, a = AttributeHolder(interface_provides = {}) + known_attributes = ['PUBLIC','PRIVATE'] + def get_classes(self): l = intrinsic_type_spec + interface_specification if self.reader.mode=='pyf': @@ -455,21 +464,35 @@ class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, 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 @@ -927,7 +950,7 @@ class Type(BeginStatement, HasVariables, HasAttributes): 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() diff --git a/numpy/f2py/lib/parser/parsefortran.py b/numpy/f2py/lib/parser/parsefortran.py index ac3df3068..71b019122 100644 --- a/numpy/f2py/lib/parser/parsefortran.py +++ b/numpy/f2py/lib/parser/parsefortran.py @@ -66,10 +66,10 @@ class FortranParser: 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 @@ class FortranParser: 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 diff --git a/numpy/f2py/lib/parser/statements.py b/numpy/f2py/lib/parser/statements.py index 7966692d2..28458ad17 100644 --- a/numpy/f2py/lib/parser/statements.py +++ b/numpy/f2py/lib/parser/statements.py @@ -900,7 +900,7 @@ class Use(Statement): module = modules[self.name] use_provides = self.parent.a.use_provides - + print use return diff --git a/numpy/f2py/lib/py_wrap.py b/numpy/f2py/lib/py_wrap.py new file mode 100644 index 000000000..788094085 --- /dev/null +++ b/numpy/f2py/lib/py_wrap.py @@ -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 diff --git a/numpy/f2py/lib/python_wrapper.py b/numpy/f2py/lib/python_wrapper.py index 6f7500b1e..7f73d6fbb 100644 --- a/numpy/f2py/lib/python_wrapper.py +++ b/numpy/f2py/lib/python_wrapper.py @@ -7,10 +7,6 @@ import sys 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 @@ PyMODINIT_FUNC init%(modulename)s(void) { 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 @@ PyMODINIT_FUNC init%(modulename)s(void) { 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'] |
