summaryrefslogtreecommitdiff
path: root/numpy/f2py
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2006-06-26 05:54:44 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2006-06-26 05:54:44 +0000
commitff660cb1a45a60128b6d934bc6977773b3ca7e34 (patch)
treebaf63ccb3f12bee380bf723d6eb8b49703e50666 /numpy/f2py
parentecd8d3e9db972b5d1f3633266004942004052354 (diff)
downloadnumpy-ff660cb1a45a60128b6d934bc6977773b3ca7e34.tar.gz
Cont. impl. Fortran parser.
Diffstat (limited to 'numpy/f2py')
-rw-r--r--numpy/f2py/lib/base_classes.py12
-rw-r--r--numpy/f2py/lib/block_statements.py79
-rw-r--r--numpy/f2py/lib/parsefortran.py11
-rw-r--r--numpy/f2py/lib/readfortran.py70
-rw-r--r--numpy/f2py/lib/splitline.py19
-rw-r--r--numpy/f2py/lib/statements.py233
-rw-r--r--numpy/f2py/lib/typedecl_statements.py24
7 files changed, 388 insertions, 60 deletions
diff --git a/numpy/f2py/lib/base_classes.py b/numpy/f2py/lib/base_classes.py
index 24a86ebf6..4f588ff32 100644
--- a/numpy/f2py/lib/base_classes.py
+++ b/numpy/f2py/lib/base_classes.py
@@ -126,7 +126,13 @@ class BeginStatement(Statement):
return False
def handle_unknown_item(self, item):
- print self.__class__.__name__,item,item.get_line()
+ message = item.reader.format_message(\
+ 'WARNING',
+ 'no parse pattern found for "%s" in %r block.'\
+ % (item.get_line(),self.__class__.__name__),
+ item.span[0], item.span[1])
+ print >> sys.stderr, message
+ sys.stderr.flush()
self.content.append(item)
return
@@ -148,7 +154,7 @@ class BeginStatement(Statement):
item = self.get_item()
if not end_flag:
- message = self.reader.format_message(\
+ message = self.item.reader.format_message(\
'WARNING',
'failed to find the end of block for %s'\
% (self.__class__.__name__),
@@ -184,7 +190,7 @@ class EndStatement(Statement):
self.isvalid = False
if line:
if not line==self.parent.name:
- message = self.reader.format_message(\
+ message = item.reader.format_message(\
'WARNING',
'expected the end of %r block but got end of %r, skipping.'\
% (self.parent.name, line),
diff --git a/numpy/f2py/lib/block_statements.py b/numpy/f2py/lib/block_statements.py
index e78ebe355..92a7f1493 100644
--- a/numpy/f2py/lib/block_statements.py
+++ b/numpy/f2py/lib/block_statements.py
@@ -38,7 +38,7 @@ class BeginSource(BeginStatement):
if self.reader.isfix77:
line = item.get_line()
if line=='end':
- message = self.reader.format_message(\
+ message = item.reader.format_message(\
'WARNING',
'assuming the end of undefined PROGRAM statement',
item.span[0],item.span[1])
@@ -131,11 +131,21 @@ class EndInterface(EndStatement):
class Interface(BeginStatement):
"""
- INTERFACE [generic-spec] | ABSTRACT INTERFACE
- END INTERFACE [generic-spec]
+ INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
+ END INTERFACE [<generic-spec>]
+
+ <generic-spec> = <generic-name>
+ | OPERATOR ( <defined-operator> )
+ | ASSIGNMENT ( = )
+ | <dtio-generic-spec>
+ <dtio-generic-spec> = READ ( FORMATTED )
+ | READ ( UNFORMATTED )
+ | WRITE ( FORMATTED )
+ | WRITE ( UNFORMATTED )
+
"""
modes = ['free90', 'fix90', 'pyf']
- match = re.compile(r'(interface\s*\w*|abstract\s*interface)\Z',re.I).match
+ match = re.compile(r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z',re.I).match
end_stmt_cls = EndInterface
blocktype = 'interface'
@@ -252,6 +262,34 @@ class Select(BeginStatement):
def get_classes(self):
return [Case] + execution_part_construct
+# Where
+
+class EndWhere(EndStatement):
+ match = re.compile(r'end\s*\w*\Z',re.I).match
+
+
+class Where(BeginStatement):
+ """
+ [ <where-construct-name> : ] WHERE ( <mask-expr> )
+ <mask-expr> = <logical-expr>
+ """
+ match = re.compile(r'where\s*\([^)]*\)\Z',re.I).match
+ end_stmt_cls = EndWhere
+ name = ''
+ def tostr(self):
+ return 'WHERE ( %s )' % (self.expr)
+ def process_item(self):
+ self.expr = self.item.get_line()[5:].lstrip()[1:-1].strip()
+ self.name = self.item.label
+ return BeginStatement.process_item(self)
+
+ def get_classes(self):
+ return [Assignment, WhereStmt,
+ WhereConstruct, ElseWhere
+ ]
+
+WhereConstruct = Where
+
# IfThen
class EndIfThen(EndStatement):
@@ -313,7 +351,7 @@ class If(BeginStatement):
if stmt.isvalid:
self.content.append(stmt)
return
- self.handle_unknown_item(newitem)
+ self.isvalid = False
return
def tostr(self):
@@ -387,6 +425,7 @@ class Type(BeginStatement):
"""
match = re.compile(r'type\b\s*').match
end_stmt_cls = EndType
+ is_name = re.compile(r'\w+\Z').match
def process_item(self):
line = self.item.get_line()[4:].lstrip()
@@ -409,6 +448,9 @@ class Type(BeginStatement):
else:
self.name = line
self.params = ''
+ if not self.is_name(self.name):
+ self.isvalid = False
+ return
return BeginStatement.process_item(self)
def tostr(self):
@@ -443,14 +485,17 @@ module_subprogram_part = [
]
specification_stmt = [
- # Access, Allocatable, Asynchronous, Bind, Common,
+ # Access, Allocatable, Asynchronous, Bind,
+ Common,
Data, Dimension,
- Equivalence, #External, Intent
- # Intrinsic, Namelist, Optional, Pointer, Protected,
+ Equivalence, External, #Intent
+ Intrinsic,
+ #Namelist,
+ Optional, #Pointer, Protected,
Save, #Target, Volatile, Value
]
intrinsic_type_spec = [
- Integer , Real, DoublePrecision, Complex, Character, Logical
+ Integer , Real, DoublePrecision, Complex, DoubleComplex, Character, Logical
]
declaration_type_spec = intrinsic_type_spec + [
TypeStmt,
@@ -459,7 +504,7 @@ declaration_type_spec = intrinsic_type_spec + [
type_declaration_stmt = declaration_type_spec
private_or_sequence = [
- Private, #Sequence
+ Private, Sequence
]
component_part = declaration_type_spec + [
@@ -483,24 +528,26 @@ action_stmt = [
Endfile, #EndFunction, EndProgram, EndSubroutine,
Exit,
# Flush, Forall,
- Goto, If, #Inquire,
+ Goto, If, Inquire,
Nullify,
Open,
Print, Read,
Return,
Rewind,
- Stop, #Wait, Where,
+ Stop, #Wait,
+ WhereStmt,
Write,
- # arithmetic-if-stmt, computed-goto-stmt
+ ArithmeticIf,
+ ComputedGoto
]
-executable_construct = action_stmt + [
+executable_construct = [
# Associate, Case,
Do,
# Forall,
IfThen,
- Select, #Where
- ]
+ Select, WhereConstruct
+ ] + action_stmt
execution_part_construct = executable_construct + [
Format, #Entry, Data
]
diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py
index 71355a9ad..21eec49fe 100644
--- a/numpy/f2py/lib/parsefortran.py
+++ b/numpy/f2py/lib/parsefortran.py
@@ -42,10 +42,13 @@ class FortranParser:
except KeyboardInterrupt:
raise
except:
- message = self.reader.format_message('FATAL ERROR',
- 'while processing line',
- self.reader.linecount, self.reader.linecount)
- self.reader.show_message(message, sys.stdout)
+ reader = self.reader
+ while reader is not None:
+ message = reader.format_message('FATAL ERROR',
+ 'while processing line',
+ reader.linecount, reader.linecount)
+ reader.show_message(message, sys.stdout)
+ reader = reader.reader
traceback.print_exc(file=sys.stdout)
self.reader.show_message(red_text('STOPPED PARSING'), sys.stdout)
diff --git a/numpy/f2py/lib/readfortran.py b/numpy/f2py/lib/readfortran.py
index 1d6335865..26bfa1b0b 100644
--- a/numpy/f2py/lib/readfortran.py
+++ b/numpy/f2py/lib/readfortran.py
@@ -21,6 +21,7 @@ __all__ = ['FortranFileReader',
]
import re
+import os
import sys
import tempfile
import traceback
@@ -35,6 +36,7 @@ _cf2py_re = re.compile(r'(?P<indent>\s*)!f2py(?P<rest>.*)',re.I)
_is_fix_cont = lambda line: line and len(line)>5 and line[5]!=' ' and line[:5]==5*' '
_is_f90_cont = lambda line: line and '&' in line and line.rstrip()[-1]=='&'
_f90label_re = re.compile(r'\s*(?P<label>(\w+\s*:|\d+))\s*(\b|(?=&)|\Z)',re.I)
+_is_include_line = re.compile(r'\s*include\s*"[^"]+"\s*\Z',re.I).match
class FortranReaderError: # TODO: may be derive it from Exception
def __init__(self, message):
@@ -45,6 +47,9 @@ class FortranReaderError: # TODO: may be derive it from Exception
class Line:
""" Holds a Fortran source line.
"""
+
+ f2py_strmap_findall = re.compile(r'( _F2PY_STRING_CONSTANT_\d+_ |\(F2PY_EXPR_TUPLE_\d+\))').findall
+
def __init__(self, line, linenospan, label, reader):
self.line = line.strip()
self.span = linenospan
@@ -55,16 +60,11 @@ class Line:
if line is None:
line = self.line
if apply_map and hasattr(self,'strlinemap'):
+ findall = self.f2py_strmap_findall
str_map = self.strlinemap
- keys = str_map.keys()
- flag = True
- while flag:
- flag = False
- for k in keys:
- if k in line:
- flag = True
- line = line.replace(k, str_map[k])
- assert k not in line, `k,line`
+ keys = findall(line)
+ for k in keys:
+ line = line.replace(k, str_map[k])
return Line(line, self.span, self.label, self.reader)
def __repr__(self):
return self.__class__.__name__+'(%r,%s,%r)' \
@@ -139,6 +139,7 @@ class FortranReaderBase:
self.ispyf = isfree and isstrict
self.isfree = isfree
self.isfix = not isfree
+ self.isstrict = isstrict
if self.isfree90: mode = 'free90'
elif self.isfix90: mode = 'fix90'
@@ -156,6 +157,10 @@ class FortranReaderBase:
self.name = '%s mode=%s' % (source, mode)
+ self.reader = None
+ self.include_dirs = ['.']
+ return
+
def close_source(self):
# called when self.source.next() raises StopIteration.
pass
@@ -184,7 +189,9 @@ class FortranReaderBase:
self.linecount += 1
# expand tabs, replace special symbols, get rid of nl characters
line = line.expandtabs().replace('\xa0',' ').rstrip('\n\r\f')
- self.source_lines.append(line)
+ self.source_lines.append(line)
+ if not line:
+ return self.get_single_line()
return line
def get_next_line(self):
@@ -199,8 +206,36 @@ class FortranReaderBase:
return self
def next(self, ignore_comments = False):
+
try:
- return self._next(ignore_comments)
+ if self.reader is not None:
+ try:
+ return self.reader.next()
+ except StopIteration:
+ self.reader = None
+ item = self._next(ignore_comments)
+ if isinstance(item, Line) and _is_include_line(item.line):
+ filename = item.line.strip()[7:].lstrip()[1:-1]
+ include_dirs = self.include_dirs[:]
+ path = filename
+ for incl_dir in include_dirs:
+ path = os.path.join(incl_dir, filename)
+ if os.path.exists(path):
+ break
+ if not os.path.isfile(path):
+ dirs = os.pathsep.join(include_dirs)
+ message = self.format_message('WARNING',
+ 'include file not found in %s, ignoring.' % (dirs),
+ self.linecount, self.linecount)
+ self.show_message(message, sys.stdout)
+ return item
+ message = self.format_message('INFORMATION',
+ 'found file %r' % (path),
+ self.linecount, self.linecount)
+ self.show_message(message, sys.stdout)
+ self.reader = FortranFileReader(path, include_dirs = include_dirs)
+ return self.reader.next()
+ return item
except StopIteration:
raise
except:
@@ -577,10 +612,16 @@ class FortranReaderBase:
class FortranFileReader(FortranReaderBase):
- def __init__(self, filename):
+ def __init__(self, filename,
+ include_dirs = None):
isfree, isstrict = get_source_info(filename)
self.file = open(filename,'r')
FortranReaderBase.__init__(self, self.file, isfree, isstrict)
+ if include_dirs is None:
+ self.include_dirs.insert(0, os.path.dirname(filename))
+ else:
+ self.include_dirs = include_dirs[:]
+ return
def close_source(self):
self.file.close()
@@ -638,6 +679,7 @@ python module foo
endif
end interface
if ( pc_get_lun() .ne. 6) &
+
write ( pc_get_lun(), '( &
& /, a, /, " p=", i4, " stopping c_flag=", a, &
& /, " print unit=", i8)') &
@@ -689,7 +731,7 @@ def profile_main():
stats.print_stats(30)
if __name__ == "__main__":
- test_pyf()
+ #test_pyf()
#test_fix90()
#profile_main()
- #simple_main()
+ simple_main()
diff --git a/numpy/f2py/lib/splitline.py b/numpy/f2py/lib/splitline.py
index be45ced2c..c5d6869b0 100644
--- a/numpy/f2py/lib/splitline.py
+++ b/numpy/f2py/lib/splitline.py
@@ -15,6 +15,8 @@ Pearu Peterson
__all__ = ['String','string_replace_map','splitquote','splitparen']
+import re
+
class String(str): pass
class ParenString(str): pass
@@ -26,6 +28,8 @@ def split2(line, lower=False):
"""
return LineSplitter(line,lower=lower).split2()
+_f2py_str_findall = re.compile(r' _F2PY_STRING_CONSTANT_\d+_ ').findall
+
def string_replace_map(line, lower=False,
_cache={'index':0,'pindex':0}):
"""
@@ -50,8 +54,9 @@ def string_replace_map(line, lower=False,
items.append(item)
newline = ''.join(items)
items = []
+ expr_keys = []
for item in splitparen(newline):
- if isinstance(item,ParenString):
+ if isinstance(item, ParenString):
key = rev_string_map.get(item)
if key is None:
_cache['pindex'] += 1
@@ -59,9 +64,21 @@ def string_replace_map(line, lower=False,
key = '(F2PY_EXPR_TUPLE_%s)' % (index)
string_map[key] = item
rev_string_map[item] = key
+ expr_keys.append(key)
items.append(key)
else:
items.append(item)
+ found_keys = set()
+ for k in expr_keys:
+ v = string_map[k]
+ l = _f2py_str_findall(v)
+ if l:
+ found_keys = found_keys.union(l)
+ for k1 in l:
+ v = v.replace(k1, string_map[k1])
+ string_map[k] = v
+ for k in found_keys:
+ del string_map[k]
return ''.join(items), string_map
def splitquote(line, stopchar=None, lower=False, quotechars = '"\''):
diff --git a/numpy/f2py/lib/statements.py b/numpy/f2py/lib/statements.py
index 09b60d328..803493aed 100644
--- a/numpy/f2py/lib/statements.py
+++ b/numpy/f2py/lib/statements.py
@@ -12,8 +12,10 @@ class Assignment(Statement):
<pointer variable> => <expr>
"""
- match = re.compile(r'\w(\s*\(\s*[^)]*\)|[\w%]*)*\s*=\>?',re.I).match
- item_re = re.compile(r'(?P<variable>\w(\s*\(\s*[^)]*\)|[\w%]*)*)\s*(?P<sign>=\>?)\s*(?P<expr>.*)\Z',re.I).match
+ #match = re.compile(r'\w(\s*\(\s*[^)]*\)|[\w%]*)*\s*=\>?',re.I).match
+ #item_re = re.compile(r'(?P<variable>\w(\s*\(\s*[^)]*\)|[\w%]*)*)\s*(?P<sign>=\>?)\s*(?P<expr>.*)\Z',re.I).match
+ match = re.compile(r'\w[^=]*\s*=\>?').match
+ item_re = re.compile(r'(?P<variable>\w[^=]*)\s*(?P<sign>=\>?)\s*(?P<expr>.*)\Z',re.I).match
def process_item(self):
m = self.item_re(self.item.get_line())
@@ -62,15 +64,32 @@ class Goto(Statement):
GO TO <label>
"""
- match = re.compile(r'go\s*to\b\s*\w*\Z', re.I).match
+ match = re.compile(r'go\s*to\b\s*\w*\s*\Z', re.I).match
def process_item(self):
- self.gotolabel = self.item.get_line()[2:].strip()[2:].strip()
+ self.gotolabel = self.item.get_line()[2:].lstrip()[2:].lstrip()
return
def __str__(self):
return self.get_indent_tab() + 'GO TO %s' % (self.gotolabel)
-
+
+class ComputedGoto(Statement):
+ """
+ GO TO ( <label-list> ) [ , ] <scalar-int-expr>
+ """
+ match = re.compile(r'go\s*to\s*\(',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[2:].lstrip()[2:].lstrip()
+ i = line.index(')')
+ self.items = [s.strip() for s in line[1:i].strip(',')]
+ self.expr = line[i+1:].lstrip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'GO TO (%s) %s' \
+ % (', '.join(self.items), self.expr)
+
+
+
class Continue(Statement):
"""
CONTINUE
@@ -103,7 +122,7 @@ class Stop(Statement):
"""
STOP [stop-code]
"""
- match = re.compile(r'stop\b\s*\w*\Z',re.I).match
+ match = re.compile(r'stop\b\s*\w*\s*\Z',re.I).match
def process_item(self):
self.stopcode = self.item.get_line()[4:].lstrip()
@@ -279,7 +298,7 @@ class Cycle(Statement):
"""
CYCLE [ <do-construct-name> ]
"""
- match = re.compile(r'cycle\b\s*\w*\Z',re.I).match
+ match = re.compile(r'cycle\b\s*\w*\s*\Z',re.I).match
def process_item(self):
self.name = self.item.get_line()[5:].lstrip()
return
@@ -424,16 +443,18 @@ class Data(Statement):
def process_item(self):
line = self.item.get_line()[4:].lstrip()
stmts = []
+ self.isvalid = False
while line:
i = line.find('/')
- assert i!=-1,`line`
+ if i==-1: return
j = line.find('/',i+1)
- assert j!=-1,`line`
+ if j==-1: return
stmts.append((line[:i].rstrip(),line[i+1:j].strip()))
line = line[j+1:].lstrip()
if line.startswith(','):
line = line[1:].lstrip()
self.stmts = stmts
+ self.isvalid = True
return
def __str__(self):
@@ -507,7 +528,7 @@ class Exit(Statement):
"""
EXIT [ <do-construct-name> ]
"""
- match = re.compile(r'exit\b\s*\w*\Z',re.I).match
+ match = re.compile(r'exit\b\s*\w*\s*\Z',re.I).match
def process_item(self):
self.exitname = self.item.get_line()[4:].lstrip()
return
@@ -558,13 +579,143 @@ class Dimension(Statement):
def __str__(self):
return self.get_indent_tab() + 'DIMENSION %s' % (', '.join(self.items))
+class ArithmeticIf(Statement):
+ """
+ IF ( <scalar-numeric-expr> ) <label> , <label> , <label>
+ """
+ match = re.compile(r'if\s*\(.*\)\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\Z', re.I).match
+ def process_item(self):
+ line = self.item.get_line()[2:].lstrip()
+ line,l2,l3 = line.rsplit(',',2)
+ i = line.rindex(')')
+ l1 = line[i+1:]
+ self.expr = line[1:i].strip()
+ self.labels = [l1.strip(),l2.strip(),l3.strip()]
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'IF (%s) %s' \
+ % (self.expr,', '.join(self.labels))
+
+class Intrinsic(Statement):
+ """
+ INTRINSIC [ :: ] <intrinsic-procedure-name-list>
+ """
+ match = re.compile(r'intrinsic\b',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[10:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.items = [s.strip() for s in line.split(',')]
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'INTRINSIC ' + ', '.join(self.items)
+
+class Inquire(Statement):
+ """
+ INQUIRE ( <inquire-spec-list> )
+ INQUIRE ( IOLENGTH = <scalar-int-variable> ) <output-item-list>
+
+ <inquire-spec> = [ UNIT = ] <file-unit-number>
+ | FILE = <file-name-expr>
+ ...
+ <output-item> = <expr>
+ | <io-implied-do>
+ """
+ match = re.compile(r'inquire\s*\(',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[7:].lstrip()
+ i = line.index(')')
+ self.specs = line[1:i].strip()
+ self.items = line[i+1:].lstrip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'INQUIRE (%s) %s' % (self.specs, self.items)
+
+class Sequence(Statement):
+ """
+ SEQUENCE
+ """
+ match = re.compile(r'sequence\Z',re.I).match
+ def process_item(self):
+ return
+ def __str__(self): return self.get_indent_tab() + 'SEQUENCE'
+
+class External(Statement):
+ """
+ EXTERNAL [ :: ] <external-name-list>
+ """
+ match = re.compile(r'external\b').match
+ def process_item(self):
+ line = self.item.get_line()[8:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.items = [s.strip() for s in line.split(',')]
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'EXTERNAL ' + ', '.join(self.items)
+
+class Common(Statement):
+ """
+ COMMON [ / [ <common-block-name> ] / ] <common-block-object-list> \
+ [ [ , ] / [ <common-block-name> ] / <common-block-object-list> ]...
+ <common-block-object> = <variable-name> [ ( <explicit-shape-spec-list> ) ]
+ | <proc-pointer-name>
+ """
+ match = re.compile(r'common\b',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[6:].lstrip()
+ items = []
+ while line:
+ if not line.startswith('/'):
+ name = ''
+ assert not items,`line`
+ else:
+ i = line.find('/',1)
+ assert i!=-1,`line`
+ name = line[:i+1]
+ line = line[i+1:].lstrip()
+ i = line.find('/')
+ if i==-1:
+ items.append((name,line))
+ line = ''
+ continue
+ s = line[:i].rstrip()
+ if s.endswith(','):
+ s = s[:-1].rstrip()
+ items.append((name,s))
+ line = line[i+1:].lstrip()
+ self.items = items
+ return
+ def __str__(self):
+ l = []
+ for name,s in self.items:
+ l.append('%s %s' % (name,s))
+ tab = self.get_indent_tab()
+ return tab + 'COMMON ' + ', '.join(l)
+
+class Optional(Statement):
+ """
+ OPTIONAL [ :: ] <dummy-arg-name-list>
+ <dummy-arg-name> = <name>
+ """
+ match = re.compile(r'optional\b',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[8:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.items = [s.split() for s in line.split(',')]
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'OPTIONAL ' + ', '.join(self.items)
+
# IF construct statements
class Else(Statement):
"""
ELSE [<if-construct-name>]
"""
- match = re.compile(r'else\s*\w*\Z',re.I).match
+ match = re.compile(r'else\b\s*\w*\s*\Z',re.I).match
def process_item(self):
item = self.item
@@ -586,7 +737,7 @@ class ElseIf(Statement):
"""
ELSE IF ( <scalar-logical-expr> ) THEN [<if-construct-name>]
"""
- match = re.compile(r'else\s*if\s*\(.*\)\s*then\s*\w*\Z',re.I).match
+ match = re.compile(r'else\s*if\s*\(.*\)\s*then\s*\w*\s*\Z',re.I).match
def process_item(self):
item = self.item
@@ -643,3 +794,61 @@ class Case(Statement):
print >> sys.stderr, message
self.isvalid = False
return
+
+# Where construct statements
+
+class Where(Statement):
+ """
+ WHERE ( <mask-expr> ) <where-assignment-stmt>
+ """
+ match = re.compile(r'where\s*\(.*\)\s*\w.*\Z',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[5:].lstrip()
+ i = line.index(')')
+ self.expr = line[1:i].strip()
+ line = line[i+1:].lstrip()
+ newitem = self.item.copy(line)
+ cls = Assignment
+ if cls.match(line):
+ stmt = cls(self, newitem)
+ if stmt.isvalid:
+ self.content = [stmt]
+ return
+ self.isvalid = False
+ return
+ def __str__(self):
+ tab = self.get_indent_tab()
+ return tab + 'WHERE (%s) %s' % (self.expr, self.content[0])
+
+WhereStmt = Where
+
+class ElseWhere(Statement):
+ """
+ ELSEWHERE ( <mask-expr> ) [ <where-construct-name> ]
+ ELSEWHERE [ <where-construct-name> ]
+ """
+ match = re.compile(r'else\s*where\b').match
+ def process_item(self):
+ line = self.item.get_line()[4:].lstrip()[5:].lstrip()
+ self.expr = None
+ if line.startswith('('):
+ i = line.index(')')
+ assert i != -1,`line`
+ self.expr = line[1:i].strip()
+ line = line[i+1:].lstrip()
+ self.name = line
+ if self.name and not self.name==self.parent.name:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'expected where-construct-name %r but got %r, skipping.'\
+ % (self.parent.name, self.name),
+ self.item.span[0],self.item.span[1])
+ print >> sys.stderr, message
+ self.isvalid = False
+ return
+
+ def __str__(self):
+ tab = self.get_indent_tab()
+ if self.expr is None:
+ return tab + 'ELSEWHERE ' + self.name
+ return tab + 'ELSEWHERE (%s) ' % (self.expr) + self.name
diff --git a/numpy/f2py/lib/typedecl_statements.py b/numpy/f2py/lib/typedecl_statements.py
index 66e162100..ee9d96b98 100644
--- a/numpy/f2py/lib/typedecl_statements.py
+++ b/numpy/f2py/lib/typedecl_statements.py
@@ -82,15 +82,16 @@ class TypeDeclarationStatement(Statement):
selector += line[:i+1].rstrip()
line = line[i+1:].lstrip()
else:
- i = line.find(',')
- if i!=-1:
- selector += line[:i].rstrip()
- line = line[i+1:].lstrip()
- else:
- i = line.find('::')
- assert i!=-1,`line`
- selector += line[:i].rstrip()
- line = line[i+2:].lstrip()
+ i = len(line)
+ ci = ''
+ for c in [',','::',' ']:
+ j = line.find(c)
+ if j!=-1 and j<i:
+ i = j
+ ci = c
+ assert i!=len(line),`i,line`
+ selector += line[:i].rstrip()
+ line = line[i+len(ci):].lstrip()
else:
selector = ''
if line.startswith(','):
@@ -98,7 +99,6 @@ class TypeDeclarationStatement(Statement):
self.raw_selector = selector
i = line.find('::')
-
if i==-1:
self.attrspec = ''
self.entity_decls = line
@@ -125,6 +125,10 @@ class DoublePrecision(TypeDeclarationStatement):
class Complex(TypeDeclarationStatement):
match = re.compile(r'complex\b',re.I).match
+class DoubleComplex(TypeDeclarationStatement):
+ match = re.compile(r'double\s*complex\b',re.I).match
+ modes = ['pyf','fix77']
+
class Logical(TypeDeclarationStatement):
match = re.compile(r'logical\b',re.I).match