From numpy-svn at scipy.org Sun Oct 1 07:49:52 2006 From: numpy-svn at scipy.org (numpy-svn at scipy.org) Date: Sun, 1 Oct 2006 06:49:52 -0500 (CDT) Subject: [Numpy-svn] r3238 - in trunk/numpy/f2py/lib: . parser Message-ID: <20061001114952.6AEB439C00E@new.scipy.org> Author: pearu Date: 2006-10-01 06:49:23 -0500 (Sun, 01 Oct 2006) New Revision: 3238 Added: trunk/numpy/f2py/lib/parser/ trunk/numpy/f2py/lib/parser/__init__.py trunk/numpy/f2py/lib/parser/api.py trunk/numpy/f2py/lib/parser/base_classes.py trunk/numpy/f2py/lib/parser/block_statements.py trunk/numpy/f2py/lib/parser/doc.txt trunk/numpy/f2py/lib/parser/parsefortran.py trunk/numpy/f2py/lib/parser/readfortran.py trunk/numpy/f2py/lib/parser/sourceinfo.py trunk/numpy/f2py/lib/parser/splitline.py trunk/numpy/f2py/lib/parser/statements.py trunk/numpy/f2py/lib/parser/test_parser.py trunk/numpy/f2py/lib/parser/typedecl_statements.py trunk/numpy/f2py/lib/parser/utils.py Removed: trunk/numpy/f2py/lib/analyzefortran.py trunk/numpy/f2py/lib/base_classes.py trunk/numpy/f2py/lib/block_statements.py trunk/numpy/f2py/lib/doc.txt trunk/numpy/f2py/lib/parsefortran.py trunk/numpy/f2py/lib/readfortran.py trunk/numpy/f2py/lib/sourceinfo.py trunk/numpy/f2py/lib/splitline.py trunk/numpy/f2py/lib/statements.py trunk/numpy/f2py/lib/test_parser.py trunk/numpy/f2py/lib/typedecl_statements.py trunk/numpy/f2py/lib/utils.py Modified: trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py trunk/numpy/f2py/lib/python_wrapper.py Log: F2PY G3: Moved Fortran parser related code to subpackage parser. Deleted: trunk/numpy/f2py/lib/analyzefortran.py =================================================================== --- trunk/numpy/f2py/lib/analyzefortran.py 2006-09-30 23:33:23 UTC (rev 3237) +++ trunk/numpy/f2py/lib/analyzefortran.py 2006-10-01 11:49:23 UTC (rev 3238) @@ -1,138 +0,0 @@ -#!/usr/bin/env python -""" -Defines FortranAnalyzer. - -Permission to use, modify, and distribute this software is given under the -terms of the NumPy License. See http://scipy.org. -NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - -Author: Pearu Peterson -Created: June 2006 -""" - -from numpy.distutils.misc_util import yellow_text, red_text - -class FortranAnalyzer: - - def __init__(self, block): - """ - block is a BeginSource instance with relevant attributes: - name - reader name - content - a list of statements - - Statements are either block statements or simple statements. - - Block statements have the following relevant attributes: - name - block name - blocktype - statement name (equal to lowered statement class name) - content - a list of statements - - Block statements may have additional attributes: - BeginSource: top - Module: - PythonModule: - Program: - BlockData: - Interface: isabstract, generic_spec - Subroutine: prefix, args, suffix - Function: prefix, typedecl, args, suffix - Select: expr - Where: expr - Forall: specs - IfThen: expr - If: expr - Do: endlabel, loopcontrol - Associate: associations - Type: specs, params - Enum: - - Simple statements have various attributes: - Assignment: variable, expr - PointerAssignment: variable, expr - Assign: items - Call: designator, items - Goto: label - ComputedGoto: items, expr - AssignedGoto: varname, items - Continue: label - Return: expr - Stop: code - Print: format, items - Read0: specs, items - Read1: format, items - Write: specs, items - Flush: specs - Wait: specs - Contains: - Allocate: spec, items - Deallocate: items - ModuleProcedure: items - Public | Private: items - Close: specs - Cycle: name - Rewind | Backspace | Endfile: specs - Open: specs - Format: specs - Save: items - Data: stmts - Nullify: items - Use: nature, name, isonly, items - Exit: name - Parameter: items - Equivalence: items - Dimension: items - Target: items - Pointer: items - Protected | Volatile | Value | Intrinsic | External | Optional: items - ArithmeticIf: expr, labels - Inquire: specs, items - Sequence: - Common: items - Intent: specs, items - Entry: name, items, result, binds - Import: items - Forall: specs, content - SpecificBinding: iname, attrs, name, bname - GenericBinding: aspec, spec, items - FinalBinding: items - Allocatable: items - Asynchronous: items - Bind: specs, items - Else: name - ElseIf: name, expr - Case: name, items - Else: name - ElseIf: name, expr - Case: name, items - Where: name, expr - ElseWhere: name, expr - Enumerator: items - FortranName: value - Threadsafe: - Depend: depends, items - Check: expr, value - CallStatement: expr - CallProtoArgument: specs - Pause: value - """ - self.block = block - print block.item - def analyze(self): - - pass - -def simple_main(): - import sys - from parsefortran import FortranParser - from readfortran import FortranFileReader - for filename in sys.argv[1:]: - reader = FortranFileReader(filename) - print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode)) - parser = FortranParser(reader) - block = parser.parse() - analyzer = FortranAnalyzer(block) - r = analyzer.analyze() - print r - -if __name__ == "__main__": - simple_main() Deleted: trunk/numpy/f2py/lib/base_classes.py =================================================================== --- trunk/numpy/f2py/lib/base_classes.py 2006-09-30 23:33:23 UTC (rev 3237) +++ trunk/numpy/f2py/lib/base_classes.py 2006-10-01 11:49:23 UTC (rev 3238) @@ -1,691 +0,0 @@ - -__all__ = ['Statement','BeginStatement','EndStatement'] - -import re -import sys -import copy -from readfortran import Line -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 - """ - 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 isempty(self): - for k in self._attributes.keys(): - v = getattr(self,k) - if v: return False - return True - - def __repr__(self): return self.torepr() - - def torepr(self, depth=-1, tab = ''): - if depth==0: return tab + self.__class__.__name__ - l = [self.__class__.__name__+':'] - ttab = tab + ' ' - for k in self._attributes.keys(): - v = getattr(self,k) - if v: - if isinstance(v,list): - l.append(ttab + '%s=<%s-list>' % (k,len(v))) - elif isinstance(v,dict): - l.append(ttab + '%s=' % (k,v.keys())) - else: - l.append(ttab + '%s=<%s>' % (k,type(v))) - return '\n'.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.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 get_bit_size(self): - typesize = self.typedecl.get_bit_size() - if self.is_pointer(): - # The size of pointer descriptor is compiler version dependent. Read: - # http://www.nersc.gov/vendor_docs/intel/f_ug1/pgwarray.htm - # https://www.cca-forum.org/pipermail/cca-fortran/2003-February/000123.html - # https://www.cca-forum.org/pipermail/cca-fortran/2003-February/000122.html - # On sgi descriptor size may be 128+ bits! - if self.is_array(): - wordsize = 4 # XXX: on a 64-bit system it is 8. - rank = len(self.bounds or self.dimension) - return 6 * wordsize + 12 * rank - return typesize - if self.is_array(): - size = reduce(lambda x,y:x*y,self.bounds or self.dimension,1) - if self.length: - size *= self.length - return size * typesize - if self.length: - return self.length * typesize - return typesize - - def get_typedecl(self): - if self.typedecl is None: - self.set_type(self.parent.get_type(self.name)) - return self.typedecl - - 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: - self.parent.warning(\ - 'variable %r already has type %s,'\ - ' resetting to %s' \ - % (self.name, self.typedecl.tostr(),typedecl.tostr())) - self.typedecl = typedecl - return - - 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 is_pointer(self): return 'POINTER' in self.attributes - - def is_array(self): return not not (self.bounds or self.dimension) - - 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() - if lattr.startswith('dimension'): - assert self.dimension is None, `self.dimension,attr` - l = attr[9:].lstrip() - assert l[0]+l[-1]=='()',`l` - 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.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, - upper = True) - 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: - if uattr not in self.known_attributes: - self.parent.warning('unknown attribute %r' % (attr)) - attributes.append(uattr) - return - - def __str__(self): - s = '' - typedecl = self.get_typedecl() - if typedecl is not None: - s += 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) + ' :: ' - 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 - - def analyze(self): - typedecl = self.get_typedecl() - return - -class ProgramBlock: - pass - -class Statement: - """ - Statement instance has attributes: - parent - Parent BeginStatement or FortranParser instance - item - Line instance containing the statement line - isvalid - boolean, when False, the Statement instance will be ignored - """ - modes = ['free90','fix90','fix77','pyf'] - _repr_attr_names = [] - - def __init__(self, parent, item): - self.parent = parent - if item is not None: - self.reader = item.reader - else: - self.reader = parent.reader - self.top = getattr(parent,'top',None) # the top of statement tree - self.item = item - - if isinstance(parent, ProgramBlock): - self.programblock = parent - elif isinstance(self, ProgramBlock): - self.programblock = self - elif hasattr(parent,'programblock'): - self.programblock = parent.programblock - else: - #self.warning('%s.programblock attribute not set.' % (self.__class__.__name__)) - pass - - # when a statement instance is constructed by error, set isvalid to False - self.isvalid = True - # 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 __repr__(self): - return self.torepr() - - def torepr(self, depth=-1,incrtab=''): - tab = incrtab + self.get_indent_tab() - clsname = self.__class__.__name__ - l = [tab + yellow_text(clsname)] - if depth==0: - return '\n'.join(l) - ttab = tab + ' ' - for n in self._repr_attr_names: - attr = getattr(self, n, None) - if not attr: continue - if hasattr(attr, 'torepr'): - r = attr.torepr(depht-1,incrtab) - else: - r = repr(attr) - l.append(ttab + '%s=%s' % (n, r)) - if self.item is not None: l.append(ttab + 'item=%r' % (self.item)) - if not self.isvalid: l.append(ttab + 'isvalid=%r' % (self.isvalid)) - if self.ignore: l.append(ttab + 'ignore=%r' % (self.ignore)) - if not self.a.isempty(): - l.append(ttab + 'a=' + self.a.torepr(depth-1,incrtab+' ').lstrip()) - return '\n'.join(l) - - def get_indent_tab(self,colon=None,deindent=False): - if self.reader.isfix: - tab = ' '*6 - else: - tab = '' - p = self.parent - while isinstance(p, Statement): - tab += ' ' - p = p.parent - if deindent: - tab = tab[:-2] - if self.item is None: - return tab - s = self.item.label - if colon is None: - if self.reader.isfix: - colon = '' - else: - colon = ':' - if s: - c = '' - if self.reader.isfix: - c = ' ' - tab = tab[len(c+s)+len(colon):] - if not tab: tab = ' ' - tab = c + s + colon + tab - return tab - - def format_message(self, kind, message): - if self.item is not None: - message = self.reader.format_message(kind, message, - self.item.span[0], self.item.span[1]) - else: - return message - 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.warning('nothing analyzed') - return - - def get_variable(self, name): - """ Return Variable instance of variable name. - """ - mth = getattr(self,'get_variable_by_name', self.parent.get_variable) - return mth(name) - - def get_type(self, name): - """ Return type declaration using implicit rules - for name. - """ - mth = getattr(self,'get_type_by_name', self.parent.get_type) - return mth(name) - - def get_type_decl(self, kind): - mth = getattr(self,'get_type_decl_by_kind', self.parent.get_type_decl) - return mth(kind) - - def get_provides(self): - """ Returns dictonary containing statements that block provides or None when N/A. - """ - return - -class BeginStatement(Statement): - """ - - BeginStatement instances have additional attributes: - name - blocktype - - Block instance has attributes: - content - list of Line or Statement instances - name - name of the block, unnamed blocks are named - with the line label - parent - Block or FortranParser instance - item - Line instance containing the block start statement - get_item, put_item - methods to retrive/submit Line instances - from/to Fortran reader. - isvalid - boolean, when False, the Block instance will be ignored. - - stmt_cls, end_stmt_cls - - """ - _repr_attr_names = ['blocktype','name'] + Statement._repr_attr_names - def __init__(self, parent, item=None): - - self.content = [] - self.get_item = parent.get_item # get line function - self.put_item = parent.put_item # put line function - if not hasattr(self, 'blocktype'): - self.blocktype = self.__class__.__name__.lower() - if not hasattr(self, 'name'): - # process_item may change this - self.name = '__'+self.blocktype.upper()+'__' - Statement.__init__(self, parent, item) - return - - def tostr(self): - return self.blocktype.upper() + ' '+ self.name - - def __str__(self): - l=[self.get_indent_tab(colon=':') + self.tostr()] - for c in self.content: - l.append(str(c)) - return '\n'.join(l) - - def torepr(self, depth=-1, incrtab=''): - tab = incrtab + self.get_indent_tab() - ttab = tab + ' ' - l=[Statement.torepr(self, depth=depth,incrtab=incrtab)] - if depth==0 or not self.content: - return '\n'.join(l) - l.append(ttab+'content:') - for c in self.content: - if isinstance(c,EndStatement): - l.append(c.torepr(depth-1,incrtab)) - else: - l.append(c.torepr(depth-1,incrtab + ' ')) - return '\n'.join(l) - - def process_item(self): - """ Process the line - """ - item = self.item - if item is None: return - self.fill() - return - - def fill(self, end_flag = False): - """ - Fills blocks content until the end of block statement. - """ - - mode = self.reader.mode - classes = self.get_classes() - self.classes = [cls for cls in classes if mode in cls.modes] - self.pyf_classes = [cls for cls in classes if 'pyf' in cls.modes] - - item = self.get_item() - while item is not None: - if isinstance(item, Line): - if self.process_subitem(item): - end_flag = True - break - item = self.get_item() - - if not end_flag: - self.warning('failed to find the end of block') - return - - def process_subitem(self, item): - """ - Check is item is blocks start statement, if it is, read the block. - - Return True to stop adding items to given block. - """ - line = item.get_line() - - # First check for the end of block - cls = self.end_stmt_cls - if cls.match(line): - stmt = cls(self, item) - if stmt.isvalid: - self.content.append(stmt) - return True - - if item.is_f2py_directive: - classes = self.pyf_classes - else: - classes = self.classes - - # Look for statement match - for cls in classes: - if cls.match(line): - stmt = cls(self, item) - if stmt.isvalid: - if not stmt.ignore: - self.content.append(stmt) - return False - # item may be cloned that changes the items line: - line = item.get_line() - - # Check if f77 code contains inline comments or other f90 - # constructs that got undetected by get_source_info. - if item.reader.isfix77: - i = line.find('!') - if i != -1: - message = item.reader.format_message(\ - 'WARNING', - 'no parse pattern found for "%s" in %r block'\ - ' maybe due to inline comment.'\ - ' Trying to remove the comment.'\ - % (item.get_line(),self.__class__.__name__), - item.span[0], item.span[1]) - # .. but at the expense of loosing the comment. - self.show_message(message) - newitem = item.copy(line[:i].rstrip()) - return self.process_subitem(newitem) - - # try fix90 statement classes - f77_classes = self.classes - classes = [] - for cls in self.get_classes(): - if 'fix90' in cls.modes and cls not in f77_classes: - classes.append(cls) - if classes: - message = item.reader.format_message(\ - 'WARNING', - 'no parse pattern found for "%s" in %r block'\ - ' maybe due to strict f77 mode.'\ - ' Trying f90 fix mode patterns..'\ - % (item.get_line(),self.__class__.__name__), - item.span[0], item.span[1]) - self.show_message(message) - - item.reader.set_mode(False, False) - self.classes = classes - - r = BeginStatement.process_subitem(self, item) - if r is None: - # restore f77 fix mode - self.classes = f77_classes - item.reader.set_mode(False, True) - else: - message = item.reader.format_message(\ - 'INFORMATION', - 'The f90 fix mode resolved the parse pattern issue.'\ - ' Setting reader to f90 fix mode.', - item.span[0], item.span[1]) - self.show_message(message) - # set f90 fix mode - self.classes = f77_classes + classes - self.reader.set_mode(False, False) - return r - - self.handle_unknown_item(item) - return - - def handle_unknown_item(self, item): - 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]) - self.show_message(message) - self.content.append(item) - #sys.exit() - return - - def analyze(self): - for stmt in self.content: - stmt.analyze() - return - -class EndStatement(Statement): - """ - END [ []] - - EndStatement instances have additional attributes: - name - blocktype - """ - _repr_attr_names = ['blocktype','name'] + Statement._repr_attr_names - - def __init__(self, parent, item): - if not hasattr(self, 'blocktype'): - self.blocktype = self.__class__.__name__.lower()[3:] - Statement.__init__(self, parent, item) - - def process_item(self): - item = self.item - line = item.get_line().replace(' ','')[3:] - blocktype = self.blocktype - if line.startswith(blocktype): - line = line[len(blocktype):].strip() - else: - if line: - # not the end of expected block - line = '' - self.isvalid = False - if line: - if not line==self.parent.name: - 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 - - def analyze(self): - return - - def get_indent_tab(self,colon=None,deindent=False): - return Statement.get_indent_tab(self, colon=colon, deindent=True) - - def __str__(self): - return self.get_indent_tab() + 'END %s %s'\ - % (self.blocktype.upper(),self.name or '') - Deleted: trunk/numpy/f2py/lib/block_statements.py =================================================================== --- trunk/numpy/f2py/lib/block_statements.py 2006-09-30 23:33:23 UTC (rev 3237) +++ trunk/numpy/f2py/lib/block_statements.py 2006-10-01 11:49:23 UTC (rev 3238) @@ -1,1149 +0,0 @@ -""" - -""" - -import re -import sys - -from base_classes import BeginStatement, EndStatement, Statement,\ - AttributeHolder, ProgramBlock -from readfortran import Line -from utils import filter_stmts, parse_bind, parse_result, AnalyzeError - -class HasImplicitStmt: - - a = AttributeHolder(implicit_rules = {}) - - def get_type_by_name(self, name): - implicit_rules = self.a.implicit_rules - if implicit_rules is None: - raise AnalyzeError,'Implicit rules mapping is null' - l = name[0].lower() - if implicit_rules.has_key(l): - return implicit_rules[l] - # default rules: - if l in 'ijklmn': - l = 'default_integer' - else: - l = 'default_real' - t = implicit_rules.get(l, None) - if t is None: - if l[8:]=='real': - implicit_rules[l] = t = Real(self, self.item.copy('real')) - else: - implicit_rules[l] = t = Integer(self, self.item.copy('integer')) - return t - - def topyf(self, tab=' '): - implicit_rules = self.a.implicit_rules - if implicit_rules is None: - return tab + 'IMPLICIT NONE\n' - items = {} - for c,t in implicit_rules.items(): - if c.startswith('default'): - continue - st = t.tostr() - if items.has_key(st): - items[st].append(c) - else: - items[st] = [c] - if not items: - return tab + '! default IMPLICIT rules apply\n' - s = 'IMPLICIT' - ls = [] - for st,l in items.items(): - l.sort() - ls.append(st + ' (%s)' % (', '.join(l))) - s += ' ' + ', '.join(ls) - return tab + s + '\n' - -class HasUseStmt: - - a = AttributeHolder(use = {}, - use_provides = {}) - - 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 topyf(self): - pass - -class HasVariables: - - a = AttributeHolder(variables = {}, - variable_names = [] # defines the order of declarations - ) - - def get_variable_by_name(self, name): - variables = self.a.variables - if variables.has_key(name): - var = variables[name] - else: - var = variables[name] = Variable(self, name) - self.a.variable_names.append(name) - return var - - def topyf(self,tab=''): - s = '' - for name, var in self.a.variables.items(): - s += tab + str(var) + '\n' - return s - -class HasTypeDecls: - - a = AttributeHolder(type_decls = {}) - - def topyf(self, tab=''): - s = '' - for name, stmt in self.a.type_decls.items(): - s += stmt.topyf(tab=' '+tab) - return s - - def get_type_decl_by_kind(self, kind): - type_decls = self.a.type_decls - type_decl = type_decls.get(kind, None) - if type_decl is None: - return self.get_entity(kind) - raise NotImplementedError,'get type_decl from use modules' - return type_decl - -class HasAttributes: - - known_attributes = [] - a = AttributeHolder(attributes = []) - - def topyf(self, tab=''): - s = '' - for attr in self.a.attributes: - s += tab + attr + '\n' - return s - - def is_private(self): - attributes = self.a.attributes - if 'PUBLIC' in attributes: return False - if 'PRIVATE' in attributes: return True - return - def is_public(self): return not self.is_private() - - def update_attributes(self,*attrs): - attributes = self.a.attributes - known_attributes = self.known_attributes - if len(attrs)==1 and isinstance(attrs[0],(tuple,list)): - attrs = attrs[0] - for attr in attrs: - uattr = attr.upper() - if uattr not in attributes: - if isinstance(known_attributes,(list, tuple)): - if uattr not in known_attributes: - self.warning('unknown attribute %r' % (attr)) - elif known_attributes(uattr): - self.warning('unknown attribute %r' % (attr)) - attributes.append(uattr) - return - -class HasModuleProcedures: - - a = AttributeHolder(module_procedures = []) - -# 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: - stmt.analyze() - return - - def get_classes(self): - return program_unit - - def process_subitem(self, item): - # MAIN block does not define start/end line conditions, - # so it should never end until all lines are read. - # However, sometimes F77 programs lack the PROGRAM statement, - # and here we fix that: - if self.reader.isfix77: - line = item.get_line() - if line=='end': - message = item.reader.format_message(\ - 'WARNING', - 'assuming the end of undefined PROGRAM statement', - item.span[0],item.span[1]) - print >> sys.stderr, message - p = Program(self) - p.content.extend(self.content) - p.content.append(EndProgram(p,item)) - self.content[:] = [p] - return - return BeginStatement.process_subitem(self, item) - - def topyf(self, tab=''): # XXXX - s = '' - for name, stmt in self.a.module.items(): - s += stmt.topyf() - for name, stmt in self.a.external_subprogram.items(): - s += stmt.topyf() - for name, stmt in self.a.blockdata.items(): - s += stmt.topyf() - return s -# Module - -class EndModule(EndStatement): - match = re.compile(r'end(\s*module\s*\w*|)\Z', re.I).match - -class Module(BeginStatement, HasAttributes, - HasImplicitStmt, HasUseStmt, HasVariables, - HasTypeDecls): - """ - MODULE - .. - END [MODULE [name]] - """ - match = re.compile(r'module\s*\w+\Z', re.I).match - end_stmt_cls = EndModule - - a = AttributeHolder(module_subprogram = {}, - module_provides = {}, # all symbols that are public and so - # can be imported via USE statement - # by other blocks - ) - - known_attributes = ['PUBLIC', 'PRIVATE'] - - def get_classes(self): - return access_spec + specification_part + module_subprogram_part - - def process_item(self): - name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip() - self.name = name - return BeginStatement.process_item(self) - - def get_provides(self): - return self.a.module_provides - - def analyze(self): - content = self.content[:] - - 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: - self.show_message('Not analyzed content: %s' % content) - - module_provides = self.a.module_provides - for name, var in self.a.variables.items(): - if var.is_public(): - if module_provides.has_key(name): - self.warning('module data object name conflict with %s, overriding.' % (name)) - module_provides[name] = var - - return - - def topyf(self, tab=''): - s = tab + 'MODULE '+self.name + '\n' - s += HasImplicitStmt.topyf(self, tab=tab+' ') - s += HasAttributesStmt.topyf(self, tab=tab+' ') - s += HasTypeDecls.topyf(self, tab=tab+' ') - s += HasVariables.topyf(self, tab=tab+' ') - s += tab + ' CONTAINS\n' - for name, stmt in self.a.module_subprogram.items(): - s += stmt.topyf(tab=tab+' ') - s += tab + 'END MODULE ' + self.name + '\n' - return s - -# Python Module - -class EndPythonModule(EndStatement): - match = re.compile(r'end(\s*python\s*module\s*\w*|)\Z', re.I).match - -class PythonModule(BeginStatement, HasImplicitStmt, HasUseStmt): - """ - PYTHON MODULE - .. - END [PYTHON MODULE [name]] - """ - modes = ['pyf'] - match = re.compile(r'python\s*module\s*\w+\Z', re.I).match - end_stmt_cls = EndPythonModule - - def get_classes(self): - return [Interface, Function, Subroutine, Module] - - def process_item(self): - self.name = self.item.get_line().replace(' ','')\ - [len(self.blocktype):].strip() - return BeginStatement.process_item(self) - -# Program - -class EndProgram(EndStatement): - """ - END [PROGRAM [name]] - """ - match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match - -class Program(BeginStatement, ProgramBlock, - HasAttributes, # XXX: why Program needs .attributes? - HasImplicitStmt, HasUseStmt): - """ PROGRAM [name] - """ - match = re.compile(r'program\s*\w*\Z', re.I).match - end_stmt_cls = EndProgram - - def get_classes(self): - return specification_part + execution_part + internal_subprogram_part - - def process_item(self): - if self.item is not None: - name = self.item.get_line().replace(' ','')\ - [len(self.blocktype):].strip() - if name: - self.name = name - return BeginStatement.process_item(self) - -# BlockData - -class EndBlockData(EndStatement): - """ - END [ BLOCK DATA [ ] ] - """ - match = re.compile(r'end(\s*block\s*data\s*\w*|)\Z', re.I).match - blocktype = 'blockdata' - -class BlockData(BeginStatement, HasImplicitStmt, HasUseStmt, - HasVariables): - """ - BLOCK DATA [ ] - """ - end_stmt_cls = EndBlockData - match = re.compile(r'block\s*data\s*\w*\Z', re.I).match - - def process_item(self): - self.name = self.item.get_line()[5:].lstrip()[4:].lstrip() - return BeginStatement.process_item(self) - - def get_classes(self): - return specification_part - -# Interface - -class EndInterface(EndStatement): - match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match - blocktype = 'interface' - -class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, - HasModuleProcedures - ): - """ - INTERFACE [] | ABSTRACT INTERFACE - END INTERFACE [] - - = - | OPERATOR ( ) - | ASSIGNMENT ( = ) - | - = READ ( FORMATTED ) - | READ ( UNFORMATTED ) - | WRITE ( FORMATTED ) - | WRITE ( UNFORMATTED ) - - """ - modes = ['free90', 'fix90', 'pyf'] - match = re.compile(r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z',re.I).match - end_stmt_cls = EndInterface - blocktype = 'interface' - - a = AttributeHolder(interface_provides = {}) - - def get_classes(self): - return intrinsic_type_spec + interface_specification - - def process_item(self): - line = self.item.get_line() - self.isabstract = line.startswith('abstract') - if self.isabstract: - self.generic_spec = '' - else: - self.generic_spec = line[len(self.blocktype):].strip() - self.name = self.generic_spec # XXX - return BeginStatement.process_item(self) - - def tostr(self): - if self.isabstract: - return 'ABSTRACT INTERFACE' - return 'INTERFACE '+ str(self.generic_spec) - - def get_provides(self): - return self.a.interface_provides - - def analyze(self): - content = self.content[:] - - while content: - stmt = content.pop(0) - if isinstance(stmt, self.end_stmt_cls): - break - stmt.analyze() - assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__` - if content: - self.show_message('Not analyzed content: %s' % content) - - parent_provides = self.parent.get_provides() - if parent_provides is not None: - if self.is_public(): - if parent_provides.has_key(self.name): - self.warning('interface name conflict with %s, overriding.' % (self.name)) - parent_provides[self.name] = self - - return - -# Subroutine - -class SubProgramStatement(BeginStatement, ProgramBlock, - HasImplicitStmt, HasAttributes, - HasUseStmt, - HasVariables, HasTypeDecls - ): - """ - [ ] [ ( ) ] [ ] - """ - known_attributes = ['PUBLIC', 'PRIVATE'] - - a = AttributeHolder(internal_subprogram = {}) - - def process_item(self): - clsname = self.__class__.__name__.lower() - item = self.item - line = item.get_line() - m = self.match(line) - i = line.find(clsname) - assert i!=-1,`line` - self.prefix = line[:i].rstrip() - self.name = line[i:m.end()].lstrip()[len(clsname):].strip() - line = line[m.end():].lstrip() - args = [] - if line.startswith('('): - i = line.find(')') - assert i!=-1,`line` - line2 = item.apply_map(line[:i+1]) - for a in line2[1:-1].split(','): - a=a.strip() - if not a: continue - args.append(a) - line = line[i+1:].lstrip() - 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) - - def tostr(self): - clsname = self.__class__.__name__.upper() - s = '' - if self.prefix: - s += self.prefix + ' ' - if self.typedecl is not None: - assert isinstance(self, Function),`self.__class__.__name__` - s += self.typedecl.tostr() + ' ' - s += clsname - 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[:] - - if self.prefix: - self.update_attributes(prefix.upper().split()) - - 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): - var = variables[self.result] = Variable(self, self.result) - if self.typedecl is not None: - var.set_type(self.typedecl) - - 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, self.end_stmt_cls): - continue - else: - stmt.analyze() - - if content: - self.show_message('Not analyzed content: %s' % content) - - parent_provides = self.parent.get_provides() - if parent_provides is not None: - if self.is_public(): - if parent_provides.has_key(self.name): - self.warning('module subprogram name conflict with %s, overriding.' % (self.name)) - parent_provides[self.name] = self - - return - - def topyf(self, tab=''): - s = tab + self.__class__.__name__.upper() - s += ' ' + self.name + ' (%s)' % (', '.join(self.args)) - if isinstance(self, Function) and self.result != self.name: - s += ' RESULT (%s)' % (self.result) - s += '\n' - s += HasImplicitStmt.topyf(self, tab=tab+' ') - s += HasTypeDecls.topyf(self, tab=tab+' ') - s += HasVariables.topyf(self, tab=tab+' ') - s += tab + 'END ' + self.__class__.__name__.upper() + ' ' + self.name + '\n' - return s - -class EndSubroutine(EndStatement): - """ - END [SUBROUTINE [name]] - """ - match = re.compile(r'end(\s*subroutine\s*\w*|)\Z', re.I).match - - -class Subroutine(SubProgramStatement): - """ - [ ] SUBROUTINE [ ( [ ] ) [ ]] - """ - end_stmt_cls = EndSubroutine - match = re.compile(r'(recursive|pure|elemental|\s)*subroutine\s*\w+', re.I).match - _repr_attr_names = ['prefix','bind','suffix','args'] + Statement._repr_attr_names - -# Function - -class EndFunction(EndStatement): - """ - END [FUNCTION [name]] - """ - match = re.compile(r'end(\s*function\s*\w*|)\Z', re.I).match - -class Function(SubProgramStatement): - """ - [ ] FUNCTION ( [] ) [] - = [ ]... - = - | RECURSIVE | PURE | ELEMENTAL - = [ RESULT ( ) ] - | RESULT ( ) [ ] - """ - end_stmt_cls = EndFunction - match = re.compile(r'(recursive|pure|elemental|\s)*function\s*\w+', re.I).match - _repr_attr_names = ['prefix','bind','suffix','args','typedecl'] + Statement._repr_attr_names - -# Handle subprogram prefixes - -class SubprogramPrefix(Statement): - """ - ... - """ - match = re.compile(r'(pure|elemental|recursive|\s)+\b',re.I).match - def process_item(self): - line = self.item.get_line() - m = self.match(line) - prefix = line[:m.end()].rstrip() - rest = self.item.get_line()[m.end():].lstrip() - if rest: - self.parent.put_item(self.item.copy(prefix)) - self.item.clone(rest) - self.isvalid = False - return - if self.parent.__class__ not in [Function, Subroutine]: - self.isvalid = False - return - prefix = prefix + ' ' + self.parent.prefix - self.parent.prefix = prefix.strip() - self.ignore = True - return - -# SelectCase - -class EndSelect(EndStatement): - match = re.compile(r'end\s*select\s*\w*\Z', re.I).match - blocktype = 'select' - -class Select(BeginStatement): - """ - [ : ] SELECT CASE ( ) - - """ - match = re.compile(r'select\s*case\s*\(.*\)\Z',re.I).match - end_stmt_cls = EndSelect - name = '' - def tostr(self): - return 'SELECT CASE ( %s )' % (self.expr) - def process_item(self): - self.expr = self.item.get_line()[6:].lstrip()[4:].lstrip()[1:-1].strip() - self.name = self.item.label - return BeginStatement.process_item(self) - - def get_classes(self): - return [Case] + execution_part_construct - -# Where - -class EndWhere(EndStatement): - """ - END WHERE [ ] - """ - match = re.compile(r'end\s*\where\s*\w*\Z',re.I).match - - -class Where(BeginStatement): - """ - [ : ] WHERE ( ) - = - """ - 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 - -# Forall - -class EndForall(EndStatement): - """ - END FORALL [ ] - """ - match = re.compile(r'end\s*forall\s*\w*\Z',re.I).match - -class Forall(BeginStatement): - """ - [ : ] FORALL - [ ]... - = - | - | - | - | - = ( [ , ] ) - = = : [ : ] - = - = | - """ - end_stmt_cls = EndForall - match = re.compile(r'forarr\s*\(.*\)\Z',re.I).match - name = '' - def process_item(self): - self.specs = self.item.get_line()[6:].lstrip()[1:-1].strip() - return BeginStatement.process_item(self) - def tostr(self): - return 'FORALL (%s)' % (self.specs) - def get_classes(self): - return [GeneralAssignment, WhereStmt, WhereConstruct, - ForallConstruct, ForallStmt] - -ForallConstruct = Forall - -# IfThen - -class EndIfThen(EndStatement): - """ - END IF [ ] - """ - match = re.compile(r'end\s*if\s*\w*\Z', re.I).match - blocktype = 'if' - -class IfThen(BeginStatement): - """ - [ :] IF ( ) THEN - - IfThen instance has the following attributes: - expr - """ - - match = re.compile(r'if\s*\(.*\)\s*then\Z',re.I).match - end_stmt_cls = EndIfThen - name = '' - - def tostr(self): - return 'IF (%s) THEN' % (self.expr) - - def process_item(self): - item = self.item - line = item.get_line()[2:-4].strip() - assert line[0]=='(' and line[-1]==')',`line` - self.expr = line[1:-1].strip() - self.name = item.label - return BeginStatement.process_item(self) - - def get_classes(self): - return [Else, ElseIf] + execution_part_construct - -class If(BeginStatement): - """ - IF ( ) action-stmt - """ - - match = re.compile(r'if\s*\(').match - - def process_item(self): - item = self.item - mode = self.reader.mode - classes = self.get_classes() - classes = [cls for cls in classes if mode in cls.modes] - - line = item.get_line()[2:] - i = line.find(')') - expr = line[1:i].strip() - line = line[i+1:].strip() - if line.lower()=='then': - self.isvalid = False - return - self.expr = expr[1:-1] - - if not line: - newitem = self.get_item() - else: - newitem = item.copy(line) - newline = newitem.get_line() - for cls in classes: - if cls.match(newline): - stmt = cls(self, newitem) - if stmt.isvalid: - self.content.append(stmt) - return - if not line: - self.put_item(newitem) - self.isvalid = False - return - - def tostr(self): - assert len(self.content)==1,`self.content` - return 'IF (%s) %s' % (self.expr, str(self.content[0]).lstrip()) - - def __str__(self): - return self.get_indent_tab(colon=':') + self.tostr() - - def get_classes(self): - return action_stmt - -# Do - -class EndDo(EndStatement): - """ - END DO [ ] - """ - match = re.compile(r'end\s*do\s*\w*\Z', re.I).match - blocktype = 'do' - -class Do(BeginStatement): - """ - [ : ] DO label [loopcontrol] - [ : ] DO [loopcontrol] - - """ - - match = re.compile(r'do\b\s*\d*',re.I).match - item_re = re.compile(r'do\b\s*(?P