summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/f2py/lib/base_classes.py180
-rw-r--r--numpy/f2py/lib/block_statements.py37
-rw-r--r--numpy/f2py/lib/parsefortran.py20
-rw-r--r--numpy/f2py/lib/readfortran.py9
-rw-r--r--numpy/f2py/lib/statements.py253
-rw-r--r--numpy/f2py/lib/typedecl_statements.py47
-rw-r--r--numpy/f2py/lib/utils.py10
7 files changed, 434 insertions, 122 deletions
diff --git a/numpy/f2py/lib/base_classes.py b/numpy/f2py/lib/base_classes.py
index 21aa63b8e..ee19caaae 100644
--- a/numpy/f2py/lib/base_classes.py
+++ b/numpy/f2py/lib/base_classes.py
@@ -5,7 +5,8 @@ import re
import sys
import copy
from readfortran import Line
-from utils import split_comma, specs_split_comma
+from numpy.distutils.misc_util import yellow_text, red_text
+from utils import split_comma, specs_split_comma, is_int_literal_constant
class AttributeHolder:
# copied from symbolic.base module
@@ -81,27 +82,111 @@ class Variable:
"""
def __init__(self, parent, name):
self.parent = parent
+ self.parents = [parent]
self.name = name
self.typedecl = None
self.dimension = None
+ self.bounds = None
+ self.length = None
self.attributes = []
self.intent = None
self.bind = []
self.check = []
+ self.init = None
+ return
+
+ def add_parent(self, parent):
+ if id(parent) not in map(id, self.parents):
+ self.parents.append(parent)
+ self.parent = parent
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.parent.warning(\
+ 'variable %r already has type %s,'\
+ ' resetting to %s' \
+ % (self.name, self.typedecl.tostr(),typedecl.tostr()))
self.typedecl = typedecl
return
- def update(self, attrs):
+ def set_init(self, expr):
+ if self.init is not None:
+ if not self.init==expr:
+ self.parent.warning(\
+ 'variable %r already has initialization %r, '\
+ ' resetting to %r' % (self.name, self.expr, expr))
+ self.init = expr
+ return
+
+ def set_dimension(self, dims):
+ if self.dimension is not None:
+ if not self.dimension==dims:
+ self.parent.warning(\
+ 'variable %r already has dimension %r, '\
+ ' resetting to %r' % (self.name, self.dimension, dims))
+ self.dimension = dims
+ return
+
+ def set_bounds(self, bounds):
+ if self.bounds is not None:
+ if not self.bounds==bounds:
+ self.parent.warning(\
+ 'variable %r already has bounds %r, '\
+ ' resetting to %r' % (self.name, self.bounds, bounds))
+ self.bounds = bounds
+ return
+
+ def set_length(self, length):
+ if self.length is not None:
+ if not self.length==length:
+ self.parent.warning(\
+ 'variable %r already has length %r, '\
+ ' resetting to %r' % (self.name, self.length, length))
+ self.length = length
+ return
+
+ known_intent_specs = ['IN','OUT','INOUT','CACHE','HIDE', 'COPY',
+ 'OVERWRITE', 'CALLBACK', 'AUX', 'C', 'INPLACE',
+ 'OUT=']
+
+ def set_intent(self, intent):
+ if self.intent is None:
+ self.intent = []
+ for i in intent:
+ if i not in self.intent:
+ if i not in self.known_intent_specs:
+ self.parent.warning('unknown intent-spec %r for %r'\
+ % (i, self.name))
+ self.intent.append(i)
+ return
+
+ known_attributes = ['PUBLIC', 'PRIVATE', 'ALLOCATABLE', 'ASYNCHRONOUS',
+ 'EXTERNAL', 'INTRINSIC', 'OPTIONAL', 'PARAMETER',
+ 'POINTER', 'PROTECTED', 'SAVE', 'TARGET', 'VALUE',
+ 'VOLATILE', 'REQUIRED']
+
+ def is_private(self):
+ if 'PUBLIC' in self.attributes: return False
+ if 'PRIVATE' in self.attributes: return True
+ parent_attrs = self.parent.parent.a.attributes
+ if 'PUBLIC' in parent_attrs: return False
+ if 'PRIVATE' in parent_attrs: return True
+ return
+ def is_public(self): return not self.is_private()
+
+ def is_allocatable(self): return 'ALLOCATABLE' in self.attributes
+ def is_external(self): return 'EXTERNAL' in self.attributes
+ def is_intrinsic(self): return 'INTRINSIC' in self.attributes
+ def is_parameter(self): return 'PARAMETER' in self.attributes
+ def is_optional(self): return 'OPTIONAL' in self.attributes
+ def is_required(self): return 'REQUIRED' in self.attributes
+
+ def update(self, *attrs):
attributes = self.attributes
+ if len(attrs)==1 and isinstance(attrs[0],(tuple,list)):
+ attrs = attrs[0]
for attr in attrs:
lattr = attr.lower()
uattr = attr.upper()
@@ -109,20 +194,19 @@ class Variable:
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)
+ self.set_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)
+ self.set_intent(specs_split_comma(l[1:-1].strip(),
+ self.parent.item, upper=True))
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)
+ self.bind = specs_split_comma(l[1:-1].strip(), self.parent.item,
+ upper = True)
continue
if lattr.startswith('check'):
l = attr[5:].lstrip()
@@ -130,6 +214,8 @@ class Variable:
self.check.extend(split_comma(l[1:-1].strip()), self.parent.item)
continue
if uattr not in attributes:
+ if uattr not in self.known_attributes:
+ self.parent.warning('unknown attribute %r' % (attr))
attributes.append(uattr)
return
@@ -148,7 +234,17 @@ class Variable:
a.append('CHECK(%s)' % (', '.join(self.check)))
if a:
s += ', '.join(a) + ' :: '
- return s + self.name
+ s += self.name
+ if self.bounds:
+ s += '(%s)' % (', '.join(self.bounds))
+ if self.length:
+ if is_int_literal_constant(self.length):
+ s += '*%s' % (self.length)
+ else:
+ s += '*(%s)' % (self.length)
+ if self.init:
+ s += ' = ' + self.init
+ return s
class ProgramBlock:
pass
@@ -164,7 +260,10 @@ class Statement:
def __init__(self, parent, item):
self.parent = parent
- self.reader = parent.reader
+ if item is not None:
+ self.reader = item.reader
+ else:
+ self.reader = parent.reader
self.top = getattr(parent,'top',None)
if isinstance(parent, ProgramBlock):
self.programblock = parent
@@ -221,15 +320,44 @@ class Statement:
tab = c + s + colon + tab
return tab
- def show_message(self, message):
- print >> sys.stderr, message
- sys.stderr.flush()
+ def format_message(self, kind, message):
+ message = self.reader.format_message(kind, message,
+ self.item.span[0], self.item.span[1])
+ return message
+
+ def show_message(self, message, stream=sys.stderr):
+ print >> stream, message
+ stream.flush()
+ return
+
+ def error(self, message):
+ message = self.format_message('ERROR', red_text(message))
+ self.show_message(message)
+ return
+
+ def warning(self, message):
+ message = self.format_message('WARNING', yellow_text(message))
+ self.show_message(message)
+ return
+
+ def info(self, message):
+ message = self.format_message('INFO', message)
+ self.show_message(message)
return
def analyze(self):
- self.show_message('nothing analyzed in %s' % (self.__class__.__name__))
+ self.warning('nothing analyzed')
return
+ def get_variable(self, name):
+ variables = self.parent.a.variables
+ if not variables.has_key(name):
+ variables[name] = var = Variable(self, name)
+ else:
+ var = variables[name]
+ var.add_parent(self)
+ return var
+
class BeginStatement(Statement):
""" <blocktype> <name>
@@ -300,12 +428,7 @@ class BeginStatement(Statement):
item = self.get_item()
if not end_flag:
- message = self.item.reader.format_message(\
- 'WARNING',
- 'failed to find the end of block for %s'\
- % (self.__class__.__name__),
- self.item.span[0],self.item.span[1])
- self.show_message(message)
+ self.warning('failed to find the end of block')
return
def process_subitem(self, item):
@@ -439,12 +562,9 @@ class EndStatement(Statement):
self.isvalid = False
if line:
if not line==self.parent.name:
- message = item.reader.format_message(\
- 'WARNING',
- 'expected the end of %r block but got end of %r, skipping.'\
- % (self.parent.name, line),
- item.span[0],item.span[1])
- self.show_message(message)
+ self.warning(\
+ 'expected the end of %r block but got the end of %r, skipping.'\
+ % (self.parent.name, line))
self.isvalid = False
self.name = self.parent.name
diff --git a/numpy/f2py/lib/block_statements.py b/numpy/f2py/lib/block_statements.py
index 5c72fb808..767bd0893 100644
--- a/numpy/f2py/lib/block_statements.py
+++ b/numpy/f2py/lib/block_statements.py
@@ -62,14 +62,14 @@ class HasTypeDecls:
a = AttributeHolder(type_decls = {})
-class HasExternal:
-
- a = AttributeHolder(external = [])
-
class HasAttributes:
a = AttributeHolder(attributes = [])
+class HasModuleProcedures:
+
+ a = AttributeHolder(module_procedures = [])
+
# File block
class EndSource(EndStatement):
@@ -110,8 +110,7 @@ class BeginSource(BeginStatement):
stmt.analyze()
self.a.blockdata[stmt.name] = stmt
else:
- message = 'Unexpected statement %r in %r block. Ignoring.' \
- % (stmt.__class__, self.__class__)
+ stmt.analyze()
return
def get_classes(self):
@@ -185,7 +184,7 @@ class Module(BeginStatement, HasAttributes,
stmt.analyze()
if content:
- print 'Not analyzed content:',content
+ self.show_message('Not analyzed content: %s' % content)
return
@@ -208,8 +207,8 @@ class PythonModule(BeginStatement, HasImplicitStmt, HasUseStmt):
return [Interface, Function, Subroutine, Module]
def process_item(self):
- name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip()
- self.name = name
+ self.name = self.item.get_line().replace(' ','')\
+ [len(self.blocktype):].strip()
return BeginStatement.process_item(self)
# Program
@@ -268,7 +267,9 @@ class EndInterface(EndStatement):
match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match
blocktype = 'interface'
-class Interface(BeginStatement, HasImplicitStmt, HasUseStmt):
+class Interface(BeginStatement, HasImplicitStmt, HasUseStmt,
+ HasModuleProcedures
+ ):
"""
INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
END INTERFACE [<generic-spec>]
@@ -311,8 +312,8 @@ class Interface(BeginStatement, HasImplicitStmt, HasUseStmt):
class SubProgramStatement(BeginStatement, ProgramBlock,
HasImplicitStmt, HasAttributes,
- HasUseStmt, HasVariables, HasTypeDecls,
- HasExternal):
+ HasUseStmt, HasVariables, HasTypeDecls
+ ):
"""
[ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ]
"""
@@ -399,20 +400,12 @@ class SubProgramStatement(BeginStatement, ProgramBlock,
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
+ self.show_message('Not analyzed content: %s' % content)
return
@@ -618,7 +611,7 @@ class If(BeginStatement):
i = line.find(')')
expr = line[1:i].strip()
line = line[i+1:].strip()
- if line=='then':
+ if line.lower()=='then':
self.isvalid = False
return
self.expr = expr[1:-1]
diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py
index 314bbfa24..00b53f0b0 100644
--- a/numpy/f2py/lib/parsefortran.py
+++ b/numpy/f2py/lib/parsefortran.py
@@ -21,8 +21,19 @@ from utils import AnalyzeError
class FortranParser:
+ cache = {}
+
def __init__(self, reader):
self.reader = reader
+ if self.cache.has_key(reader.id):
+ parser = self.cache[reader.id]
+ self.block = parser.block
+ self.is_analyzed = parser.is_analyzed
+ self.block.show_message('using cached %s' % (reader.id))
+ else:
+ self.cache[reader.id] = self
+ self.block = None
+ self.is_analyzed = False
return
def get_item(self):
@@ -37,6 +48,8 @@ class FortranParser:
return
def parse(self):
+ if self.block is not None:
+ return
try:
block = self.block = BeginSource(self)
except KeyboardInterrupt:
@@ -55,12 +68,19 @@ class FortranParser:
return
def analyze(self):
+ if self.is_analyzed:
+ return
+ if self.block is None:
+ self.reader.show_message('Nothing to analyze.')
+ return
+
try:
self.block.analyze()
except AnalyzeError:
pass
except:
raise
+ self.is_analyzed = True
return
def test_pyf():
diff --git a/numpy/f2py/lib/readfortran.py b/numpy/f2py/lib/readfortran.py
index add45e71c..b23a7368f 100644
--- a/numpy/f2py/lib/readfortran.py
+++ b/numpy/f2py/lib/readfortran.py
@@ -379,10 +379,11 @@ class FortranReaderBase:
def format_message(self, kind, message, startlineno, endlineno,
startcolno=0, endcolno=-1):
- r = ['%s while processing %s (mode=%r)..' % (kind, self.source, self.mode)]
- for i in range(max(1,startlineno-3),startlineno):
+ back_index = {'warning':2,'error':3,'info':0}.get(kind.lower(),3)
+ r = ['%s while processing %r (mode=%r)..' % (kind, self.id, self.mode)]
+ for i in range(max(1,startlineno-back_index),startlineno):
r.append('%5d:%s' % (i,self.source_lines[i-1]))
- for i in range(startlineno,min(endlineno+3,len(self.source_lines))+1):
+ for i in range(startlineno,min(endlineno+back_index,len(self.source_lines))+1):
if i==0 and not self.source_lines:
break
linenostr = '%5d:' % (i)
@@ -695,6 +696,7 @@ class FortranFileReader(FortranReaderBase):
def __init__(self, filename,
include_dirs = None):
isfree, isstrict = get_source_info(filename)
+ self.id = filename
self.file = open(filename,'r')
FortranReaderBase.__init__(self, self.file, isfree, isstrict)
if include_dirs is None:
@@ -709,6 +711,7 @@ class FortranFileReader(FortranReaderBase):
class FortranStringReader(FortranReaderBase):
def __init__(self, string, isfree, isstrict):
+ self.id = 'string-'+str(id(string))
source = StringIO(string)
FortranReaderBase.__init__(self, source, isfree, isstrict)
diff --git a/numpy/f2py/lib/statements.py b/numpy/f2py/lib/statements.py
index 5a24f2d84..b3bd34e51 100644
--- a/numpy/f2py/lib/statements.py
+++ b/numpy/f2py/lib/statements.py
@@ -3,29 +3,34 @@ import re
import sys
from base_classes import Statement, Variable
-from expression import Expression
+#from expression import Expression
# Auxiliary tools
from utils import split_comma, specs_split_comma, AnalyzeError, ParseError,\
- get_module_file, parse_bind, parse_result
-
-is_name = re.compile(r'\w+\Z').match
+ get_module_file, parse_bind, parse_result, is_name
class StatementWithNamelist(Statement):
"""
<statement> [ :: ] <name-list>
"""
def process_item(self):
- assert not self.item.has_map()
+ if self.item.has_map():
+ self.isvalid = False
+ return
if hasattr(self,'stmtname'):
clsname = self.stmtname
else:
- clsname = self.__class__.__name__.lower()
+ clsname = self.__class__.__name__
line = self.item.get_line()[len(clsname):].lstrip()
if line.startswith('::'):
line = line[2:].lstrip()
- self.items = [s.strip() for s in line.split(',')]
+ self.items = items = []
+ for item in split_comma(line):
+ if not is_name(item):
+ self.isvalid = False
+ return
+ items.append(item)
return
def __str__(self):
if hasattr(self,'stmtname'):
@@ -74,6 +79,8 @@ class GeneralAssignment(Statement):
return self.get_indent_tab() + '%s %s %s' \
% (self.variable, self.sign, self.expr)
+ def analyze(self): return
+
class Assignment(GeneralAssignment):
pass
@@ -95,6 +102,7 @@ class Assign(Statement):
def __str__(self):
return self.get_indent_tab() + 'ASSIGN %s TO %s' \
% (self.items[0], self.items[1])
+ def analyze(self): return
class Call(Statement):
"""Call statement class
@@ -167,6 +175,7 @@ class Goto(Statement):
def __str__(self):
return self.get_indent_tab() + 'GO TO %s' % (self.label)
+ def analyze(self): return
class ComputedGoto(Statement):
"""
@@ -186,6 +195,7 @@ class ComputedGoto(Statement):
def __str__(self):
return self.get_indent_tab() + 'GO TO (%s) %s' \
% (', '.join(self.items), self.expr)
+ def analyze(self): return
class AssignedGoto(Statement):
"""
@@ -212,6 +222,7 @@ class AssignedGoto(Statement):
return tab + 'GO TO %s (%s)' \
% (self.varname, ', '.join(self.items))
return tab + 'GO TO %s' % (self.varname)
+ def analyze(self): return
class Continue(Statement):
"""
@@ -290,6 +301,7 @@ class Print(Statement):
def __str__(self):
return self.get_indent_tab() + 'PRINT %s' \
% (', '.join([self.format]+self.items))
+ def analyze(self): return
class Read(Statement):
"""
@@ -315,6 +327,7 @@ Read1: READ <format> [, <input-item-list>]
self.__class__ = Read1
self.process_item()
return
+ def analyze(self): return
class Read0(Read):
@@ -365,7 +378,7 @@ class Write(Statement):
if self.items:
s += ' ' + ', '.join(self.items)
return s
-
+ def analyze(self): return
class Flush(Statement):
@@ -394,6 +407,7 @@ class Flush(Statement):
def __str__(self):
tab = self.get_indent_tab()
return tab + 'FLUSH (%s)' % (', '.join(self.specs))
+ def analyze(self): return
class Wait(Statement):
"""
@@ -415,6 +429,7 @@ class Wait(Statement):
def __str__(self):
tab = self.get_indent_tab()
return tab + 'WAIT (%s)' % (', '.join(self.specs))
+ def analyze(self): return
class Contains(Statement):
"""
@@ -450,7 +465,7 @@ class Allocate(Statement):
if stmt is not None and stmt.isvalid:
spec = stmt
else:
- print 'TODO: unparsed type-spec',`spec`
+ self.warning('TODO: unparsed type-spec' + `spec`)
line2 = line2[i+2:].lstrip()
else:
spec = None
@@ -464,6 +479,7 @@ class Allocate(Statement):
t = self.spec.tostr() + ' :: '
return self.get_indent_tab() \
+ 'ALLOCATE (%s%s)' % (t,', '.join(self.items))
+ def analyze(self): return
class Deallocate(Statement):
"""
@@ -481,7 +497,8 @@ class Deallocate(Statement):
return
def __str__(self): return self.get_indent_tab() \
+ 'DEALLOCATE (%s)' % (', '.join(self.items))
-
+ def analyze(self): return
+
class ModuleProcedure(Statement):
"""
[ MODULE ] PROCEDURE <procedure-name-list>
@@ -503,6 +520,11 @@ class ModuleProcedure(Statement):
tab = self.get_indent_tab()
return tab + 'MODULE PROCEDURE %s' % (', '.join(self.items))
+ def analyze(self):
+ module_procedures = self.parent.a.module_procedures
+ module_procedures.extend(self.items)
+ return
+
class Access(Statement):
"""
<access-spec> [ [::] <access-id-list>]
@@ -532,12 +554,9 @@ class Access(Statement):
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])
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update(clsname)
else:
self.parent.a.attributes.append(clsname)
return
@@ -564,6 +583,7 @@ class Close(Statement):
def __str__(self):
tab = self.get_indent_tab()
return tab + 'CLOSE (%s)' % (', '.join(self.specs))
+ def analyze(self): return
class Cycle(Statement):
"""
@@ -577,6 +597,7 @@ class Cycle(Statement):
if self.name:
return self.get_indent_tab() + 'CYCLE ' + self.name
return self.get_indent_tab() + 'CYCLE'
+ def analyze(self): return
class FilePositioningStatement(Statement):
"""
@@ -608,6 +629,7 @@ class FilePositioningStatement(Statement):
def __str__(self):
clsname = self.__class__.__name__.upper()
return self.get_indent_tab() + clsname + ' (%s)' % (', '.join(self.specs))
+ def analyze(self): return
class Backspace(FilePositioningStatement): pass
@@ -629,6 +651,7 @@ class Open(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'OPEN (%s)' % (', '.join(self.specs))
+ def analyze(self): return
class Format(Statement):
"""
@@ -659,18 +682,15 @@ class Format(Statement):
item = self.item
if not item.label:
# R1001:
- message = self.reader.format_message(\
- 'WARNING',
- 'R1001: FORMAT statement must be labeled but got %r.' \
- % (item.label),
- item.span[0],item.span[1])
- self.show_message(message)
+ self.warning('R1001: FORMAT statement must be labeled but got %r.' \
+ % (item.label))
line = item.get_line()[6:].lstrip()
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 analyze(self): return
class Save(Statement):
"""
@@ -708,6 +728,7 @@ class Save(Statement):
if not self.items:
return tab + 'SAVE'
return tab + 'SAVE %s' % (', '.join(self.items))
+ def analyze(self): return
class Data(Statement):
"""
@@ -755,6 +776,7 @@ class Data(Statement):
for o,v in self.stmts:
l.append('%s / %s /' %(', '.join(o),', '.join(v)))
return tab + 'DATA ' + ' '.join(l)
+ def analyze(self): return
class Nullify(Statement):
"""
@@ -768,6 +790,7 @@ class Nullify(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'NULLIFY (%s)' % (', '.join(self.items))
+ def analyze(self): return
class Use(Statement):
"""
@@ -830,11 +853,10 @@ class Use(Statement):
fn = get_module_file(self.name, d)
if fn is not None:
break
-
- if fn is not None:
+ if 1 and fn is not None:
from readfortran import FortranFileReader
from parsefortran import FortranParser
- self.show_message('Processing %r (parent file=%r)' % (fn, self.reader.name))
+ self.info('looking module information from %r' % (fn))
reader = FortranFileReader(fn)
parser = FortranParser(reader)
parser.parse()
@@ -843,15 +865,7 @@ class Use(Statement):
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
-
+ self.warning('no information about the use module %r' % (self.name))
return
class Exit(Statement):
@@ -866,6 +880,7 @@ class Exit(Statement):
if self.name:
return self.get_indent_tab() + 'EXIT ' + self.name
return self.get_indent_tab() + 'EXIT'
+ def analyze(self): return
class Parameter(Statement):
"""
@@ -879,6 +894,16 @@ class Parameter(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'PARAMETER (%s)' % (', '.join(self.items))
+ def analyze(self):
+ for item in self.items:
+ i = item.find('=')
+ assert i!=-1,`item`
+ name = item[:i].rstrip()
+ value = item[i+1:].lstrip()
+ var = self.get_variable(name)
+ var.update('parameter')
+ var.set_init(value)
+ return
class Equivalence(Statement):
"""
@@ -898,6 +923,7 @@ class Equivalence(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'EQUIVALENCE %s' % (', '.join(self.items))
+ def analyze(self): return
class Dimension(Statement):
"""
@@ -913,6 +939,15 @@ class Dimension(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'DIMENSION %s' % (', '.join(self.items))
+ def analyze(self):
+ for line in self.items:
+ i = line.find('(')
+ assert i!=-1 and line.endswith(')'),`line`
+ name = line[:i].rstrip()
+ array_spec = split_comma(line[i+1:-1].strip(), self.item)
+ var = self.get_variable(name)
+ var.set_bounds(array_spec)
+ return
class Target(Statement):
"""
@@ -928,6 +963,17 @@ class Target(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'TARGET %s' % (', '.join(self.items))
+ def analyze(self):
+ for line in self.items:
+ i = line.find('(')
+ assert i!=-1 and line.endswith(')'),`line`
+ name = line[:i].rstrip()
+ array_spec = split_comma(line[i+1:-1].strip(), self.item)
+ var = self.get_variable(name)
+ var.set_bounds(array_spec)
+ var.update('target')
+ return
+
class Pointer(Statement):
"""
@@ -945,25 +991,53 @@ class Pointer(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'POINTER %s' % (', '.join(self.items))
+ def analyze(self):
+ for line in self.items:
+ i = line.find('(')
+ if i==-1:
+ name = line
+ array_spec = None
+ else:
+ assert line.endswith(')'),`line`
+ name = line[:i].rstrip()
+ array_spec = split_comma(line[i+1:-1].strip(), self.item)
+ var = self.get_variable(name)
+ var.set_bounds(array_spec)
+ var.update('pointer')
+ return
class Protected(StatementWithNamelist):
"""
PROTECTED [ :: ] <entity-name-list>
"""
match = re.compile(r'protected\b',re.I).match
-
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('protected')
+ return
class Volatile(StatementWithNamelist):
"""
- Volatile [ :: ] <object-name-list>
+ VOLATILE [ :: ] <object-name-list>
"""
match = re.compile(r'volatile\b',re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('volatile')
+ return
class Value(StatementWithNamelist):
"""
VALUE [ :: ] <dummy-arg-name-list>
"""
match = re.compile(r'value\b',re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('value')
+ return
class ArithmeticIf(Statement):
"""
@@ -982,12 +1056,18 @@ class ArithmeticIf(Statement):
def __str__(self):
return self.get_indent_tab() + 'IF (%s) %s' \
% (self.expr,', '.join(self.labels))
+ def analyze(self): return
class Intrinsic(StatementWithNamelist):
"""
INTRINSIC [ :: ] <intrinsic-procedure-name-list>
"""
match = re.compile(r'intrinsic\b',re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('intrinsic')
+ return
class Inquire(Statement):
"""
@@ -1013,6 +1093,7 @@ class Inquire(Statement):
% (', '.join(self.specs), ', '.join(self.items))
return self.get_indent_tab() + 'INQUIRE (%s)' \
% (', '.join(self.specs))
+ def analyze(self): return
class Sequence(Statement):
"""
@@ -1022,12 +1103,21 @@ class Sequence(Statement):
def process_item(self):
return
def __str__(self): return self.get_indent_tab() + 'SEQUENCE'
+ def analyze(self):
+ self.parent.a.attributes.append('SEQUENCE')
+ return
class External(StatementWithNamelist):
"""
EXTERNAL [ :: ] <external-name-list>
"""
match = re.compile(r'external\b', re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('external')
+ return
+
class Namelist(Statement):
"""
@@ -1107,6 +1197,21 @@ class Common(Statement):
l.append(s)
tab = self.get_indent_tab()
return tab + 'COMMON ' + ' '.join(l)
+ def analyze(self):
+ for cname, items in self.items:
+ for item in items:
+ i = item.find('(')
+ if i!=-1:
+ assert item.endswith(')'),`item`
+ name = item[:i].rstrip()
+ shape = split_comma(item[i+1:-1].strip(), self.item)
+ else:
+ name = item
+ shape = None
+ var = self.get_variable(name)
+ if shape is not None:
+ var.set_bounds(shape)
+ return
class Optional(StatementWithNamelist):
"""
@@ -1114,6 +1219,11 @@ class Optional(StatementWithNamelist):
<dummy-arg-name> = <name>
"""
match = re.compile(r'optional\b',re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('optional')
+ return
class Intent(Statement):
"""
@@ -1128,7 +1238,7 @@ class Intent(Statement):
def process_item(self):
line = self.item.get_line()[6:].lstrip()
i = line.find(')')
- self.specs = split_comma(line[1:i], self.item)
+ self.specs = specs_split_comma(line[1:i], self.item, upper=True)
line = line[i+1:].lstrip()
if line.startswith('::'):
line = line[2:].lstrip()
@@ -1141,6 +1251,12 @@ class Intent(Statement):
def __str__(self):
return self.get_indent_tab() + 'INTENT (%s) %s' \
% (', '.join(self.specs), ', '.join(self.items))
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.set_intent(self.specs)
+ return
+
class Entry(Statement):
"""
@@ -1252,6 +1368,7 @@ class Forall(Statement):
s += ', ' + self.mask
return tab + 'FORALL (%s) %s' % \
(s, str(self.content[0]).lstrip())
+ def analyze(self): return
ForallStmt = Forall
@@ -1360,12 +1477,33 @@ class Allocatable(Statement):
return
def __str__(self):
return self.get_indent_tab() + 'ALLOCATABLE ' + ', '.join(self.items)
+ def analyze(self):
+ for line in self.items:
+ i = line.find('(')
+ if i==-1:
+ name = line
+ array_spec = None
+ else:
+ assert line.endswith(')')
+ name = line[:i].rstrip()
+ array_spec = split_comma(line[i+1:-1], self.item)
+ var = self.get_variable(name)
+ var.update('allocatable')
+ if array_spec is not None:
+ var.set_bounds(array_spec)
+ return
class Asynchronous(StatementWithNamelist):
"""
ASYNCHRONOUS [ :: ] <object-name-list>
"""
match = re.compile(r'asynchronous\b',re.I).match
+ def analyze(self):
+ for name in self.items:
+ var = self.get_variable(name)
+ var.update('asynchronous')
+ return
+
class Bind(Statement):
"""
@@ -1404,12 +1542,8 @@ class Else(Statement):
self.name = item.get_line()[4:].strip()
parent_name = getattr(self.parent,'name','')
if self.name and self.name!=parent_name:
- message = self.reader.format_message(\
- 'WARNING',
- 'expected if-construct-name %r but got %r, skipping.'\
- % (parent_name, self.name),
- item.span[0],item.span[1])
- print >> sys.stderr, message
+ self.warning('expected if-construct-name %r but got %r, skipping.'\
+ % (parent_name, self.name))
self.isvalid = False
return
@@ -1418,6 +1552,8 @@ class Else(Statement):
return self.get_indent_tab(deindent=True) + 'ELSE ' + self.name
return self.get_indent_tab(deindent=True) + 'ELSE'
+ def analyze(self): return
+
class ElseIf(Statement):
"""
ELSE IF ( <scalar-logical-expr> ) THEN [ <if-construct-name> ]
@@ -1433,12 +1569,8 @@ class ElseIf(Statement):
self.name = line[i+1:].lstrip()[4:].strip()
parent_name = getattr(self.parent,'name','')
if self.name and self.name!=parent_name:
- message = self.reader.format_message(\
- 'WARNING',
- 'expected if-construct-name %r but got %r, skipping.'\
- % (parent_name, self.name),
- item.span[0],item.span[1])
- self.show_message(message)
+ self.warning('expected if-construct-name %r but got %r, skipping.'\
+ % (parent_name, self.name))
self.isvalid = False
return
@@ -1449,6 +1581,8 @@ class ElseIf(Statement):
return self.get_indent_tab(deindent=True) + 'ELSE IF (%s) THEN%s' \
% (self.expr, s)
+ def analyze(self): return
+
# SelectCase construct statements
class Case(Statement):
@@ -1483,12 +1617,8 @@ class Case(Statement):
self.name = line
parent_name = getattr(self.parent, 'name', '')
if self.name and self.name!=parent_name:
- message = self.reader.format_message(\
- 'WARNING',
- 'expected case-construct-name %r but got %r, skipping.'\
- % (parent_name, self.name),
- self.item.span[0],self.item.span[1])
- self.show_message(message)
+ self.warning('expected case-construct-name %r but got %r, skipping.'\
+ % (parent_name, self.name))
self.isvalid = False
return
@@ -1505,6 +1635,7 @@ class Case(Statement):
if self.name:
s += ' ' + self.name
return s
+ def analyze(self): return
# Where construct statements
@@ -1531,6 +1662,7 @@ class Where(Statement):
def __str__(self):
tab = self.get_indent_tab()
return tab + 'WHERE ( %s ) %s' % (self.expr, str(self.content[0]).lstrip())
+ def analyze(self): return
WhereStmt = Where
@@ -1551,12 +1683,8 @@ class ElseWhere(Statement):
self.name = line
parent_name = getattr(self.parent,'name','')
if self.name and not self.name==parent_name:
- message = self.reader.format_message(\
- 'WARNING',
- 'expected where-construct-name %r but got %r, skipping.'\
- % (parent_name, self.name),
- self.item.span[0],self.item.span[1])
- print >> sys.stderr, message
+ self.warning('expected where-construct-name %r but got %r, skipping.'\
+ % (parent_name, self.name))
self.isvalid = False
return
@@ -1568,6 +1696,7 @@ class ElseWhere(Statement):
if self.name:
s += ' ' + self.name
return tab + s
+ def analyze(self): return
# Enum construct statements
@@ -1685,3 +1814,5 @@ class Pause(Statement):
if self.value:
return self.get_indent_tab() + 'PAUSE ' + self.value
return self.get_indent_tab() + 'PAUSE'
+ def analyze(self): return
+
diff --git a/numpy/f2py/lib/typedecl_statements.py b/numpy/f2py/lib/typedecl_statements.py
index dba912743..63b9a346e 100644
--- a/numpy/f2py/lib/typedecl_statements.py
+++ b/numpy/f2py/lib/typedecl_statements.py
@@ -3,7 +3,7 @@ import re
import string
from base_classes import Statement, BeginStatement, EndStatement,\
AttributeHolder, Variable
-from utils import split_comma, AnalyzeError
+from utils import split_comma, AnalyzeError, name_re, is_entity_decl
# Intrinsic type specification statements
@@ -136,6 +136,11 @@ class TypeDeclarationStatement(Statement):
else:
self.attrspec = split_comma(line[:i].rstrip(), self.item)
self.entity_decls = split_comma(line[i+2:].lstrip(), self.item)
+ for entity in self.entity_decls:
+ if not is_entity_decl(entity):
+ self.isvalid = False
+ return
+
if isinstance(self.parent, Function) \
and self.parent.name in self.entity_decls:
assert self.parent.typedecl is None,`self.parent.typedecl`
@@ -246,15 +251,51 @@ class TypeDeclarationStatement(Statement):
return
variables = self.parent.a.variables
typedecl = self.astypedecl()
- for name in self.entity_decls:
+ for item in self.entity_decls:
+ name, array_spec, char_length, value = self._parse_entity(item)
if not variables.has_key(name):
variables[name] = var = Variable(self, name)
else:
var = variables[name]
- var.set_type(typedecl)
+ var.add_parent(self)
+ if char_length:
+ var.set_length(char_length)
+ else:
+ var.set_type(typedecl)
var.update(self.attrspec)
+ if array_spec:
+ var.set_bounds(array_spec)
+ if value:
+ var.set_init(value)
return
+ def _parse_entity(self, line):
+ m = name_re(line)
+ assert m,`line,self.item,self.__class__.__name__`
+ name = line[:m.end()]
+ line = line[m.end():].lstrip()
+ array_spec = None
+ item = self.item.copy(line)
+ line = item.get_line()
+ if line.startswith('('):
+ i = line.find(')')
+ assert i!=-1,`line`
+ array_spec = split_comma(line[1:i].strip(), item)
+ line = line[i+1:].lstrip()
+ char_length = None
+ if line.startswith('*'):
+ i = line.find('=')
+ if i==-1:
+ char_length = item.apply_map(line[1:].lstrip())
+ line = ''
+ else:
+ char_length = item.apply_map(line[1:i].strip())
+ line = line[i:]
+ value = None
+ if line.startswith('='):
+ value = item.apply_map(line[1:].lstrip())
+ return name, array_spec, char_length, value
+
class Integer(TypeDeclarationStatement):
match = re.compile(r'integer\b',re.I).match
diff --git a/numpy/f2py/lib/utils.py b/numpy/f2py/lib/utils.py
index 7a501144e..7a194c9c7 100644
--- a/numpy/f2py/lib/utils.py
+++ b/numpy/f2py/lib/utils.py
@@ -9,6 +9,9 @@ class AnalyzeError(Exception):
pass
is_name = re.compile(r'^[a-z_]\w*$',re.I).match
+name_re = re.compile(r'[a-z_]\w*',re.I).match
+is_entity_decl = re.compile(r'^[a-z_]\w*',re.I).match
+is_int_literal_constant = re.compile(r'^\d+(_\w+|)$').match
def split_comma(line, item = None, comma=','):
items = []
@@ -26,7 +29,7 @@ def split_comma(line, item = None, comma=','):
items.append(s)
return items
-def specs_split_comma(line, item = None):
+def specs_split_comma(line, item = None, upper=False):
specs0 = split_comma(line, item)
specs = []
for spec in specs0:
@@ -36,6 +39,8 @@ def specs_split_comma(line, item = None):
v = spec[i+1:].strip()
specs.append('%s = %s' % (kw, v))
else:
+ if upper:
+ spec = spec.upper()
specs.append(spec)
return specs
@@ -51,8 +56,7 @@ def parse_bind(line, item = None):
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()
+ for a in specs_split_comma(newline[1:i].strip(), newitem, upper=True):
args.append(a)
rest = newline[i+1:].lstrip()
if item is not None: