diff options
Diffstat (limited to 'numpy/f2py/lib/block.py')
-rw-r--r-- | numpy/f2py/lib/block.py | 368 |
1 files changed, 177 insertions, 191 deletions
diff --git a/numpy/f2py/lib/block.py b/numpy/f2py/lib/block.py index b9bafdcff..09d39d0e2 100644 --- a/numpy/f2py/lib/block.py +++ b/numpy/f2py/lib/block.py @@ -11,238 +11,241 @@ Created: May 2006 """ -__all__ = ['Block','Module','PythonModule','Interface', - 'Subroutine','Function','Type'] +__all__ = ['Block','ModuleBlock','PythonModuleBlock','InterfaceBlock', + 'SubroutineBlock','FunctionBlock','TypeBlock', 'ProgramBlock', + 'BlockDataBlock','DoBlock','IfThenBlock','SelectBlock', + 'StatementBlock'] import re import sys from readfortran import Line -from splitline import split2, string_replace_map +from splitline import string_replace_map +from stmt import statements, end_stmts, block_stmts class Block: - - classes = [] - end_re = re.compile(r'\s*end\s*\Z', re.I) - - def __init__(self, parent): + """ + 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 instaces + from/to Fortran reader. + isvalid - boolean, when False, the Block instance will be ignored. + """ + + classes = {} + + end_re = re.compile(r'end\Z', re.I).match + + def __init__(self, parent, item = None): + """ + parent - Block or FortanParser instance having the + following attributes: reader, get_item, put_item + item - Line instance containing the beginning of block + statement. + """ self.parent = parent - self.isfix77 = parent.isfix77 self.reader = parent.reader - self.get_item = parent.get_item - self.put_item = parent.put_item - self.lower = not self.reader.ispyf + self.get_item = parent.get_item # get line function + self.put_item = parent.put_item # put line function self.content = [] self.name = None + self.item = item + if item is None: + return + stmt = self.stmt_cls(self, item) + self.isvalid = stmt.isvalid + if self.isvalid: + self.content.append(stmt) + self.name = stmt.name + self.fill() # read block content + def get_name(self): - if self.__class__ is Block: return '__MAIN__' - if self.name is None: return '' + if self.__class__ is Block: return '__F2PY_MAIN__' + if not hasattr(self,'name') or self.name is None: return '' return self.name def __str__(self): - tab = '' - p = self.parent - while isinstance(p, Block): - tab += ' ' - p = p.parent - name = self.get_name() - l=[tab+'begin '+self.__class__.__name__ +' '+ name] + l=[] for c in self.content: l.append(str(c)) - l.append(tab+'end '+self.__class__.__name__ +' '+ name) return '\n'.join(l) - def isenditem(self, item): - line,sline = split2(item.get_line()) - if sline: return False # end statement never contains strings + def isstmt(self, item): + """ + Check is item is blocks start statement, if it is, read the block. + """ + line = item.get_line() + mode = item.reader.mode + classes = self.classes[mode] + statements[self.__class__.__name__] + for cls in classes: + if issubclass(cls, Block): + match_cmd = cls.stmt_cls.start_re + else: + match_cmd = cls.start_re + if match_cmd(line): + subblock = cls(self, item) + if subblock.isvalid: + self.content.append(subblock) + return True + return False + + def isendblock(self, item): + line = item.get_line() if self.__class__ is Block: # 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.isfix77: - m = self.end_re.match(line) + if self.reader.isfix77: + m = self.end_re(line) if m: message = self.reader.format_message(\ 'WARNING', 'assuming the end of undefined PROGRAM statement', item.span[0],item.span[1]) print >> sys.stderr, message - i = Line('program UNDEFINED',(0,0),None,self.reader) - p = Program(self,Program.start_re.match(i.get_line()),i) + l = Line('program UNDEFINED',(0,0),None,self.reader) + p = Program(self,l) p.content.extend(self.content) self.content[:] = [p] - return None + return True return False - m = self.end_re.match(line) - if not m: return False - # check if the block start name matches with the block end name - - if m.groupdict().has_key('name'): - end_name = m.group('name') - if end_name: end_name = end_name.strip() - name = self.get_name() - if end_name and name != end_name: - message = self.reader.format_message(\ - 'WARNING', - 'expected the end of %r block but got end of %r'\ - % (name, end_name), - item.span[0],item.span[1]) - print >> sys.stderr, message - return True - - def isblock(self, item): - line = item.get_line() - for cls in self.classes: - m = cls.start_re.match(line) - if m: - subblock = cls(self, m, item) - self.content.append(subblock) - subblock.fill() + cls = self.end_stmt_cls + if cls.start_re(line): + stmt = cls(self, item) + if stmt.isvalid: + self.content.append(stmt) return True return False def fill(self): + """ + Fills blocks content until the end of block statement. + """ end_flag = self.__class__ is Block - item = startitem = self.get_item() + item = self.get_item() while item is not None: if isinstance(item, Line): # handle end of a block - flag = self.isenditem(item) - if flag: # end of block + if self.isendblock(item): end_flag = True break - if flag is None: # fixing the end of undefined start - item = self.get_item() - continue - # handle subblocks - if self.isblock(item): - item = self.get_item() - continue - # line contains something else - self.content.append(item) + elif not self.isstmt(item): + # put unknown item's to content. + self.content.append(item) item = self.get_item() if not end_flag: message = self.reader.format_message(\ 'WARNING', - 'failed to find the end of block', + 'failed to find the end of block for %s'\ + % (self.__class__.__name__), self.item.span[0],self.item.span[1]) print >> sys.stderr, message sys.stderr.flush() return -class CodeBlock(Block): - def __init__(self, parent, start_re_match, item): - Block.__init__(self, parent) - self.name = start_re_match.group('name') - self.item = item - -class Program(CodeBlock): - classes = [] - start_re = re.compile(r'\s*program\s*((?P<name>\w+)|)', re.I) - end_re = re.compile(r'\s*end(\s*program(\s*(?P<name>\w+)|)|)\s*\Z', re.I) - - -class Module(CodeBlock): - classes = [] - start_re = re.compile(r'\s*module\s*(?P<name>\w+)\s*\Z', re.I) - end_re = re.compile(r'\s*end(\s*module(\s*(?P<name>\w+)|)|)\s*\Z', re.I) - def __init__(self, parent, start_re_match, item): - Block.__init__(self, parent) - self.name = start_re_match.group('name') - self.item = item - -class Interface(CodeBlock): - classes = [] - start_re = re.compile(r'\s*interface(\s*(?P<name>\w+)|)', re.I) - end_re = re.compile(r'\s*end(\s*interface(\s*(?P<name>\w+)|)|)\s*\Z', re.I) - -class PythonModule(CodeBlock): - classes = [] - start_re = re.compile(r'\s*python\s*module\s*(?P<name>\w+)', re.I) - end_re = re.compile(r'\s*end(\s*python\s*module(\s*(?P<name>\w+)|)|)\s*\Z', re.I) +class ProgramUnit(Block): + """ + <main program> + <external subprogram (function | subroutine)> + <module> + <block data> + """ + +class ProgramBlock(ProgramUnit): + """ + program [name] + <specification part> + <execution part> + <internal subprogram part> + end [program [name]] + """ + classes = {} -class Subroutine(CodeBlock): - classes = [] - start_re = re.compile(r'\s*subroutine\s*(?P<name>\w+)', re.I) - end_re = re.compile(r'\s*end(\s*subroutine(\s*(?P<name>\w+)|)|)\s*\Z', re.I) - -class Function(CodeBlock): - classes = [] - start_re = re.compile(r'\s*(?P<prefix>[\w,\s=()]*)\s*function\s*(?P<name>\w+)', re.I) - end_re = re.compile(r'\s*end(\s*function(\s*(?P<name>\w+)|)|)\s*\Z') - -class Type(CodeBlock): - classes = [] - start_re = re.compile(r'\s*type(?!\s*\()(.*::|)\s*(?P<name>\w+)\s*\Z', re.I) - end_re = re.compile(r'\s*end(\s*type(\s*(?P<name>\w+)|)|)\s*\Z', re.I) +class ModuleBlock(ProgramUnit): + """ + module <name> + <specification part> + <module subprogram part> + end [module [name]] + """ + classes = {} + +class BlockDataBlock(ProgramUnit): + """ + block data [name] + end [block data [name]] + """ + classes = {} + +class InterfaceBlock(ProgramUnit): + """ + abstract interface | interface [<generic-spec>] + <interface specification> + end interface [<generic spec>] + """ + classes = {} + +class PythonModuleBlock(ProgramUnit): + """ + python module <name> + .. + end [python module [<name>]] + """ + +class SubroutineBlock(ProgramUnit): + """ + [prefix] subroutine <name> [ ( [<dummy-arg-list>] ) [<proc-language-binding-spec>]] + <specification-part> + <execution-part> + <internal-subprogram part> + end [subroutine [name]] + """ + classes = {} + +class FunctionBlock(ProgramUnit): + classes = {} + +class TypeBlock(Block): + """ + type [[type-attr-spec-list] ::] <name> [(type-param-name-list)] + <type-param-def-stmt> + <private-or-sequence> + <component-part> + <type-bound-procedure-part> + end type [name] + """ + classes = {} class StatementBlock(Block): - classes = [] - - def __init__(self, parent, start_re_match, item): - Block.__init__(self, parent) - self.item = item - - def isenditem(self, item): - line,sline = split2(item.get_line()) - if sline: return False # end statement never contains strings - m = self.end_re.match(line) - if not m: return False - # check if the block start name matches with the block end name - if m.groupdict().has_key('name'): - end_name = m.group('name') - if end_name: end_name = end_name.strip() - name = self.get_name() - if end_name and name != end_name: - message = self.reader.format_message(\ - 'WARNING', - 'expected the end of %r block but got end of %r'\ - % (name, end_name), - item.span[0],item.span[1]) - print >> sys.stderr, message - return True - - def fill(self): - item = self.get_item() - while item is not None: - if isinstance(item, Line): - # handle end of a block - flag = self.isenditem(item) - if flag: # end of block - break - # handle subblocks - if self.isblock(item): - item = self.get_item() - continue - - # line contains something else - self.content.append(item) - item = self.get_item() - if item is None: - message = self.reader.format_message(\ - 'WARNING', - 'failed to find the end of block', - self.item.span[0],self.item.span[1]) - print >> sys.stderr, message - sys.stderr.flush() - return - + """ + <start stmt-block> + <statements> + <end stmt-block> + """ + classes = {} + class DoBlock(StatementBlock): - start_re = re.compile(r'\s*do\b\s*(?P<label>\d*)', re.I) - end_re = re.compile(r'\s*end\s*do(\s*(?P<name>.*)|)\s*\Z', re.I) - def __init__(self, parent, start_re_match, item): - StatementBlock.__init__(self, parent, start_re_match, item) - label = start_re_match.group('label').strip() - if label.endswith(':'): label = label[:-1].strip() + begin_re = re.compile(r'do\b\s*(?P<label>\d*)', re.I).match + + def __init__(self, parent, item): + label = self.begin_re(item.get_line()).group('label').strip() self.endlabel = label - self.name = item.label + StatementBlock.__init__(self, parent, item) - def isenditem(self, item): + def isendblock(self, item): if self.endlabel: + # Handle: + # do 1, i=1,n + # .. + # 1 continue if item.label==self.endlabel: # item may contain computational statemets self.content.append(item) @@ -250,31 +253,14 @@ class DoBlock(StatementBlock): self.put_item(item) return True else: - return StatementBlock.isenditem(self, item) + return StatementBlock.isendblock(self, item) return False class IfThenBlock(StatementBlock): - start_re = re.compile(r'\s*if\b.*?\bthen\s*\Z', re.I) - #start_re = re.compile(r'\s*if\b', re.I) - end_re = re.compile(r'\s*end\s*if(\s*(?P<name>.*)|)\s*\Z', re.I) + pass - def __init__(self, parent, start_re_match, item): - StatementBlock.__init__(self, parent, start_re_match, item) - self.name = item.label - - -# Initialize classes lists - -basic_blocks = [Program,PythonModule,Module,Interface,Subroutine,Function,Type] -stmt_blocks = [DoBlock,IfThenBlock] +class SelectBlock(StatementBlock): -Block.classes.extend(basic_blocks + stmt_blocks) -Module.classes.extend(Block.classes[1:]) -PythonModule.classes.extend(Module.classes) -Interface.classes.extend(Block.classes[1:]) -Subroutine.classes.extend(Block.classes[1:]) -Function.classes.extend(Subroutine.classes) -Type.classes.extend(Block.classes[3:]) + pass -StatementBlock.classes.extend(stmt_blocks) |