diff options
author | Robert Kern <robert.kern@gmail.com> | 2008-07-03 19:57:24 +0000 |
---|---|---|
committer | Robert Kern <robert.kern@gmail.com> | 2008-07-03 19:57:24 +0000 |
commit | 484c100392601f4942ceecbedf32e6df0201d473 (patch) | |
tree | 5e5a58b30a39bd1b5481333ae4a4b9c34e466841 /numpy/f2py/lib/parser/base_classes.py | |
parent | 0c817a5d51c2c16db9df5c015ff846002d991d74 (diff) | |
download | numpy-484c100392601f4942ceecbedf32e6df0201d473.tar.gz |
Removing G3 f2py code. Development has moved to https://launchpad.net/f2py/
Diffstat (limited to 'numpy/f2py/lib/parser/base_classes.py')
-rw-r--r-- | numpy/f2py/lib/parser/base_classes.py | 819 |
1 files changed, 0 insertions, 819 deletions
diff --git a/numpy/f2py/lib/parser/base_classes.py b/numpy/f2py/lib/parser/base_classes.py deleted file mode 100644 index 68ea9c24a..000000000 --- a/numpy/f2py/lib/parser/base_classes.py +++ /dev/null @@ -1,819 +0,0 @@ -""" ------ -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 <pearu@cens.ioc.ee> -Created: May 2006 ------ -""" - -__all__ = ['Statement','BeginStatement','EndStatement', 'Variable', - 'AttributeHolder','ProgramBlock'] - -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=<dict with keys %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 - - # after calling analyze the following additional attributes are set: - # .is_array: - # rank - # shape - return - - def __repr__(self): - l = [] - for a in ['name','typedecl','dimension','bounds','length','attributes','intent','bind','check','init']: - v = getattr(self,a) - if v: - l.append('%s=%r' % (a,v)) - return 'Variable: ' + ', '.join(l) - - 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())) - assert typedecl is not None - 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_intent_in(self): - if not self.intent: return True - if 'HIDE' in self.intent: return False - if 'INPLACE' in self.intent: return False - if 'IN' in self.intent: return True - if 'OUT' in self.intent: return False - if 'INOUT' in self.intent: return False - if 'OUTIN' in self.intent: return False - return True - - def is_intent_inout(self): - if not self.intent: return False - if 'INOUT' in self.intent: - if 'IN' in self.intent or 'HIDE' in self.intent or 'INPLACE' in self.intent: - self.warning('INOUT ignored in INPUT(%s)' % (', '.join(self.intent))) - return False - return True - return False - - def is_intent_hide(self): - if not self.intent: return False - if 'HIDE' in self.intent: return True - if 'OUT' in self.intent: - return 'IN' not in self.intent and 'INPLACE' not in self.intent and 'INOUT' not in self.intent - return False - - def is_intent_inplace(self): return self.intent and 'INPLACE' in self.intent - def is_intent_out(self): return self.intent and 'OUT' in self.intent - def is_intent_c(self): return self.intent and 'C' in self.intent - def is_intent_cache(self): return self.intent and 'CACHE' in self.intent - def is_intent_copy(self): return self.intent and 'COPY' in self.intent - def is_intent_overwrite(self): return self.intent and 'OVERWRITE' in self.intent - def is_intent_callback(self): return self.intent and 'CALLBACK' in self.intent - def is_intent_aux(self): return self.intent and 'AUX' in self.intent - - 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 and 'REQUIRED' not in self.attributes and not self.is_intent_hide() - def is_required(self): return self.is_optional() and not self.is_intent_hide() - def is_pointer(self): return 'POINTER' in self.attributes - - def is_array(self): return not not (self.bounds or self.dimension) - def is_scalar(self): return not self.is_array() - - 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([':'.join(spec) for spec in 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 get_array_spec(self): - assert self.is_array(),'array_spec is available only for arrays' - if self.bounds: - if self.dimension: - self.parent.warning('both bounds=%r and dimension=%r are defined, ignoring dimension.' % (self.bounds, self.dimension)) - array_spec = self.bounds - else: - array_spec = self.dimension - return array_spec - - def is_deferred_shape_array(self): - if not self.is_array(): return False - return self.is_allocatable() or self.is_pointer() - - def is_assumed_size_array(self): - if not self.is_array(): return False - return self.get_array_spec()[-1][-1]=='*' - - def is_assumed_shape_array(self): - if not self.is_array(): return False - if self.is_deferred_shape_array(): return False - for spec in self.get_array_spec(): - if not spec[-1]: return True - return False - - def is_explicit_shape_array(self): - if not self.is_array(): return False - if self.is_deferred_shape_array(): return False - for spec in self.get_array_spec(): - if not spec[-1] or spec[-1] == '*': return False - return True - - def is_allocatable_array(self): - return self.is_array() and self.is_allocatable() - - def is_array_pointer(self): - return self.is_array() and self.is_pointer() - - def analyze(self): - typedecl = self.get_typedecl() - if self.is_array(): - array_spec = self.get_array_spec() - self.rank = len(array_spec) - if self.is_deferred_shape_array(): # a(:,:) - pass - elif self.is_explicit_shape_array(): - shape = [] - for spec in array_spec: - if len(spec)==1: - shape.append(spec[0]) - else: - shape.append(spec[1]-spec[0]) - self.shape = shape - 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(depth-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,isfix=None): - if isfix is None: isfix = self.reader.isfix - if 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 isfix: - colon = '' - else: - colon = ':' - if s: - c = '' - if isfix: - c = ' ' - tab = tab[len(c+s)+len(colon):] - if not tab: tab = ' ' - tab = c + s + colon + tab - return tab - - def __str__(self): - return self.tofortran() - - def asfix(self): - lines = [] - for line in self.tofortran(isfix=True).split('\n'): - if len(line)>72 and line[0]==' ': - lines.append(line[:72]+'&\n &') - line = line[72:] - while len(line)>66: - lines.append(line[:66]+'&\n &') - line = line[66:] - lines.append(line+'\n') - else: lines.append(line+'\n') - return ''.join(lines).replace('\n &\n','\n') - - 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): - """ <blocktype> <name> - - 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 tofortran(self, isfix=None): - l=[self.get_indent_tab(colon=':', isfix=isfix) + self.tostr()] - for c in self.content: - l.append(c.tofortran(isfix=isfix)) - 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 [<blocktype> [<name>]] - - 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.lower().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,isfix=None): - return Statement.get_indent_tab(self, colon=colon, deindent=True,isfix=isfix) - - def tofortran(self, isfix=None): - return self.get_indent_tab(isfix=isfix) + 'END %s %s'\ - % (self.blocktype.upper(),self.name or '') |