diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-07-04 12:12:47 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-07-04 12:12:47 +0000 |
commit | a8672c2c5e1fe4ae0c51805aa1eed5d736a5eedf (patch) | |
tree | b081bf1ae86d4b0f734157e2e7810c8fb43568b0 /numpy/f2py/lib/base_classes.py | |
parent | 17d8921d6d37745e01601fc19497ae2b4029b10c (diff) | |
download | numpy-a8672c2c5e1fe4ae0c51805aa1eed5d736a5eedf.tar.gz |
Working on Fortran analyzer.
Diffstat (limited to 'numpy/f2py/lib/base_classes.py')
-rw-r--r-- | numpy/f2py/lib/base_classes.py | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/numpy/f2py/lib/base_classes.py b/numpy/f2py/lib/base_classes.py index cdae17f03..21aa63b8e 100644 --- a/numpy/f2py/lib/base_classes.py +++ b/numpy/f2py/lib/base_classes.py @@ -3,8 +3,155 @@ __all__ = ['Statement','BeginStatement','EndStatement'] import re import sys +import copy from readfortran import Line +from utils import split_comma, specs_split_comma +class AttributeHolder: + # copied from symbolic.base module + """ + Defines a object with predefined attributes. Only those attributes + are allowed that are specified as keyword arguments of a constructor. + When an argument is callable then the corresponding attribute will + be read-only and set by the value the callable object returns. + """ + def __init__(self, **kws): + self._attributes = {} + self._readonly = [] + for k,v in kws.items(): + self._attributes[k] = v + if callable(v): + self._readonly.append(k) + return + + def __getattr__(self, name): + if name not in self._attributes: + raise AttributeError,'%s instance has no attribute %r, '\ + 'expected attributes: %s' \ + % (self.__class__.__name__,name, + ','.join(self._attributes.keys())) + value = self._attributes[name] + if callable(value): + value = value() + self._attributes[name] = value + return value + + def __setattr__(self, name, value): + if name in ['_attributes','_readonly']: + self.__dict__[name] = value + return + if name in self._readonly: + raise AttributeError,'%s instance attribute %r is readonly' \ + % (self.__class__.__name__, name) + if name not in self._attributes: + raise AttributeError,'%s instance has no attribute %r, '\ + 'expected attributes: %s' \ + % (self.__class__.__name__,name,','.join(self._attributes.keys())) + self._attributes[name] = value + + def __repr__(self): + l = [] + for k in self._attributes.keys(): + v = getattr(self,k) + l.append('%s=%r' % (k,v)) + return '%s(%s)' % (self.__class__.__name__,', '.join(l)) + + def todict(self): + d = {} + for k in self._attributes.keys(): + v = getattr(self, k) + d[k] = v + return d + +def get_base_classes(cls): + bases = () + for c in cls.__bases__: + bases += get_base_classes(c) + return bases + cls.__bases__ + (cls,) + +class Variable: + """ + Variable instance has attributes: + name + typedecl + dimension + attributes + intent + parent - Statement instances defining the variable + """ + def __init__(self, parent, name): + self.parent = parent + self.name = name + self.typedecl = None + self.dimension = None + self.attributes = [] + self.intent = None + self.bind = [] + self.check = [] + return + + def set_type(self, typedecl): + if self.typedecl is not None: + if not self.typedecl==typedecl: + message = 'Warning: variable %r already has type %s' \ + % (self.name, self.typedecl.tostr()) + message += '.. resetting to %s' % (typedecl.tostr()) + self.parent.show_message(message) + self.typedecl = typedecl + return + + def update(self, attrs): + attributes = self.attributes + for attr in attrs: + lattr = attr.lower() + uattr = attr.upper() + if lattr.startswith('dimension'): + assert self.dimension is None, `self.dimension,attr` + l = attr[9:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.dimension = split_comma(l[1:-1].strip(), self.parent.item) + continue + if lattr.startswith('intent'): + l = attr[6:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.intent = intent = [] + for i in split_comma(l[1:-1].strip(), self.parent.item): + if i not in intent: + intent.append(i) + continue + if lattr.startswith('bind'): + l = attr[4:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.bind = specs_split_comma(l[1:-1].strip(), self.parent.item) + continue + if lattr.startswith('check'): + l = attr[5:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.check.extend(split_comma(l[1:-1].strip()), self.parent.item) + continue + if uattr not in attributes: + attributes.append(uattr) + return + + def __str__(self): + s = '' + if self.typedecl is not None: + s += self.typedecl.tostr() + ' ' + a = self.attributes[:] + if self.dimension is not None: + a.append('DIMENSION(%s)' % (', '.join(self.dimension))) + if self.intent is not None: + a.append('INTENT(%s)' % (', '.join(self.intent))) + if self.bind: + a.append('BIND(%s)' % (', '.join(self.bind))) + if self.check: + a.append('CHECK(%s)' % (', '.join(self.check))) + if a: + s += ', '.join(a) + ' :: ' + return s + self.name + +class ProgramBlock: + pass class Statement: """ @@ -18,6 +165,14 @@ class Statement: def __init__(self, parent, item): self.parent = parent self.reader = parent.reader + self.top = getattr(parent,'top',None) + if isinstance(parent, ProgramBlock): + self.programblock = parent + elif isinstance(self, ProgramBlock): + self.programblock = self + elif hasattr(parent,'programblock'): + self.programblock = parent.programblock + self.item = item # when a statement instance is constructed by error, set isvalid to False @@ -25,8 +180,19 @@ class Statement: # when a statement should be ignored, set ignore to True self.ignore = False + # attribute a will hold analyze information. + a_dict = {} + for cls in get_base_classes(self.__class__): + if hasattr(cls,'a'): + a_dict.update(copy.deepcopy(cls.a.todict())) + self.a = AttributeHolder(**a_dict) + if hasattr(self.__class__,'a'): + assert self.a is not self.__class__.a + self.process_item() + return + def get_indent_tab(self,colon=None,deindent=False): if self.reader.isfix: tab = ' '*6 @@ -60,6 +226,10 @@ class Statement: sys.stderr.flush() return + def analyze(self): + self.show_message('nothing analyzed in %s' % (self.__class__.__name__)) + return + class BeginStatement(Statement): """ <blocktype> <name> @@ -237,6 +407,10 @@ class BeginStatement(Statement): #sys.exit() return + def analyze(self): + for stmt in self.content: + stmt.analyze() + return class EndStatement(Statement): """ @@ -274,6 +448,9 @@ class EndStatement(Statement): self.isvalid = False self.name = self.parent.name + def analyze(self): + return + def __str__(self): return self.get_indent_tab()[:-2] + 'END %s %s'\ % (self.blocktype.upper(),self.name or '') |