summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2006-07-04 12:12:47 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2006-07-04 12:12:47 +0000
commita8672c2c5e1fe4ae0c51805aa1eed5d736a5eedf (patch)
treeb081bf1ae86d4b0f734157e2e7810c8fb43568b0 /numpy
parent17d8921d6d37745e01601fc19497ae2b4029b10c (diff)
downloadnumpy-a8672c2c5e1fe4ae0c51805aa1eed5d736a5eedf.tar.gz
Working on Fortran analyzer.
Diffstat (limited to 'numpy')
-rw-r--r--numpy/f2py/lib/base_classes.py177
-rw-r--r--numpy/f2py/lib/block_statements.py215
-rw-r--r--numpy/f2py/lib/parsefortran.py18
-rw-r--r--numpy/f2py/lib/research/rat/rational.f906
-rw-r--r--numpy/f2py/lib/research/rat/wrap.f905
-rw-r--r--numpy/f2py/lib/splitline.py2
-rw-r--r--numpy/f2py/lib/statements.py163
-rw-r--r--numpy/f2py/lib/test_parser.py63
-rw-r--r--numpy/f2py/lib/typedecl_statements.py204
-rw-r--r--numpy/f2py/lib/utils.py121
10 files changed, 846 insertions, 128 deletions
diff --git a/numpy/f2py/lib/base_classes.py b/numpy/f2py/lib/base_classes.py
index cdae17f03..21aa63b8e 100644
--- a/numpy/f2py/lib/base_classes.py
+++ b/numpy/f2py/lib/base_classes.py
@@ -3,8 +3,155 @@ __all__ = ['Statement','BeginStatement','EndStatement']
import re
import sys
+import copy
from readfortran import Line
+from utils import split_comma, specs_split_comma
+class AttributeHolder:
+ # copied from symbolic.base module
+ """
+ Defines a object with predefined attributes. Only those attributes
+ are allowed that are specified as keyword arguments of a constructor.
+ When an argument is callable then the corresponding attribute will
+ be read-only and set by the value the callable object returns.
+ """
+ def __init__(self, **kws):
+ self._attributes = {}
+ self._readonly = []
+ for k,v in kws.items():
+ self._attributes[k] = v
+ if callable(v):
+ self._readonly.append(k)
+ return
+
+ def __getattr__(self, name):
+ if name not in self._attributes:
+ raise AttributeError,'%s instance has no attribute %r, '\
+ 'expected attributes: %s' \
+ % (self.__class__.__name__,name,
+ ','.join(self._attributes.keys()))
+ value = self._attributes[name]
+ if callable(value):
+ value = value()
+ self._attributes[name] = value
+ return value
+
+ def __setattr__(self, name, value):
+ if name in ['_attributes','_readonly']:
+ self.__dict__[name] = value
+ return
+ if name in self._readonly:
+ raise AttributeError,'%s instance attribute %r is readonly' \
+ % (self.__class__.__name__, name)
+ if name not in self._attributes:
+ raise AttributeError,'%s instance has no attribute %r, '\
+ 'expected attributes: %s' \
+ % (self.__class__.__name__,name,','.join(self._attributes.keys()))
+ self._attributes[name] = value
+
+ def __repr__(self):
+ l = []
+ for k in self._attributes.keys():
+ v = getattr(self,k)
+ l.append('%s=%r' % (k,v))
+ return '%s(%s)' % (self.__class__.__name__,', '.join(l))
+
+ def todict(self):
+ d = {}
+ for k in self._attributes.keys():
+ v = getattr(self, k)
+ d[k] = v
+ return d
+
+def get_base_classes(cls):
+ bases = ()
+ for c in cls.__bases__:
+ bases += get_base_classes(c)
+ return bases + cls.__bases__ + (cls,)
+
+class Variable:
+ """
+ Variable instance has attributes:
+ name
+ typedecl
+ dimension
+ attributes
+ intent
+ parent - Statement instances defining the variable
+ """
+ def __init__(self, parent, name):
+ self.parent = parent
+ self.name = name
+ self.typedecl = None
+ self.dimension = None
+ self.attributes = []
+ self.intent = None
+ self.bind = []
+ self.check = []
+ return
+
+ def set_type(self, typedecl):
+ if self.typedecl is not None:
+ if not self.typedecl==typedecl:
+ message = 'Warning: variable %r already has type %s' \
+ % (self.name, self.typedecl.tostr())
+ message += '.. resetting to %s' % (typedecl.tostr())
+ self.parent.show_message(message)
+ self.typedecl = typedecl
+ return
+
+ def update(self, attrs):
+ attributes = self.attributes
+ for attr in attrs:
+ lattr = attr.lower()
+ uattr = attr.upper()
+ if lattr.startswith('dimension'):
+ assert self.dimension is None, `self.dimension,attr`
+ l = attr[9:].lstrip()
+ assert l[0]+l[-1]=='()',`l`
+ self.dimension = split_comma(l[1:-1].strip(), self.parent.item)
+ continue
+ if lattr.startswith('intent'):
+ l = attr[6:].lstrip()
+ assert l[0]+l[-1]=='()',`l`
+ self.intent = intent = []
+ for i in split_comma(l[1:-1].strip(), self.parent.item):
+ if i not in intent:
+ intent.append(i)
+ continue
+ if lattr.startswith('bind'):
+ l = attr[4:].lstrip()
+ assert l[0]+l[-1]=='()',`l`
+ self.bind = specs_split_comma(l[1:-1].strip(), self.parent.item)
+ continue
+ if lattr.startswith('check'):
+ l = attr[5:].lstrip()
+ assert l[0]+l[-1]=='()',`l`
+ self.check.extend(split_comma(l[1:-1].strip()), self.parent.item)
+ continue
+ if uattr not in attributes:
+ attributes.append(uattr)
+ return
+
+ def __str__(self):
+ s = ''
+ if self.typedecl is not None:
+ s += self.typedecl.tostr() + ' '
+ a = self.attributes[:]
+ if self.dimension is not None:
+ a.append('DIMENSION(%s)' % (', '.join(self.dimension)))
+ if self.intent is not None:
+ a.append('INTENT(%s)' % (', '.join(self.intent)))
+ if self.bind:
+ a.append('BIND(%s)' % (', '.join(self.bind)))
+ if self.check:
+ a.append('CHECK(%s)' % (', '.join(self.check)))
+ if a:
+ s += ', '.join(a) + ' :: '
+ return s + self.name
+
+class ProgramBlock:
+ pass
class Statement:
"""
@@ -18,6 +165,14 @@ class Statement:
def __init__(self, parent, item):
self.parent = parent
self.reader = parent.reader
+ self.top = getattr(parent,'top',None)
+ if isinstance(parent, ProgramBlock):
+ self.programblock = parent
+ elif isinstance(self, ProgramBlock):
+ self.programblock = self
+ elif hasattr(parent,'programblock'):
+ self.programblock = parent.programblock
+
self.item = item
# when a statement instance is constructed by error, set isvalid to False
@@ -25,8 +180,19 @@ class Statement:
# when a statement should be ignored, set ignore to True
self.ignore = False
+ # attribute a will hold analyze information.
+ a_dict = {}
+ for cls in get_base_classes(self.__class__):
+ if hasattr(cls,'a'):
+ a_dict.update(copy.deepcopy(cls.a.todict()))
+ self.a = AttributeHolder(**a_dict)
+ if hasattr(self.__class__,'a'):
+ assert self.a is not self.__class__.a
+
self.process_item()
+ return
+
def get_indent_tab(self,colon=None,deindent=False):
if self.reader.isfix:
tab = ' '*6
@@ -60,6 +226,10 @@ class Statement:
sys.stderr.flush()
return
+ def analyze(self):
+ self.show_message('nothing analyzed in %s' % (self.__class__.__name__))
+ return
+
class BeginStatement(Statement):
""" <blocktype> <name>
@@ -237,6 +407,10 @@ class BeginStatement(Statement):
#sys.exit()
return
+ def analyze(self):
+ for stmt in self.content:
+ stmt.analyze()
+ return
class EndStatement(Statement):
"""
@@ -274,6 +448,9 @@ class EndStatement(Statement):
self.isvalid = False
self.name = self.parent.name
+ def analyze(self):
+ return
+
def __str__(self):
return self.get_indent_tab()[:-2] + 'END %s %s'\
% (self.blocktype.upper(),self.name or '')
diff --git a/numpy/f2py/lib/block_statements.py b/numpy/f2py/lib/block_statements.py
index 804a5549e..5c72fb808 100644
--- a/numpy/f2py/lib/block_statements.py
+++ b/numpy/f2py/lib/block_statements.py
@@ -5,31 +5,115 @@
import re
import sys
-from base_classes import BeginStatement, EndStatement, Statement
+from base_classes import BeginStatement, EndStatement, Statement,\
+ AttributeHolder, ProgramBlock
from readfortran import Line
+from utils import filter_stmts, parse_bind, parse_result
+
+class HasImplicitStmt:
+
+ a = AttributeHolder(implicit_rules = None)
+
+ def get_type(self, name):
+ implicit_rules = self.a.implicit_rules
+ if implicit_rules=={}:
+ raise ValueError,'Implicit rules mapping is null'
+ l = name[0].lower()
+ if implicit_rules.has_key(l):
+ return implicit_rules[l]
+ # default rules
+ if l in 'ijklmn':
+ return implicit_rules['default_integer']
+ return implicit_rules['default_real']
+
+ def initialize(self):
+ implicit_rules = self.a.implicit_rules
+ if implicit_rules is not None:
+ return
+ self.a.implicit_rules = implicit_rules = {}
+ real = Real(self, self.item.copy('real'))
+ assert real.isvalid
+ integer = Integer(self, self.item.copy('integer'))
+ assert integer.isvalid
+ implicit_rules['default_real'] = real
+ implicit_rules['default_integer'] = integer
+ return
+
+class HasUseStmt:
+
+ a = AttributeHolder(use = {})
+
+ def get_entity(self, name):
+ for modname, modblock in self.top.a.module.items():
+ for stmt in modblock.content:
+ if getattr(stmt,'name','') == name:
+ return stmt
+ return
+
+ def initialize(self):
+
+ return
+
+class HasVariables:
+
+ a = AttributeHolder(variables = {})
+
+class HasTypeDecls:
+
+ a = AttributeHolder(type_decls = {})
+
+class HasExternal:
+
+ a = AttributeHolder(external = [])
+
+class HasAttributes:
+
+ a = AttributeHolder(attributes = [])
# File block
class EndSource(EndStatement):
"""
+ Dummy End statement for BeginSource.
"""
match = staticmethod(lambda s: False)
class BeginSource(BeginStatement):
"""
+ Fortran source content.
"""
match = staticmethod(lambda s: True)
-
end_stmt_cls = EndSource
+ a = AttributeHolder(module = {},
+ external_subprogram = {},
+ blockdata = {},
+ )
def tostr(self):
return '!' + self.blocktype.upper() + ' '+ self.name
def process_item(self):
self.name = self.reader.name
+ self.top = self
self.fill(end_flag = True)
return
+ def analyze(self):
+ for stmt in self.content:
+ if isinstance(stmt, Module):
+ stmt.analyze()
+ self.a.module[stmt.name] = stmt
+ elif isinstance(stmt, SubProgramStatement):
+ stmt.analyze()
+ self.a.external_subprogram[stmt.name] = stmt
+ elif isinstance(stmt, BlockData):
+ stmt.analyze()
+ self.a.blockdata[stmt.name] = stmt
+ else:
+ message = 'Unexpected statement %r in %r block. Ignoring.' \
+ % (stmt.__class__, self.__class__)
+ return
+
def get_classes(self):
return program_unit
@@ -58,7 +142,9 @@ class BeginSource(BeginStatement):
class EndModule(EndStatement):
match = re.compile(r'end(\s*module\s*\w*|)\Z', re.I).match
-class Module(BeginStatement):
+class Module(BeginStatement, HasAttributes,
+ HasImplicitStmt, HasUseStmt, HasVariables,
+ HasTypeDecls):
"""
MODULE <name>
..
@@ -66,6 +152,9 @@ class Module(BeginStatement):
"""
match = re.compile(r'module\s*\w+\Z', re.I).match
end_stmt_cls = EndModule
+ a = AttributeHolder(module_subprogram = {},
+ module_data = {},
+ )
def get_classes(self):
return access_spec + specification_part + module_subprogram_part
@@ -75,17 +164,37 @@ class Module(BeginStatement):
self.name = name
return BeginStatement.process_item(self)
- #def __str__(self):
- # s = self.get_indent_tab(deindent=True)
- # s += 'MODULE '+ self.name
- # return s
+ def analyze(self):
+ content = self.content[:]
+
+ [stmt.analyze() for stmt in filter_stmts(content, Use)]
+ HasUseStmt.initialize(self)
+
+ [stmt.analyze() for stmt in filter_stmts(content, Implicit)]
+ HasImplicitStmt.initialize(self)
+
+ while content:
+ stmt = content.pop(0)
+ if isinstance(stmt, Contains):
+ for stmt in filter_stmts(content, SubProgramStatement):
+ stmt.analyze()
+ self.a.module_subprogram[stmt.name] = stmt
+ stmt = content.pop(0)
+ assert isinstance(stmt, EndModule),`stmt`
+ continue
+ stmt.analyze()
+
+ if content:
+ print 'Not analyzed content:',content
+
+ return
# Python Module
class EndPythonModule(EndStatement):
match = re.compile(r'end(\s*python\s*module\s*\w*|)\Z', re.I).match
-class PythonModule(BeginStatement):
+class PythonModule(BeginStatement, HasImplicitStmt, HasUseStmt):
"""
PYTHON MODULE <name>
..
@@ -111,7 +220,8 @@ class EndProgram(EndStatement):
"""
match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
-class Program(BeginStatement):
+class Program(BeginStatement, ProgramBlock, HasAttributes,
+ HasImplicitStmt, HasUseStmt):
""" PROGRAM [name]
"""
match = re.compile(r'program\s*\w*\Z', re.I).match
@@ -137,7 +247,8 @@ class EndBlockData(EndStatement):
match = re.compile(r'end(\s*block\s*data\s*\w*|)\Z', re.I).match
blocktype = 'blockdata'
-class BlockData(BeginStatement):
+class BlockData(BeginStatement, HasImplicitStmt, HasUseStmt,
+ HasVariables):
"""
BLOCK DATA [ <block-data-name> ]
"""
@@ -157,7 +268,7 @@ class EndInterface(EndStatement):
match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match
blocktype = 'interface'
-class Interface(BeginStatement):
+class Interface(BeginStatement, HasImplicitStmt, HasUseStmt):
"""
INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
END INTERFACE [<generic-spec>]
@@ -198,10 +309,14 @@ class Interface(BeginStatement):
# Subroutine
-class SubProgramStatement(BeginStatement):
+class SubProgramStatement(BeginStatement, ProgramBlock,
+ HasImplicitStmt, HasAttributes,
+ HasUseStmt, HasVariables, HasTypeDecls,
+ HasExternal):
"""
[ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ]
"""
+ a = AttributeHolder(internal_subprogram = {})
def process_item(self):
clsname = self.__class__.__name__.lower()
@@ -223,7 +338,17 @@ class SubProgramStatement(BeginStatement):
if not a: continue
args.append(a)
line = line[i+1:].lstrip()
- self.suffix = item.apply_map(line)
+ suffix = item.apply_map(line)
+ self.bind, suffix = parse_bind(suffix, item)
+ self.result = None
+ if isinstance(self, Function):
+ self.result, suffix = parse_result(suffix, item)
+ if suffix:
+ assert self.bind is None,`self.bind`
+ self.bind, suffix = parse_result(suffix, item)
+ if self.result is None:
+ self.result = self.name
+ assert not suffix,`suffix`
self.args = args
self.typedecl = None
return BeginStatement.process_item(self)
@@ -237,12 +362,60 @@ class SubProgramStatement(BeginStatement):
assert isinstance(self, Function),`self.__class__.__name__`
s += self.typedecl.tostr() + ' '
s += clsname
- return '%s %s(%s) %s' % (s, self.name,', '.join(self.args),self.suffix)
+ suf = ''
+ if self.result and self.result!=self.name:
+ suf += ' RESULT ( %s )' % (self.result)
+ if self.bind:
+ suf += ' BIND ( %s )' % (', '.join(self.bind))
+ return '%s %s(%s)%s' % (s, self.name,', '.join(self.args),suf)
def get_classes(self):
return f2py_stmt + specification_part + execution_part \
+ internal_subprogram_part
+ def analyze(self):
+ content = self.content[:]
+
+ variables = self.a.variables
+ for a in self.args:
+ assert not variables.has_key(a)
+ assert is_name(a)
+ variables[a] = Variable(self, a)
+
+ if isinstance(self, Function):
+ variables[self.result] = Variable(self, self.result)
+
+ [stmt.analyze() for stmt in filter_stmts(content, Use)]
+ HasUseStmt.initialize(self)
+
+ [stmt.analyze() for stmt in filter_stmts(content, Implicit)]
+ HasImplicitStmt.initialize(self)
+
+ while content:
+ stmt = content.pop(0)
+ if isinstance(stmt, Contains):
+ for stmt in filter_stmts(content, SubProgramStatement):
+ stmt.analyze()
+ self.a.internal_subprogram[stmt.name] = stmt
+ stmt = content.pop(0)
+ assert isinstance(stmt, self.end_stmt_cls),`stmt`
+ elif isinstance(stmt, TypeDecl):
+ stmt.analyze()
+ self.a.type_declaration[stmt.name] = stmt
+ elif isinstance(stmt, self.end_stmt_cls):
+ continue
+ elif isinstance(stmt, External):
+ self.a.external.extend(stmt.items)
+ continue
+ elif isinstance(stmt, tuple(declaration_type_spec)):
+ stmt.analyze()
+ else:
+ stmt.analyze()
+ if content:
+ print 'Not analyzed content:',content
+
+ return
+
class EndSubroutine(EndStatement):
"""
END [SUBROUTINE [name]]
@@ -252,7 +425,7 @@ class EndSubroutine(EndStatement):
class Subroutine(SubProgramStatement):
"""
- [prefix] SUBROUTINE <name> [ ( [<dummy-arg-list>] ) [<proc-language-binding-spec>]]
+ [ <prefix> ] SUBROUTINE <name> [ ( [ <dummy-arg-list> ] ) [ <proc-language-binding-spec> ]]
"""
end_stmt_cls = EndSubroutine
match = re.compile(r'(recursive|pure|elemental|\s)*subroutine\s*\w+', re.I).match
@@ -271,6 +444,8 @@ class Function(SubProgramStatement):
<prefix> = <prefix-spec> [ <prefix-spec> ]...
<prefix-spec> = <declaration-type-spec>
| RECURSIVE | PURE | ELEMENTAL
+ <suffix> = <proc-language-binding-spec> [ RESULT ( <result-name> ) ]
+ | RESULT ( <result-name> ) [ <proc-language-binding-spec> ]
"""
end_stmt_cls = EndFunction
match = re.compile(r'(recursive|pure|elemental|\s)*function\s*\w+', re.I).match
@@ -292,7 +467,7 @@ class SubprogramPrefix(Statement):
self.item.clone(rest)
self.isvalid = False
return
- if self.parent.__class__ not in [Function,Subroutine]:
+ if self.parent.__class__ not in [Function, Subroutine]:
self.isvalid = False
return
prefix = prefix + ' ' + self.parent.prefix
@@ -558,7 +733,7 @@ class EndType(EndStatement):
match = re.compile(r'end\s*type\s*\w*\Z', re.I).match
blocktype = 'type'
-class Type(BeginStatement):
+class Type(BeginStatement, HasVariables, HasAttributes):
"""
TYPE [ [, <type-attr-spec-list>] ::] <type-name> [ ( <type-param-name-list> ) ]
<type-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> )
@@ -607,6 +782,12 @@ class Type(BeginStatement):
return [Integer] + private_or_sequence + component_part +\
type_bound_procedure_part
+ def analyze(self):
+ BeginStatement.analyze(self)
+ assert isinstance(self.parent,HasTypeDecls)
+ self.parent.a.type_decls[self.name] = self
+ return
+
TypeDecl = Type
# Enum
diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py
index 33a6eb112..314bbfa24 100644
--- a/numpy/f2py/lib/parsefortran.py
+++ b/numpy/f2py/lib/parsefortran.py
@@ -17,6 +17,7 @@ from numpy.distutils.misc_util import yellow_text, red_text
from readfortran import FortranFileReader, FortranStringReader
from block_statements import BeginSource
+from utils import AnalyzeError
class FortranParser:
@@ -37,7 +38,7 @@ class FortranParser:
def parse(self):
try:
- return BeginSource(self)
+ block = self.block = BeginSource(self)
except KeyboardInterrupt:
raise
except:
@@ -50,6 +51,16 @@ class FortranParser:
reader = reader.reader
traceback.print_exc(file=sys.stdout)
self.reader.show_message(red_text('STOPPED PARSING'), sys.stdout)
+ return
+ return
+
+ def analyze(self):
+ try:
+ self.block.analyze()
+ except AnalyzeError:
+ pass
+ except:
+ raise
return
def test_pyf():
@@ -123,8 +134,9 @@ def simple_main():
reader = FortranFileReader(filename)
print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode))
parser = FortranParser(reader)
- block = parser.parse()
- #print block
+ parser.parse()
+ parser.analyze()
+ #print parser.block
def profile_main():
import hotshot, hotshot.stats
diff --git a/numpy/f2py/lib/research/rat/rational.f90 b/numpy/f2py/lib/research/rat/rational.f90
index 7ae6d340a..9cbc57e15 100644
--- a/numpy/f2py/lib/research/rat/rational.f90
+++ b/numpy/f2py/lib/research/rat/rational.f90
@@ -41,8 +41,4 @@ module rational
end module rational
-subroutine init_f90_funcs(set_f90_funcs)
- use rational
- external set_f90_funcs
- call set_f90_funcs(4, rat_create, rat_show, rat_set, rat_add)
-end subroutine init_f90_funcs
+
diff --git a/numpy/f2py/lib/research/rat/wrap.f90 b/numpy/f2py/lib/research/rat/wrap.f90
new file mode 100644
index 000000000..6c9da8491
--- /dev/null
+++ b/numpy/f2py/lib/research/rat/wrap.f90
@@ -0,0 +1,5 @@
+subroutine init_f90_funcs(set_f90_funcs)
+ use rational
+ external set_f90_funcs
+ call set_f90_funcs(4, rat_create, rat_show, rat_set, rat_add)
+end subroutine init_f90_funcs
diff --git a/numpy/f2py/lib/splitline.py b/numpy/f2py/lib/splitline.py
index a1148a502..1bbd77b6e 100644
--- a/numpy/f2py/lib/splitline.py
+++ b/numpy/f2py/lib/splitline.py
@@ -65,7 +65,7 @@ def string_replace_map(line, lower=False,
_cache['pindex'] += 1
index = _cache['pindex']
key = 'F2PY_EXPR_TUPLE_%s' % (index)
- it = item[1:-1]
+ it = item[1:-1].strip()
string_map[key] = it
rev_string_map[it] = key
expr_keys.append(key)
diff --git a/numpy/f2py/lib/statements.py b/numpy/f2py/lib/statements.py
index 741b0a11f..5a24f2d84 100644
--- a/numpy/f2py/lib/statements.py
+++ b/numpy/f2py/lib/statements.py
@@ -2,40 +2,15 @@
import re
import sys
-from base_classes import Statement
+from base_classes import Statement, Variable
+from expression import Expression
# Auxiliary tools
-is_name = re.compile(r'\w+\Z').match
+from utils import split_comma, specs_split_comma, AnalyzeError, ParseError,\
+ get_module_file, parse_bind, parse_result
-def split_comma(line, item = None, comma=','):
- items = []
- if item is None:
- for s in line.split(comma):
- s = s.strip()
- if not s: continue
- items.append(s)
- return items
- newitem = item.copy(line, True)
- apply_map = newitem.apply_map
- for s in newitem.get_line().split(comma):
- s = apply_map(s).strip()
- if not s: continue
- items.append(s)
- return items
-
-def specs_split_comma(line, item):
- specs0 = split_comma(line, item)
- specs = []
- for spec in specs0:
- i = spec.find('=')
- if i!=-1:
- kw = spec[:i].strip().upper()
- v = spec[i+1:].strip()
- specs.append('%s = %s' % (kw, v))
- else:
- specs.append(spec)
- return specs
+is_name = re.compile(r'\w+\Z').match
class StatementWithNamelist(Statement):
"""
@@ -113,7 +88,7 @@ class Assign(Statement):
match = re.compile(r'assign\s*\d+\s*to\s*\w+\s*\Z',re.I).match
def process_item(self):
line = self.item.get_line()[6:].lstrip()
- i = line.find('to')
+ i = line.lower().find('to')
assert not self.item.has_map()
self.items = [line[:i].rstrip(),line[i+2:].lstrip()]
return
@@ -121,7 +96,6 @@ class Assign(Statement):
return self.get_indent_tab() + 'ASSIGN %s TO %s' \
% (self.items[0], self.items[1])
-
class Call(Statement):
"""Call statement class
CALL <procedure-designator> [ ( [ <actual-arg-spec-list> ] ) ]
@@ -172,6 +146,14 @@ class Call(Statement):
s += '('+', '.join(map(str,self.items))+ ')'
return s
+ def analyze(self):
+ a = self.programblock.a
+ if hasattr(a, 'external'):
+ external = a.external
+ if self.designator in external:
+ print 'Need to analyze:',self
+ return
+
class Goto(Statement):
"""
GO TO <label>
@@ -244,6 +226,7 @@ class Continue(Statement):
def __str__(self):
return self.get_indent_tab(deindent=True) + 'CONTINUE'
+ def analyze(self): return
class Return(Statement):
"""
@@ -261,6 +244,8 @@ class Return(Statement):
return tab + 'RETURN %s' % (self.expr)
return tab + 'RETURN'
+ def analyze(self): return
+
class Stop(Statement):
"""
STOP [ <stop-code> ]
@@ -278,6 +263,8 @@ class Stop(Statement):
return tab + 'STOP %s' % (self.code)
return tab + 'STOP'
+ def analyze(self): return
+
class Print(Statement):
"""
PRINT <format> [, <output-item-list>]
@@ -526,7 +513,7 @@ class Access(Statement):
def process_item(self):
clsname = self.__class__.__name__.lower()
line = self.item.get_line()
- if not line.startswith(clsname):
+ if not line.lower().startswith(clsname):
self.isvalid = False
return
line = line[len(clsname):].lstrip()
@@ -542,8 +529,23 @@ class Access(Statement):
return tab + clsname + ' ' + ', '.join(self.items)
return tab + clsname
-class Public(Access): pass
-class Private(Access): pass
+ def analyze(self):
+ clsname = self.__class__.__name__.upper()
+ if self.items:
+ variables = self.parent.a.variables
+ for n in self.items:
+ if not variables.has_key(n):
+ variables[n] = Variable(self, n)
+ var = variables[n]
+ var.update([clsname])
+ else:
+ self.parent.a.attributes.append(clsname)
+ return
+
+class Public(Access):
+ is_public = True
+class Private(Access):
+ is_public = False
class Close(Statement):
"""
@@ -591,7 +593,7 @@ class FilePositioningStatement(Statement):
def process_item(self):
clsname = self.__class__.__name__.lower()
line = self.item.get_line()
- if not line.startswith(clsname):
+ if not line.lower().startswith(clsname):
self.isvalid = False
return
line = line[len(clsname):].lstrip()
@@ -799,7 +801,7 @@ class Use(Statement):
else:
self.name = line[:i].rstrip()
line = line[i+1:].lstrip()
- if line.startswith('only') and line[4:].lstrip().startswith(':'):
+ if line.lower().startswith('only') and line[4:].lstrip().startswith(':'):
self.isonly = True
line = line[4:].lstrip()[1:].lstrip()
self.items = split_comma(line, self.item)
@@ -819,6 +821,39 @@ class Use(Statement):
s += ' ' + ', '.join(self.items)
return tab + s
+ def analyze(self):
+ modules = self.top.a.module
+
+ if not modules.has_key(self.name):
+ fn = None
+ for d in self.reader.include_dirs:
+ fn = get_module_file(self.name, d)
+ if fn is not None:
+ break
+
+ if fn is not None:
+ from readfortran import FortranFileReader
+ from parsefortran import FortranParser
+ self.show_message('Processing %r (parent file=%r)' % (fn, self.reader.name))
+ reader = FortranFileReader(fn)
+ parser = FortranParser(reader)
+ parser.parse()
+ parser.block.a.module.update(modules)
+ parser.analyze()
+ modules.update(parser.block.a.module)
+
+ if not modules.has_key(self.name):
+ message = self.reader.format_message(\
+ 'ERROR',
+ 'No information about the use module %r.' \
+ % (self.name),
+ self.item.span[0],self.item.span[1])
+ self.show_message(message)
+ raise AnalyzeError
+ return
+
+ return
+
class Exit(Statement):
"""
EXIT [ <do-construct-name> ]
@@ -869,7 +904,7 @@ class Dimension(Statement):
DIMENSION [ :: ] <array-name> ( <array-spec> ) [ , <array-name> ( <array-spec> ) ]...
"""
- match = re.compile(r'dimension\b').match
+ match = re.compile(r'dimension\b', re.I).match
def process_item(self):
line = self.item.get_line()[9:].lstrip()
if line.startswith('::'):
@@ -884,7 +919,7 @@ class Target(Statement):
TARGET [ :: ] <object-name> ( <array-spec> ) [ , <object-name> ( <array-spec> ) ]...
"""
- match = re.compile(r'target\b').match
+ match = re.compile(r'target\b', re.I).match
def process_item(self):
line = self.item.get_line()[6:].lstrip()
if line.startswith('::'):
@@ -992,7 +1027,7 @@ class External(StatementWithNamelist):
"""
EXTERNAL [ :: ] <external-name-list>
"""
- match = re.compile(r'external\b').match
+ match = re.compile(r'external\b', re.I).match
class Namelist(Statement):
"""
@@ -1129,33 +1164,14 @@ class Entry(Statement):
line = line[i+1:].lstrip()
else:
items = []
- binds = []
- result = ''
- if line.startswith('bind'):
- line = line[4:].lstrip()
- i = line.find(')')
- assert line.startswith('(') and i != -1,`line`
- binds = split_comma(line[1:i], self.item)
- line = line[i+1:].lstrip()
- if line.startswith('result'):
- line = line[6:].lstrip()
- i = line.find(')')
- assert line.startswith('(') and i != -1,`line`
- result = line[1:i].strip()
- assert is_name(result),`result,line`
- line = line[i+1:].lstrip()
- if line.startswith('bind'):
- assert not binds
- line = line[4:].lstrip()
- i = line.find(')')
- assert line.startswith('(') and i != -1,`line`
- binds = split_comma(line[1:i], self.item)
- line = line[i+1:].lstrip()
+ self.bind, line = parse_bind(line, self.item)
+ self.result, line = parse_result(line, self.item)
+ if line:
+ assert self.bind is None,`self.bind`
+ self.bind, line = parse_bind(line, self.item)
assert not line,`line`
self.name = name
self.items = items
- self.result = result
- self.binds = binds
return
def __str__(self):
tab = self.get_indent_tab()
@@ -1164,8 +1180,8 @@ class Entry(Statement):
s += ' (%s)' % (', '.join(self.items))
if self.result:
s += ' RESULT (%s)' % (self.result)
- if self.binds:
- s += ' BIND (%s)' % (', '.join(self.binds))
+ if self.bind:
+ s += ' BIND (%s)' % (', '.join(self.bind))
return s
class Import(StatementWithNamelist):
@@ -1359,15 +1375,8 @@ class Bind(Statement):
"""
match = re.compile(r'bind\s*\(.*\)',re.I).match
def process_item(self):
- line = self.item.get_line()[4:].lstrip()
- specs = []
- for spec in specs_split_comma(line[1:line.index(')')].strip(), self.item):
- if is_name(spec):
- specs.append(spec.upper())
- else:
- specs.append(spec)
- self.specs = specs
- line = line[line.index(')')+1:].lstrip()
+ line = self.item.line
+ self.specs, line = parse_bind(line, self.item)
if line.startswith('::'):
line = line[2:].lstrip()
items = []
@@ -1461,7 +1470,7 @@ class Case(Statement):
items = split_comma(line[1:i].strip(), self.item)
line = line[i+1:].lstrip()
else:
- assert line.startswith('default'),`line`
+ assert line.lower().startswith('default'),`line`
items = []
line = line[7:].lstrip()
for i in range(len(items)):
@@ -1530,7 +1539,7 @@ class ElseWhere(Statement):
ELSE WHERE ( <mask-expr> ) [ <where-construct-name> ]
ELSE WHERE [ <where-construct-name> ]
"""
- match = re.compile(r'else\s*where\b').match
+ match = re.compile(r'else\s*where\b',re.I).match
def process_item(self):
line = self.item.get_line()[4:].lstrip()[5:].lstrip()
self.expr = None
diff --git a/numpy/f2py/lib/test_parser.py b/numpy/f2py/lib/test_parser.py
index 47b20b652..af54efdf2 100644
--- a/numpy/f2py/lib/test_parser.py
+++ b/numpy/f2py/lib/test_parser.py
@@ -14,7 +14,12 @@ def parse(cls, line, label='',
raise ValueError, '%r does not match %s pattern' % (line, cls.__name__)
stmt = cls(item, item)
if stmt.isvalid:
- return str(stmt)
+ r = str(stmt)
+ if not isstrict:
+ r1 = parse(cls, r, isstrict=True)
+ if r != r1:
+ raise ValueError, 'Failed to parse %r with %s pattern in pyf mode, got %r' % (r, cls.__name__, r1)
+ return r
raise ValueError, 'parsing %r with %s pattern failed' % (line, cls.__name__)
class test_Statements(NumpyTestCase):
@@ -107,7 +112,7 @@ class test_Statements(NumpyTestCase):
'allocate (a, stat=b)'), 'ALLOCATE (a, STAT = b)')
assert_equal(parse(Allocate, 'allocate (a,b(:1))'), 'ALLOCATE (a, b(:1))')
assert_equal(parse(Allocate, \
- 'allocate (real(8)::a)'), 'ALLOCATE (REAL(8) :: a)')
+ 'allocate (real(8)::a)'), 'ALLOCATE (REAL(KIND=8) :: a)')
def check_deallocate(self):
assert_equal(parse(Deallocate, 'deallocate (a)'), 'DEALLOCATE (a)')
assert_equal(parse(Deallocate, 'deallocate (a, stat=b)'), 'DEALLOCATE (a, STAT = b)')
@@ -289,12 +294,12 @@ class test_Statements(NumpyTestCase):
assert_equal(parse(Entry,'entry a(b)'), 'ENTRY a (b)')
assert_equal(parse(Entry,'entry a(b,*)'), 'ENTRY a (b, *)')
assert_equal(parse(Entry,'entry a bind(c , name="a b")'),
- 'ENTRY a BIND (c, name="a b")')
+ 'ENTRY a BIND (C, NAME = "a b")')
assert_equal(parse(Entry,'entry a result (b)'), 'ENTRY a RESULT (b)')
assert_equal(parse(Entry,'entry a bind(d) result (b)'),
'ENTRY a RESULT (b) BIND (d)')
- assert_equal(parse(Entry,'entry a result (b) bind(c)'),
- 'ENTRY a RESULT (b) BIND (c)')
+ assert_equal(parse(Entry,'entry a result (b) bind( c )'),
+ 'ENTRY a RESULT (b) BIND (C)')
assert_equal(parse(Entry,'entry a(b,*) result (g)'),
'ENTRY a (b, *) RESULT (g)')
@@ -423,5 +428,53 @@ class test_Statements(NumpyTestCase):
assert_equal(parse(Pause,'pause "hey"'),'PAUSE "hey"')
assert_equal(parse(Pause,'pause "hey pa"'),'PAUSE "hey pa"')
+ def check_integer(self):
+ assert_equal(parse(Integer,'integer'),'INTEGER')
+ assert_equal(parse(Integer,'integer*4'),'INTEGER(KIND=4)')
+ assert_equal(parse(Integer,'integer*4 a'),'INTEGER(KIND=4) a')
+ assert_equal(parse(Integer,'integer*4, a'),'INTEGER(KIND=4) a')
+ assert_equal(parse(Integer,'integer*4 a ,b'),'INTEGER(KIND=4) a, b')
+ assert_equal(parse(Integer,'integer*4 :: a ,b'),'INTEGER(KIND=4) a, b')
+ assert_equal(parse(Integer,'integer*4 a(1,2)'),'INTEGER(KIND=4) a(1,2)')
+ assert_equal(parse(Integer,'integer*4 :: a(1,2),b'),'INTEGER(KIND=4) a(1,2), b')
+ assert_equal(parse(Integer,'integer*4 external :: a'),
+ 'INTEGER(KIND=4), external :: a')
+ assert_equal(parse(Integer,'integer*4, external :: a'),
+ 'INTEGER(KIND=4), external :: a')
+ assert_equal(parse(Integer,'integer*4 external , intent(in) :: a'),
+ 'INTEGER(KIND=4), external, intent(in) :: a')
+ assert_equal(parse(Integer,'integer(kind=4)'),'INTEGER(KIND=4)')
+ assert_equal(parse(Integer,'integer ( kind = 4)'),'INTEGER(KIND=4)')
+ assert_equal(parse(Integer,'integer(kind=2+2)'),'INTEGER(KIND=2+2)')
+ assert_equal(parse(Integer,'integer(kind=f(4,5))'),'INTEGER(KIND=f(4,5))')
+
+ def check_character(self):
+ assert_equal(parse(Character,'character'),'CHARACTER')
+ assert_equal(parse(Character,'character*2'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character**'),'CHARACTER(LEN=*)')
+ assert_equal(parse(Character,'character*(2)'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character*(len =2)'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character*(len =2),'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character*(len =:)'),'CHARACTER(LEN=:)')
+ assert_equal(parse(Character,'character(len =2)'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character(2)'),'CHARACTER(LEN=2)')
+ assert_equal(parse(Character,'character(kind=2)'),'CHARACTER(KIND=2)')
+ assert_equal(parse(Character,'character(kind=2,len=3)'),
+ 'CHARACTER(LEN=3, KIND=2)')
+ assert_equal(parse(Character,'character(lEN=3,kind=2)'),
+ 'CHARACTER(LEN=3, KIND=2)')
+ assert_equal(parse(Character,'character(len=3,kind=2)', isstrict=True),
+ 'CHARACTER(LEN=3, KIND=2)')
+ assert_equal(parse(Character,'chaRACTER(len=3,kind=fA(1,2))', isstrict=True),
+ 'CHARACTER(LEN=3, KIND=fA(1,2))')
+ assert_equal(parse(Character,'character(len=3,kind=fA(1,2))'),
+ 'CHARACTER(LEN=3, KIND=fa(1,2))')
+
+ def check_implicit(self):
+ assert_equal(parse(Implicit,'implicit none'),'IMPLICIT NONE')
+ assert_equal(parse(Implicit,'implicit'),'IMPLICIT NONE')
+ assert_equal(parse(Implicit,'implicit integer (i-m)'),
+ 'IMPLICIT INTEGER ( i-m )')
+
if __name__ == "__main__":
NumpyTest().run()
diff --git a/numpy/f2py/lib/typedecl_statements.py b/numpy/f2py/lib/typedecl_statements.py
index 3f91d4a35..dba912743 100644
--- a/numpy/f2py/lib/typedecl_statements.py
+++ b/numpy/f2py/lib/typedecl_statements.py
@@ -1,6 +1,9 @@
import re
-from base_classes import Statement, BeginStatement, EndStatement
+import string
+from base_classes import Statement, BeginStatement, EndStatement,\
+ AttributeHolder, Variable
+from utils import split_comma, AnalyzeError
# Intrinsic type specification statements
@@ -66,7 +69,7 @@ class TypeDeclarationStatement(Statement):
line = item.get_line()
from block_statements import Function
- if not line.startswith(clsname):
+ if not line.lower().startswith(clsname):
i = 0
j = 0
for c in line:
@@ -77,7 +80,7 @@ class TypeDeclarationStatement(Statement):
break
line = line[:i].replace(' ','') + line[i:]
- assert line.startswith(clsname),`line,clsname`
+ assert line.lower().startswith(clsname),`line,clsname`
line = line[len(clsname):].lstrip()
if line.startswith('('):
@@ -121,31 +124,137 @@ class TypeDeclarationStatement(Statement):
line = line[1:].lstrip()
self.raw_selector = selector
+ if isinstance(self, Character):
+ self.selector = self._parse_char_selector(selector)
+ else:
+ self.selector = self._parse_kind_selector(selector)
+
i = line.find('::')
if i==-1:
- self.attrspec = ''
- self.entity_decls = line
+ self.attrspec = []
+ self.entity_decls = split_comma(line, self.item)
else:
- self.attrspec = line[:i].rstrip()
- self.entity_decls = line[i+2:].lstrip()
- if isinstance(self.parent, Function) and self.parent.name==self.entity_decls:
+ self.attrspec = split_comma(line[:i].rstrip(), self.item)
+ self.entity_decls = split_comma(line[i+2:].lstrip(), self.item)
+ if isinstance(self.parent, Function) \
+ and self.parent.name in self.entity_decls:
assert self.parent.typedecl is None,`self.parent.typedecl`
self.parent.typedecl = self
self.ignore = True
return
+ def _parse_kind_selector(self, selector):
+ if not selector:
+ return ''
+ if selector.startswith('*'):
+ kind = selector[1:].lstrip()
+ else:
+ assert selector[0]+selector[-1]=='()',`selector`
+ l = selector[1:-1].strip()
+ if l.lower().startswith('kind'):
+ l = l[4:].lstrip()
+ assert l.startswith('='),`l`
+ kind = l[1:].lstrip()
+ else:
+ kind = l
+ return kind
+
+ def _parse_char_selector(self, selector):
+ if not selector:
+ return '',''
+ if selector.startswith('*'):
+ l = selector[1:].lstrip()
+ if l.startswith('('):
+ if l.endswith(','): l = l[:-1].rstrip()
+ assert l.endswith(')'),`l`
+ l = l[1:-1].strip()
+ if l.lower().startswith('len'):
+ l = l[3:].lstrip()[1:].lstrip()
+ kind=''
+ else:
+ assert selector[0]+selector[-1]=='()',`selector`
+ l = split_comma(selector[1:-1].strip(), self.item)
+ if len(l)==1:
+ l = l[0]
+ if l.lower().startswith('len'):
+ l=l[3:].lstrip()
+ assert l.startswith('='),`l`
+ l=l[1:].lstrip()
+ kind = ''
+ elif l.lower().startswith('kind'):
+ kind = l[4:].lstrip()[1:].lstrip()
+ l = ''
+ else:
+ kind = ''
+ else:
+ assert len(l)==2
+ if l[0].lower().startswith('len'):
+ assert l[1].lower().startswith('kind'),`l`
+ kind = l[1][4:].lstrip()[1:].lstrip()
+ l = l[0][3:].lstrip()[1:].lstrip()
+ elif l[0].lower().startswith('kind'):
+ assert l[1].lower().startswith('len'),`l`
+ kind = l[0][4:].lstrip()[1:].lstrip()
+ l = l[1][3:].lstrip()[1:].lstrip()
+ else:
+ if l[1].lower().startswith('kind'):
+ kind = l[1][4:].lstrip()[1:].lstrip()
+ l = l[0]
+ else:
+ kind = l[1]
+ l = l[0]
+ return l,kind
+
def tostr(self):
- clsname = self.__class__.__name__.upper()
- return clsname + self.raw_selector
+ clsname = self.__class__.__name__.upper()
+ s = ''
+ if isinstance(self, Character):
+ length, kind = self.selector
+ if length and kind:
+ s += '(LEN=%s, KIND=%s)' % (length,kind)
+ elif length:
+ s += '(LEN=%s)' % (length)
+ elif kind:
+ s += '(KIND=%s)' % (kind)
+ else:
+ kind = self.selector
+ if kind:
+ s += '(KIND=%s)' % (kind)
+ return clsname + s
def __str__(self):
tab = self.get_indent_tab()
- if not self.attrspec:
- return tab + '%s :: %s' \
- % (self.tostr(), self.entity_decls)
- return tab + '%s, %s :: %s' \
- % (self.tostr(), self.attrspec, self.entity_decls)
-
+ s = self.tostr()
+ if self.attrspec:
+ s += ', ' + ', '.join(self.attrspec)
+ if self.entity_decls:
+ s += ' ::'
+ if self.entity_decls:
+ s += ' ' + ', '.join(self.entity_decls)
+ return tab + s
+
+ def __eq__(self, other):
+ if self.__class__ is not other.__class__:
+ return False
+ return self.selector==other.selector
+
+ def astypedecl(self):
+ return self.__class__(self.parent, self.item.copy(self.tostr()))
+
+ def analyze(self):
+ if not self.entity_decls:
+ return
+ variables = self.parent.a.variables
+ typedecl = self.astypedecl()
+ for name in self.entity_decls:
+ if not variables.has_key(name):
+ variables[name] = var = Variable(self, name)
+ else:
+ var = variables[name]
+ var.set_type(typedecl)
+ var.update(self.attrspec)
+ return
+
class Integer(TypeDeclarationStatement):
match = re.compile(r'integer\b',re.I).match
@@ -187,18 +296,73 @@ class Implicit(Statement):
<letter-spec> = <letter> [ - <letter> ]
"""
match = re.compile(r'implicit\b',re.I).match
+
+ letters = string.lowercase
+
def process_item(self):
line = self.item.get_line()[8:].lstrip()
- if line=='none':
+ if line.lower()=='none':
self.items = []
return
- self.items = [s.strip() for s in line.split()]
- assert self.items
+ items = []
+ for item in split_comma(line, self.item):
+ i = item.find('(')
+ assert i!=-1 and item.endswith(')'),`item`
+ specs = []
+ for spec in split_comma(item[i+1:-1].strip(), self.item):
+ if '-' in spec:
+ s,e = spec.lower().split('-')
+ assert s in self.letters and e in self.letters
+ else:
+ e = s = spec.lower()
+ assert s in self.letters
+ specs.append((s,e))
+ self.specs = specs
+ tspec = item[:i].rstrip()
+ stmt = None
+ for cls in declaration_type_spec:
+ if cls.match(tspec):
+ stmt = cls(self, self.item.copy(tspec))
+ if stmt.isvalid:
+ break
+ assert stmt is not None,`item,line`
+ items.append((stmt,specs))
+ self.items = items
+ return
def __str__(self):
tab = self.get_indent_tab()
if not self.items:
return tab + 'IMPLICIT NONE'
- return tab + 'IMPLICIT ' + ', '.join(self.items)
+ l = []
+ for stmt,specs in self.items:
+ l1 = []
+ for s,e in specs:
+ if s==e:
+ l1.append(s)
+ else:
+ l1.append(s + '-' + e)
+ l.append('%s ( %s )' % (stmt.tostr(), ', '.join(l1)))
+ return tab + 'IMPLICIT ' + ', '.join(l)
+ def analyze(self):
+ implicit_rules = self.parent.a.implicit_rules
+ if not self.items:
+ if implicit_rules:
+ raise AnalyzeError,'IMPLICIT NONE implies emtpy implicit_rules'\
+ ' but got %r' % (implicit_rules)
+ return
+ if implicit_rules is None:
+ self.parent.a.implicit_rules = implicit_rules = {}
+ for stmt,specs in self.items:
+ s,e = specs
+ for l in string.lowercase[string.lowercase.index(s.lower()):\
+ string.lowercase.index(e.lower())+1]:
+ implicit_rules[l] = stmt
+ return
+intrinsic_type_spec = [ \
+ Integer , Real,
+ DoublePrecision, Complex, DoubleComplex, Character, Logical, Byte
+ ]
+declaration_type_spec = intrinsic_type_spec + [ TypeStmt, Class ]
diff --git a/numpy/f2py/lib/utils.py b/numpy/f2py/lib/utils.py
new file mode 100644
index 000000000..7a501144e
--- /dev/null
+++ b/numpy/f2py/lib/utils.py
@@ -0,0 +1,121 @@
+
+import re
+import os, glob
+
+class ParseError(Exception):
+ pass
+
+class AnalyzeError(Exception):
+ pass
+
+is_name = re.compile(r'^[a-z_]\w*$',re.I).match
+
+def split_comma(line, item = None, comma=','):
+ items = []
+ if item is None:
+ for s in line.split(comma):
+ s = s.strip()
+ if not s: continue
+ items.append(s)
+ return items
+ newitem = item.copy(line, True)
+ apply_map = newitem.apply_map
+ for s in newitem.get_line().split(comma):
+ s = apply_map(s).strip()
+ if not s: continue
+ items.append(s)
+ return items
+
+def specs_split_comma(line, item = None):
+ specs0 = split_comma(line, item)
+ specs = []
+ for spec in specs0:
+ i = spec.find('=')
+ if i!=-1:
+ kw = spec[:i].strip().upper()
+ v = spec[i+1:].strip()
+ specs.append('%s = %s' % (kw, v))
+ else:
+ specs.append(spec)
+ return specs
+
+def parse_bind(line, item = None):
+ if not line.lower().startswith('bind'):
+ return None, line
+ if item is not None:
+ newitem = item.copy(line, apply_map=True)
+ newline = newitem.get_line()
+ else:
+ newitem = None
+ newline = newline[4:].lstrip()
+ i = newline.find(')')
+ assert i!=-1,`newline`
+ args = []
+ for a in specs_split_comma(newline[1:i].strip(), newitem):
+ if a=='c': a = a.upper()
+ args.append(a)
+ rest = newline[i+1:].lstrip()
+ if item is not None:
+ rest = newitem.apply_map(rest)
+ return args, rest
+
+def parse_result(line, item = None):
+ if not line.lower().startswith('result'):
+ return None, line
+ line = line[6:].lstrip()
+ i = line.find(')')
+ assert i != -1,`line`
+ name = line[1:i].strip()
+ assert is_name(name),`name`
+ return name, line[i+1:].lstrip()
+
+def filter_stmts(content, classes):
+ stmts = []
+ indices = []
+ for i in range(len(content)):
+ stmt = content[i]
+ if isinstance(stmt, classes):
+ stmts.append(stmt)
+ indices.append(i)
+ indices.reverse()
+ for i in indices:
+ del content[i]
+ return stmts
+
+
+def get_module_files(directory, _cache={}):
+ if _cache.has_key(directory):
+ return _cache[directory]
+ module_line = re.compile(r'(\A|^)module\s+(?P<name>\w+)\s*(!.*|)$',re.I | re.M)
+ d = {}
+ for fn in glob.glob(os.path.join(directory,'*.f90')):
+ f = open(fn,'r')
+ for name in module_line.findall(f.read()):
+ name = name[1]
+ if d.has_key(name):
+ print d[name],'already defines',name
+ continue
+ d[name] = fn
+ _cache[directory] = d
+ return d
+
+def get_module_file(name, directory, _cache={}):
+ fn = _cache.get(name, None)
+ if fn is not None:
+ return fn
+ if name.endswith('_module'):
+ f1 = os.path.join(directory,name[:-7]+'.f90')
+ if os.path.isfile(f1):
+ _cache[name] = fn
+ return f1
+ pattern = re.compile(r'\s*module\s+(?P<name>[a-z]\w*)', re.I).match
+ for fn in glob.glob(os.path.join(directory,'*.f90')):
+ f = open(fn,'r')
+ for line in f:
+ m = pattern(line)
+ if m and m.group('name')==name:
+ _cache[name] = fn
+ f.close()
+ return fn
+ f.close()
+ return