mutable_tree.py

Go to the documentation of this file.
00001 #
00002 # mutator classes and utilities
00003 #
00004 
00005 from _Setup import *
00006 from PyUtil.fval import Fval
00007 
00008 def _noop(s,*a,**kw):
00009     'mutator _noop primitive'
00010     pass
00011 
00012 def _prim_m(s,*a,**kw):
00013     'non-node noop'
00014     return s
00015 
00016 class LexiMutator(object):
00017     'mutator defined by lexicon (ie by cases)'
00018     def __init__(self,lexi,prim=_prim_m):
00019         self.lexi = lexi
00020         self.prim = Fval(prim)
00021 
00022     def setup(self):
00023         for (cls,fn) in self.lexi:
00024             cls.mutator = fn
00025         _Mutable_T.prim_mutate = self.prim
00026 
00027     def restore(self):
00028         for (cls,dc) in self.lexi:
00029             del cls.mutator
00030         _Mutable_T.mutator = _noop
00031         _Mutable_T.prim_mutate = Fval(_prim_m)
00032 
00033     clr = restore
00034 
00035 class FnMutator(object):
00036     'mutator defined as a single function'
00037     def __init__(self,fn,prim=_prim_m):
00038         self.fn   = fn
00039         self.prim = Fval(prim)
00040 
00041     def setup(self):
00042         _Mutable_T.mutator = self.fn
00043         _Mutable_T.prim_mutate = self.prim
00044 
00045     def restore(self):
00046         _Mutable_T.mutator = _noop
00047         _Mutable_T.prim_mutate = Fval(_prim_m)
00048 #
00049 # paths to tree objects
00050 #
00051 class __Path(object):
00052     '''abstract path class:
00053     when a value is mutated to a new node class(!), then
00054     the path must be reassigned the new value.
00055     '''
00056 class _Spath(object):
00057     '''a scalar path: base object + attribute name are sufficient
00058     '''
00059     def __init__(self,base,attr):
00060         self.base = base
00061         self.attr = attr
00062 
00063     def set(self,val):
00064         'set a value for a scalar path'
00065         setattr(self.base,self.attr,val)
00066 
00067 class _Lpath(object):
00068     '''a list path object: base object + attribute + index
00069     '''
00070     def __init__(self,base,attr,idx):
00071         self.base = base
00072         self.attr = attr
00073         self.idx  = idx
00074 
00075     def set(self,val):
00076         'set a value for an element of a list'
00077         m = self.base.sonv(self.attr)
00078         m[self.idx] = val
00079 #
00080 # Mutable tree support stuff
00081 #
00082 def is_leaf(v):
00083     '''a node is a leaf if:
00084        1) it is a token  OR
00085        2) it has an empty sons list
00086     '''
00087     return isinstance(v,str) or (hasattr(v,'sons') and not v.sons)
00088 
00089 def _prim(n):
00090     'if "node" n has no mutate method, then it is primitive'
00091     return not hasattr(n,'mutate')
00092 
00093 class _Mutable_T(object):
00094     '''Support mutable tree data structures:
00095     expect a sons element in the class that describes what
00096     attributes hold subtrees.
00097     if one of the subtree attributes is list valued, then
00098     list
00099     '''
00100 
00101     def putpth(self,pth):
00102         self._pth = pth
00103         return self
00104 
00105     def clrpth(self):
00106         del self._pth
00107         return self
00108 
00109     def prune(self,v=True):
00110         self._prune = v
00111         return self._prune
00112     
00113     def pruneq(self):
00114         return hasattr(self,'_prune') and self._prune
00115             
00116     def repl(self,val):
00117         'replace self with val: use pth to link to new val'
00118         self._pth.set(val)
00119 
00120     def sonv(self,son):
00121         '''synonym for getattr'''
00122         return getattr(self,son)
00123 
00124     def idx_son_val(self,son,idx):
00125         '''get an element from a list-valued son'''
00126         tmp = getattr(self,son)
00127         return tmp[idx]
00128 
00129     def subtrees(self):
00130         'create a list of (path,subtree) pairs for a given node'
00131         rv = []
00132         for a in self._sons:
00133             son_val = self.sonv(a)
00134             if isinstance(son_val,list):
00135                rv.extend([(_Lpath(self,a,i),self.idx_son_val(a,i))
00136                           for i in range(len(son_val))])
00137             else:
00138                 rv.append((_Spath(self,a),son_val))
00139         return rv
00140 
00141     mutator     = _noop
00142     prim_mutate = Fval(_prim_m)
00143 
00144     def mapp(self,*arg):
00145         'like mapc, but the mappor may be deleted'
00146         self.mappor(*arg)
00147 
00148     def visit(self,*arg):
00149         '''primarily operate on arg'''
00150         rv = self.visitor(*arg)
00151         if not (self.pruneq() or is_leaf(self)):
00152             for (pth,n) in self.subtrees():
00153                 if _prim(n):
00154                     self.prim_visit(n,pth,*arg)
00155                 else:
00156                     n.putpth(pth).visit(*arg)
00157                     n.clrpth()
00158         # FIXME: clear the _prune thing?
00159         return rv
00160 
00161     def mutate(self,oth=None):
00162         '''The mutation walker:
00163         apply the mutator to self, THEN
00164         mutate all subtrees
00165         '''
00166         rv = self.mutator(oth)
00167         if not (self.pruneq() or is_leaf(self)):
00168             for (pth,n) in self.subtrees():
00169                 if _prim(n):
00170                     self.prim_mutate(n,pth,oth)
00171                 else:
00172                     n.putpth(pth).mutate(oth)
00173                     n.clrpth()
00174 
00175 def mutate(top,mutator,oth=None):
00176     '''mutate the substructure of the top level object (top).
00177     Use the mutator function to do it.
00178     !!! NOTE: This is not quite the same as the method. The
00179     mutator is NOT applied to the toplevel object
00180     '''
00181     mutator.setup()
00182     for (pth,n) in top.subtrees():
00183         if _prim(n):
00184             top.prim_mutate(n,pth,oth)
00185         else:
00186             n.putpth(pth).mutate(oth)
00187             n.clrpth()
00188     mutator.restore()
00189     return top

Generated on Wed Jan 28 02:45:34 2009 for OpenADFortTk (SourceProcessing) by  doxygen 1.5.7.1