From b7f719aac1d6ff56cf58cb915ca7453820357a11 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Sun, 8 Oct 2006 13:16:13 +0000 Subject: [PATCH] F2PY G3: added simple test for subroutine with derived type intent(in,out) argument. Fixed bugs. --- numpy/f2py/lib/main.py | 51 ++++ numpy/f2py/lib/parser/base_classes.py | 41 +++- numpy/f2py/lib/parser/block_statements.py | 4 +- numpy/f2py/lib/parser/statements.py | 241 ++++++++++--------- numpy/f2py/lib/parser/typedecl_statements.py | 11 +- numpy/f2py/lib/py_wrap_type.py | 18 +- numpy/f2py/lib/test_derived_scalar.py | 73 ++++++ numpy/f2py/lib/test_scalar_in_out.py | 9 + 8 files changed, 306 insertions(+), 142 deletions(-) create mode 100644 numpy/f2py/lib/test_derived_scalar.py diff --git a/numpy/f2py/lib/main.py b/numpy/f2py/lib/main.py index fc265ae3221d..8892c6e52fcc 100644 --- a/numpy/f2py/lib/main.py +++ b/numpy/f2py/lib/main.py @@ -44,6 +44,56 @@ --2d-numeric Use f2py2e tool with Numeric support. --2d-numarray Use f2py2e tool with Numarray support. + -m Name of the module; f2py generates a Python/C API + file module.c or extension module . + For wrapping Fortran 90 modules, f2py will use Fortran + module names. + + +Options effective only with -h +------------------------------ + + -h Write signatures of the fortran routines to file + and exit. You can then edit and use it instead + of for generating extension module source. + If is stdout or stderr then the signatures are + printed to the corresponding stream. + + --overwrite-signature Overwrite existing signature file. + +Options effective only with -c +------------------------------ + + -c Compile fortran sources and build extension module. + + --build-dir All f2py generated files are created in . + Default is tempfile.mktemp() and it will be removed after + f2py stops unless is specified via --build-dir + option. + +numpy.distutils options effective only with -c +---------------------------------------------- + + --fcompiler= Specify Fortran compiler type by vendor + + + +Extra options effective only with -c +------------------------------------ + + -L/path/to/lib/ -l + -D -U + -I/path/to/include/ + .o .(so|dynlib|dll) .a + + Using the following macros may be required with non-gcc Fortran + compilers: + -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN + -DUNDERSCORE_G77 + + -DF2PY_DEBUG_PYOBJ_TOFROM --- pyobj_(to|from)_ functions will + print debugging messages to stderr. + """ import re @@ -266,6 +316,7 @@ def configuration(parent_package='', top_path=None): undef_macros = undef_macros, include_dirs = include_dirs, extra_objects = extra_objects, + language = 'f90', ) if external_subprograms: wrapper = PythonWrapperModule(modulename) diff --git a/numpy/f2py/lib/parser/base_classes.py b/numpy/f2py/lib/parser/base_classes.py index 4dce5ba8b4e9..9d633539e9c2 100644 --- a/numpy/f2py/lib/parser/base_classes.py +++ b/numpy/f2py/lib/parser/base_classes.py @@ -426,8 +426,9 @@ def torepr(self, depth=-1,incrtab=''): l.append(ttab + 'a=' + self.a.torepr(depth-1,incrtab+' ').lstrip()) return '\n'.join(l) - def get_indent_tab(self,colon=None,deindent=False): - if self.reader.isfix: + def get_indent_tab(self,colon=None,deindent=False,isfix=None): + if isfix is None: isfix = self.reader.isfix + if isfix: tab = ' '*6 else: tab = '' @@ -441,19 +442,35 @@ def get_indent_tab(self,colon=None,deindent=False): return tab s = self.item.label if colon is None: - if self.reader.isfix: + if isfix: colon = '' else: colon = ':' if s: c = '' - if self.reader.isfix: + if isfix: c = ' ' tab = tab[len(c+s)+len(colon):] if not tab: tab = ' ' tab = c + s + colon + tab return tab + def __str__(self): + return self.tofortran() + + def asfix(self): + lines = [] + for line in self.tofortran(isfix=True).split('\n'): + if len(line)>72 and line[0]==' ': + lines.append(line[:72]+'&\n &') + line = line[72:] + while len(line)>66: + lines.append(line[:66]+'&\n &') + line = line[66:] + lines.append(line+'\n') + else: lines.append(line+'\n') + return ''.join(lines).replace('\n &\n','\n') + def format_message(self, kind, message): if self.item is not None: message = self.reader.format_message(kind, message, @@ -544,11 +561,11 @@ def __init__(self, parent, item=None): def tostr(self): return self.blocktype.upper() + ' '+ self.name - - def __str__(self): - l=[self.get_indent_tab(colon=':') + self.tostr()] + + def tofortran(self, isfix=None): + l=[self.get_indent_tab(colon=':', isfix=isfix) + self.tostr()] for c in self.content: - l.append(str(c)) + l.append(c.tofortran(isfix=isfix)) return '\n'.join(l) def torepr(self, depth=-1, incrtab=''): @@ -736,10 +753,10 @@ def process_item(self): def analyze(self): return - def get_indent_tab(self,colon=None,deindent=False): - return Statement.get_indent_tab(self, colon=colon, deindent=True) + def get_indent_tab(self,colon=None,deindent=False,isfix=None): + return Statement.get_indent_tab(self, colon=colon, deindent=True,isfix=isfix) - def __str__(self): - return self.get_indent_tab() + 'END %s %s'\ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'END %s %s'\ % (self.blocktype.upper(),self.name or '') diff --git a/numpy/f2py/lib/parser/block_statements.py b/numpy/f2py/lib/parser/block_statements.py index e5596d12ae07..a6bb6c321de0 100644 --- a/numpy/f2py/lib/parser/block_statements.py +++ b/numpy/f2py/lib/parser/block_statements.py @@ -846,8 +846,8 @@ def tostr(self): assert len(self.content)==1,`self.content` return 'IF (%s) %s' % (self.expr, str(self.content[0]).lstrip()) - def __str__(self): - return self.get_indent_tab(colon=':') + self.tostr() + def tofortran(self,isfix=None): + return self.get_indent_tab(colon=':',isfix=isfix) + self.tostr() def get_classes(self): return action_stmt diff --git a/numpy/f2py/lib/parser/statements.py b/numpy/f2py/lib/parser/statements.py index 28458ad1726c..be846da8df35 100644 --- a/numpy/f2py/lib/parser/statements.py +++ b/numpy/f2py/lib/parser/statements.py @@ -56,7 +56,8 @@ def process_item(self): return items.append(item) return - def __str__(self): + + def tofortran(self,isfix=None): if hasattr(self,'stmtname'): clsname = self.stmtname.upper() else: @@ -64,7 +65,7 @@ def __str__(self): s = ', '.join(self.items) if s: s = ' ' + s - return self.get_indent_tab() + clsname + s + return self.get_indent_tab(isfix=isfix) + clsname + s # Execution statements @@ -100,8 +101,8 @@ def process_item(self): self.expr = apply_map(m.group('expr')) return - def __str__(self): - return self.get_indent_tab() + '%s %s %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + '%s %s %s' \ % (self.variable, self.sign, self.expr) def analyze(self): return @@ -124,8 +125,8 @@ def process_item(self): assert not self.item.has_map() self.items = [line[:i].rstrip(),line[i+2:].lstrip()] return - def __str__(self): - return self.get_indent_tab() + 'ASSIGN %s TO %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ASSIGN %s TO %s' \ % (self.items[0], self.items[1]) def analyze(self): return @@ -173,8 +174,8 @@ def process_item(self): self.items = items return - def __str__(self): - s = self.get_indent_tab() + 'CALL '+str(self.designator) + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'CALL '+str(self.designator) if self.items: s += '('+', '.join(map(str,self.items))+ ')' return s @@ -199,8 +200,8 @@ def process_item(self): self.label = self.item.get_line()[2:].lstrip()[2:].lstrip() return - def __str__(self): - return self.get_indent_tab() + 'GO TO %s' % (self.label) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'GO TO %s' % (self.label) def analyze(self): return class ComputedGoto(Statement): @@ -218,8 +219,8 @@ def process_item(self): line = line[1:].lstrip() self.expr = apply_map(line) return - def __str__(self): - return self.get_indent_tab() + 'GO TO (%s) %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'GO TO (%s) %s' \ % (', '.join(self.items), self.expr) def analyze(self): return @@ -242,8 +243,8 @@ def process_item(self): self.items = split_comma(line[i+1:-1], self.item) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) if self.items: return tab + 'GO TO %s (%s)' \ % (self.varname, ', '.join(self.items)) @@ -260,7 +261,7 @@ def process_item(self): self.label = self.item.label return - def __str__(self): + def tofortran(self, isfix=None): return self.get_indent_tab(deindent=True) + 'CONTINUE' def analyze(self): return @@ -275,8 +276,8 @@ def process_item(self): self.expr = self.item.apply_map(self.item.get_line()[6:].lstrip()) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) if self.expr: return tab + 'RETURN %s' % (self.expr) return tab + 'RETURN' @@ -294,8 +295,8 @@ def process_item(self): self.code = self.item.apply_map(self.item.get_line()[4:].lstrip()) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) if self.code: return tab + 'STOP %s' % (self.code) return tab + 'STOP' @@ -324,8 +325,8 @@ def process_item(self): self.items = items[1:] return - def __str__(self): - return self.get_indent_tab() + 'PRINT %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'PRINT %s' \ % (', '.join([self.format]+self.items)) def analyze(self): return @@ -365,8 +366,8 @@ def process_item(self): self.items = split_comma(line[i+1:], item) return - def __str__(self): - s = self.get_indent_tab() + 'READ (%s)' % (', '.join(self.specs)) + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'READ (%s)' % (', '.join(self.specs)) if self.items: return s + ' ' + ', '.join(self.items) return s @@ -381,8 +382,8 @@ def process_item(self): self.items = items[1:] return - def __str__(self): - return self.get_indent_tab() + 'READ ' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'READ ' \ + ', '.join([self.format]+self.items) class Write(Statement): @@ -399,8 +400,8 @@ def process_item(self): self.items = split_comma(line[i+1:], item) return - def __str__(self): - s = self.get_indent_tab() + 'WRITE (%s)' % ', '.join(self.specs) + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'WRITE (%s)' % ', '.join(self.specs) if self.items: s += ' ' + ', '.join(self.items) return s @@ -430,8 +431,8 @@ def process_item(self): self.specs = specs_split_comma(line,self.item) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) return tab + 'FLUSH (%s)' % (', '.join(self.specs)) def analyze(self): return @@ -452,8 +453,8 @@ def process_item(self): self.specs = specs_split_comma(\ self.item.get_line()[4:].lstrip()[1:-1], self.item) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) return tab + 'WAIT (%s)' % (', '.join(self.specs)) def analyze(self): return @@ -463,7 +464,7 @@ class Contains(Statement): """ match = re.compile(r'contains\Z',re.I).match def process_item(self): return - def __str__(self): return self.get_indent_tab() + 'CONTAINS' + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) + 'CONTAINS' class Allocate(Statement): """ @@ -499,11 +500,11 @@ def process_item(self): self.items = specs_split_comma(line2, item2) return - def __str__(self): + def tofortran(self, isfix=None): t = '' if self.spec: t = self.spec.tostr() + ' :: ' - return self.get_indent_tab() \ + return self.get_indent_tab(isfix=isfix) \ + 'ALLOCATE (%s%s)' % (t,', '.join(self.items)) def analyze(self): return @@ -521,7 +522,7 @@ def process_item(self): line = self.item.get_line()[10:].lstrip()[1:-1].strip() self.items = specs_split_comma(line, self.item) return - def __str__(self): return self.get_indent_tab() \ + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) \ + 'DEALLOCATE (%s)' % (', '.join(self.items)) def analyze(self): return @@ -542,8 +543,8 @@ def process_item(self): self.items = items return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) return tab + 'MODULE PROCEDURE %s' % (', '.join(self.items)) def analyze(self): @@ -571,9 +572,9 @@ def process_item(self): self.items = split_comma(line, self.item) return - def __str__(self): + def tofortran(self, isfix=None): clsname = self.__class__.__name__.upper() - tab = self.get_indent_tab() + tab = self.get_indent_tab(isfix=isfix) if self.items: return tab + clsname + ' ' + ', '.join(self.items) return tab + clsname @@ -607,8 +608,8 @@ def process_item(self): line = self.item.get_line()[5:].lstrip()[1:-1].strip() self.specs = specs_split_comma(line, self.item) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) return tab + 'CLOSE (%s)' % (', '.join(self.specs)) def analyze(self): return @@ -620,10 +621,10 @@ class Cycle(Statement): def process_item(self): self.name = self.item.get_line()[5:].lstrip() return - def __str__(self): + def tofortran(self, isfix=None): if self.name: - return self.get_indent_tab() + 'CYCLE ' + self.name - return self.get_indent_tab() + 'CYCLE' + return self.get_indent_tab(isfix=isfix) + 'CYCLE ' + self.name + return self.get_indent_tab(isfix=isfix) + 'CYCLE' def analyze(self): return class FilePositioningStatement(Statement): @@ -653,9 +654,9 @@ def process_item(self): self.specs = specs_split_comma(spec, self.item) return - def __str__(self): + def tofortran(self, isfix=None): clsname = self.__class__.__name__.upper() - return self.get_indent_tab() + clsname + ' (%s)' % (', '.join(self.specs)) + return self.get_indent_tab(isfix=isfix) + clsname + ' (%s)' % (', '.join(self.specs)) def analyze(self): return class Backspace(FilePositioningStatement): pass @@ -676,8 +677,8 @@ def process_item(self): line = self.item.get_line()[4:].lstrip()[1:-1].strip() self.specs = specs_split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'OPEN (%s)' % (', '.join(self.specs)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'OPEN (%s)' % (', '.join(self.specs)) def analyze(self): return class Format(Statement): @@ -715,8 +716,8 @@ def process_item(self): assert line[0]+line[-1]=='()',`line` self.specs = split_comma(line[1:-1], item) return - def __str__(self): - return self.get_indent_tab() + 'FORMAT (%s)' % (', '.join(self.specs)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'FORMAT (%s)' % (', '.join(self.specs)) def analyze(self): return class Save(Statement): @@ -750,8 +751,8 @@ def process_item(self): return self.items = items return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) if not self.items: return tab + 'SAVE' return tab + 'SAVE %s' % (', '.join(self.items)) @@ -797,8 +798,8 @@ def process_item(self): self.isvalid = True return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) l = [] for o,v in self.stmts: l.append('%s / %s /' %(', '.join(o),', '.join(v))) @@ -815,8 +816,8 @@ def process_item(self): line = self.item.get_line()[7:].lstrip()[1:-1].strip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'NULLIFY (%s)' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'NULLIFY (%s)' % (', '.join(self.items)) def analyze(self): return class Use(Statement): @@ -857,8 +858,8 @@ def process_item(self): self.items = split_comma(line, self.item) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = 'USE' if self.nature: s += ' ' + self.nature + ' ::' @@ -912,10 +913,10 @@ class Exit(Statement): def process_item(self): self.name = self.item.get_line()[4:].lstrip() return - def __str__(self): + def tofortran(self, isfix=None): if self.name: - return self.get_indent_tab() + 'EXIT ' + self.name - return self.get_indent_tab() + 'EXIT' + return self.get_indent_tab(isfix=isfix) + 'EXIT ' + self.name + return self.get_indent_tab(isfix=isfix) + 'EXIT' def analyze(self): return class Parameter(Statement): @@ -928,8 +929,8 @@ def process_item(self): line = self.item.get_line()[9:].lstrip()[1:-1].strip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'PARAMETER (%s)' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'PARAMETER (%s)' % (', '.join(self.items)) def analyze(self): for item in self.items: i = item.find('=') @@ -957,8 +958,8 @@ def process_item(self): items.append('('+s+')') self.items = items return - def __str__(self): - return self.get_indent_tab() + 'EQUIVALENCE %s' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'EQUIVALENCE %s' % (', '.join(self.items)) def analyze(self): return class Dimension(Statement): @@ -973,8 +974,8 @@ def process_item(self): line = line[2:].lstrip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'DIMENSION %s' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'DIMENSION %s' % (', '.join(self.items)) def analyze(self): for line in self.items: i = line.find('(') @@ -997,8 +998,8 @@ def process_item(self): line = line[2:].lstrip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'TARGET %s' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'TARGET %s' % (', '.join(self.items)) def analyze(self): for line in self.items: i = line.find('(') @@ -1025,8 +1026,8 @@ def process_item(self): line = line[2:].lstrip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'POINTER %s' % (', '.join(self.items)) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'POINTER %s' % (', '.join(self.items)) def analyze(self): for line in self.items: i = line.find('(') @@ -1089,8 +1090,8 @@ def process_item(self): self.labels = [l1.strip(),l2.strip(),l3.strip()] return - def __str__(self): - return self.get_indent_tab() + 'IF (%s) %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'IF (%s) %s' \ % (self.expr,', '.join(self.labels)) def analyze(self): return @@ -1123,11 +1124,11 @@ def process_item(self): self.specs = specs_split_comma(line[1:i].strip(), self.item) self.items = split_comma(line[i+1:].lstrip(), self.item) return - def __str__(self): + def tofortran(self, isfix=None): if self.items: - return self.get_indent_tab() + 'INQUIRE (%s) %s' \ + return self.get_indent_tab(isfix=isfix) + 'INQUIRE (%s) %s' \ % (', '.join(self.specs), ', '.join(self.items)) - return self.get_indent_tab() + 'INQUIRE (%s)' \ + return self.get_indent_tab(isfix=isfix) + 'INQUIRE (%s)' \ % (', '.join(self.specs)) def analyze(self): return @@ -1138,7 +1139,7 @@ class Sequence(Statement): match = re.compile(r'sequence\Z',re.I).match def process_item(self): return - def __str__(self): return self.get_indent_tab() + 'SEQUENCE' + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) + 'SEQUENCE' def analyze(self): self.parent.update_attributes('SEQUENCE') return @@ -1183,11 +1184,11 @@ def process_item(self): self.items = items return - def __str__(self): + def tofortran(self, isfix=None): l = [] for name,s in self.items: l.append('%s %s' % (name,s)) - tab = self.get_indent_tab() + tab = self.get_indent_tab(isfix=isfix) return tab + 'NAMELIST ' + ', '.join(l) class Common(Statement): @@ -1223,7 +1224,7 @@ def process_item(self): line = line[i:].lstrip() self.items = items return - def __str__(self): + def tofortran(self, isfix=None): l = [] for name,s in self.items: s = ', '.join(s) @@ -1231,7 +1232,7 @@ def __str__(self): l.append('/ %s / %s' % (name,s)) else: l.append(s) - tab = self.get_indent_tab() + tab = self.get_indent_tab(isfix=isfix) return tab + 'COMMON ' + ' '.join(l) def analyze(self): for cname, items in self.items: @@ -1285,8 +1286,8 @@ def process_item(self): self.isvalid = False return return - def __str__(self): - return self.get_indent_tab() + 'INTENT (%s) %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'INTENT (%s) %s' \ % (', '.join(self.specs), ', '.join(self.items)) def analyze(self): for name in self.items: @@ -1326,8 +1327,8 @@ def process_item(self): self.name = name self.items = items return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = tab + 'ENTRY '+self.name if self.items: s += ' (%s)' % (', '.join(self.items)) @@ -1392,8 +1393,8 @@ def process_item(self): self.mask = mask return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) l = [] for index,s1,s2,s3 in self.specs: s = '%s = %s : %s' % (index,s1,s2) @@ -1455,8 +1456,8 @@ def process_item(self): self.name = line[:i].rstrip() self.bname = line[i+1:].lstrip()[1:].lstrip() return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = 'PROCEDURE ' if self.iname: s += '(' + self.iname + ') ' @@ -1485,8 +1486,8 @@ def process_item(self): self.items = split_comma(line[i+2:].lstrip()) return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = 'GENERIC' if self.aspec: s += ', '+self.aspec @@ -1512,8 +1513,8 @@ def process_item(self): line = line[2:].lstrip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'ALLOCATABLE ' + ', '.join(self.items) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ALLOCATABLE ' + ', '.join(self.items) def analyze(self): for line in self.items: i = line.find('(') @@ -1562,8 +1563,8 @@ def process_item(self): items.append(item) self.items = items return - def __str__(self): - return self.get_indent_tab() + 'BIND (%s) %s' %\ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'BIND (%s) %s' %\ (', '.join(self.specs), ', '.join(self.items)) # IF construct statements @@ -1584,7 +1585,7 @@ def process_item(self): self.isvalid = False return - def __str__(self): + def tofortran(self, isfix=None): if self.name: return self.get_indent_tab(deindent=True) + 'ELSE ' + self.name return self.get_indent_tab(deindent=True) + 'ELSE' @@ -1611,7 +1612,7 @@ def process_item(self): self.isvalid = False return - def __str__(self): + def tofortran(self, isfix=None): s = '' if self.name: s = ' ' + self.name @@ -1659,8 +1660,8 @@ def process_item(self): self.isvalid = False return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = 'CASE' if self.items: l = [] @@ -1696,8 +1697,8 @@ def process_item(self): self.isvalid = False return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) return tab + 'WHERE ( %s ) %s' % (self.expr, str(self.content[0]).lstrip()) def analyze(self): return @@ -1725,8 +1726,8 @@ def process_item(self): self.isvalid = False return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = 'ELSE WHERE' if self.expr is not None: s += ' ( %s )' % (self.expr) @@ -1749,8 +1750,8 @@ def process_item(self): line = line[2:].lstrip() self.items = split_comma(line, self.item) return - def __str__(self): - return self.get_indent_tab() + 'ENUMERATOR ' + ', '.join(self.items) + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ENUMERATOR ' + ', '.join(self.items) # F2PY specific statements @@ -1762,8 +1763,8 @@ class FortranName(Statement): def process_item(self): self.value = self.item.get_line()[11:].lstrip() return - def __str__(self): - return self.get_indent_tab() + 'FORTRANNAME ' + self.value + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'FORTRANNAME ' + self.value class Threadsafe(Statement): """ @@ -1772,8 +1773,8 @@ class Threadsafe(Statement): match = re.compile(r'threadsafe\Z',re.I).match def process_item(self): return - def __str__(self): - return self.get_indent_tab() + 'THREADSAFE' + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'THREADSAFE' class Depend(Statement): """ @@ -1791,8 +1792,8 @@ def process_item(self): self.items = split_comma(line) return - def __str__(self): - return self.get_indent_tab() + 'DEPEND ( %s ) %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'DEPEND ( %s ) %s' \ % (', '.join(self.depends), ', '.join(self.items)) class Check(Statement): @@ -1811,8 +1812,8 @@ def process_item(self): line = line[2:].lstrip() self.value = line return - def __str__(self): - return self.get_indent_tab() + 'CHECK ( %s ) %s' \ + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CHECK ( %s ) %s' \ % (self.expr, self.value) class CallStatement(Statement): @@ -1823,8 +1824,8 @@ class CallStatement(Statement): def process_item(self): self.expr = self.item.apply_map(self.item.get_line()[13:].lstrip()) return - def __str__(self): - return self.get_indent_tab() + 'CALLSTATEMENT ' + self.expr + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CALLSTATEMENT ' + self.expr class CallProtoArgument(Statement): """ @@ -1834,8 +1835,8 @@ class CallProtoArgument(Statement): def process_item(self): self.specs = self.item.apply_map(self.item.get_line()[17:].lstrip()) return - def __str__(self): - return self.get_indent_tab() + 'CALLPROTOARGUMENT ' + self.specs + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CALLPROTOARGUMENT ' + self.specs # Non-standard statements @@ -1847,9 +1848,9 @@ class Pause(Statement): def process_item(self): self.value = self.item.apply_map(self.item.get_line()[5:].lstrip()) return - def __str__(self): + def tofortran(self, isfix=None): if self.value: - return self.get_indent_tab() + 'PAUSE ' + self.value - return self.get_indent_tab() + 'PAUSE' + return self.get_indent_tab(isfix=isfix) + 'PAUSE ' + self.value + return self.get_indent_tab(isfix=isfix) + 'PAUSE' def analyze(self): return diff --git a/numpy/f2py/lib/parser/typedecl_statements.py b/numpy/f2py/lib/parser/typedecl_statements.py index 3031c582ae7c..3c07a0128088 100644 --- a/numpy/f2py/lib/parser/typedecl_statements.py +++ b/numpy/f2py/lib/parser/typedecl_statements.py @@ -260,8 +260,8 @@ def tostr(self): return clsname + s - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self,isfix=None): + tab = self.get_indent_tab(isfix=isfix) s = self.tostr() if self.attrspec: s += ', ' + ', '.join(self.attrspec) @@ -270,6 +270,9 @@ def __str__(self): if self.entity_decls: s += ' ' + ', '.join(self.entity_decls) return tab + s + + def __str__(self): + return self.tofortran() def __eq__(self, other): if self.__class__ is not other.__class__: @@ -538,8 +541,8 @@ def process_item(self): self.items = items return - def __str__(self): - tab = self.get_indent_tab() + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) if not self.items: return tab + 'IMPLICIT NONE' l = [] diff --git a/numpy/f2py/lib/py_wrap_type.py b/numpy/f2py/lib/py_wrap_type.py index 50481ad7b7a7..1f3b68ef0181 100644 --- a/numpy/f2py/lib/py_wrap_type.py +++ b/numpy/f2py/lib/py_wrap_type.py @@ -2,7 +2,8 @@ __all__ = ['PythonCAPIType'] from wrapper_base import * -from parser.api import CHAR_BIT, Module, declaration_type_spec, TypeDecl +from parser.api import CHAR_BIT, Module, declaration_type_spec, \ + TypeDecl, TypeStmt, Subroutine, Function class PythonCAPIType(WrapperBase): """ @@ -11,7 +12,11 @@ class PythonCAPIType(WrapperBase): def __init__(self, parent, typedecl): WrapperBase.__init__(self) if isinstance(typedecl, tuple(declaration_type_spec)): - PythonCAPIIntrinsicType(parent, typedecl) + if isinstance(typedecl, TypeStmt): + type_decl = typedecl.get_type_decl(typedecl.name) + PythonCAPIDerivedType(parent, type_decl) + else: + PythonCAPIIntrinsicType(parent, typedecl) elif isinstance(typedecl, TypeDecl): PythonCAPIDerivedType(parent, typedecl) else: @@ -516,6 +521,7 @@ class PythonCAPIDerivedType(WrapperBase): fortran_code_template = '''\ subroutine %(init_func)s(init_func_c, self, obj) %(use_stmt_list)s + %(type_decl_list)s external init_func_c ! self is %(oname)sObject external self @@ -557,7 +563,7 @@ def __init__(self, parent, typedecl): for n in typedecl.a.component_names: v = typedecl.a.components[n] t = v.get_typedecl() - PythonCAPIType(t) + PythonCAPIType(parent, t) ct = t.get_c_type() on = 'f2py_' + t.name parent.add(t) @@ -605,8 +611,12 @@ def __init__(self, parent, typedecl): self.cname = typedecl.get_c_name() self.use_stmt_list = [] + self.type_decl_list = [] if isinstance(typedecl.parent, Module): self.use_stmt_list.append('use %s' % (typedecl.parent.name)) - + elif isinstance(typedecl.parent, (Subroutine, Function)): + self.type_decl_list.append(typedecl.asfix()) + else: + raise NotImplementedError,'types declared in '+typedecl.parent.__class__.__name__ parent.apply_templates(self) return diff --git a/numpy/f2py/lib/test_derived_scalar.py b/numpy/f2py/lib/test_derived_scalar.py new file mode 100644 index 000000000000..23f504a1c7cb --- /dev/null +++ b/numpy/f2py/lib/test_derived_scalar.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +""" +Tests for intent(in,out) derived type arguments in Fortran subroutine's. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * + +def build(fortran_code, rebuild=True): + modulename = os.path.splitext(os.path.basename(__file__))[0]+'_ext' + try: + exec ('import %s as m' % (modulename)) + if rebuild and os.stat(m.__file__)[8] < os.stat(__file__)[8]: + del sys.modules[m.__name__] # soft unload extension module + os.remove(m.__file__) + raise ImportError,'%s is newer than %s' % (__file__, m.__file__) + except ImportError,msg: + print msg, ', recompiling %s.' % (modulename) + import tempfile + fname = tempfile.mktemp() + '.f90' + f = open(fname,'w') + f.write(fortran_code) + f.close() + sys_argv = [] + sys_argv.extend(['--build-dir','dsctmp']) + #sys_argv.extend(['-DF2PY_DEBUG_PYOBJ_TOFROM']) + from main import build_extension + sys_argv.extend(['-m',modulename, fname]) + build_extension(sys_argv) + os.remove(fname) + os.system(' '.join([sys.executable] + sys.argv)) + sys.exit(0) + return m + +fortran_code = ''' +subroutine foo(a) + type myt + integer flag + end type myt + type(myt) a +!f2py intent(in,out) a + a % flag = a % flag + 1 +end +''' + +# tester note: set rebuild=True when changing fortan_code and for SVN +m = build(fortran_code, rebuild=True) + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_simple(self, level=1): + a = m.myt(2) + assert_equal(a.flag,2) + assert isinstance(a,m.myt),`a` + r = m.foo(a) + assert isinstance(r,m.myt),`r` + assert_equal(r.flag,3) + assert_equal(a.flag,2) + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/test_scalar_in_out.py b/numpy/f2py/lib/test_scalar_in_out.py index 21bbb2c2ef42..eeca265e55a7 100644 --- a/numpy/f2py/lib/test_scalar_in_out.py +++ b/numpy/f2py/lib/test_scalar_in_out.py @@ -1,6 +1,15 @@ #!/usr/bin/env python """ +Tests for intent(in,out) arguments in Fortran subroutine's. +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson +Created: Oct 2006 +----- """ import os