#!/usr/bin/env python """ cdecl.py - parse c declarations (c) 2002, 2003, 2004, 2005 Simon Burton Released under GNU LGPL license. version 0.xx """ import string class Node(list): " A node in a parse tree " def __init__(self,*items,**kw): list.__init__( self, items ) self.lock1 = 0 # these two should be properties (simplifies serializing) self.lock2 = 0 self.verbose = 0 for key in kw.keys(): self.__dict__[key] = kw[key] def __str__(self): attrs = [] for item in self: if isinstance(item,Node): attrs.append( str(item) ) else: attrs.append( repr(item) ) attrs = ','.join(attrs) return "%s(%s)"%(self.__class__.__name__,attrs) def safe_repr( self, tank ): tank[ str(self) ] = None attrs = [] for item in self: if isinstance(item,Node): attrs.append( item.safe_repr(tank) ) # can we use repr here ? else: attrs.append( repr(item) ) # this is the dangerous bit: for key, val in self.__dict__.items(): if isinstance(val,Node): if str(val) not in tank: attrs.append( '%s=%s'%(key,val.safe_repr(tank)) ) else: attrs.append( '%s=%s'%(key,repr(val)) ) attrs = ','.join(attrs) return "%s(%s)"%(self.__class__.__name__,attrs) def __repr__(self): #attrs = ','.join( [repr(item) for item in self] + \ # [ '%s=%s'%(key,repr(val)) for key,val in self.__dict__.items() ] ) #return "%s%s"%(self.__class__.__name__,tuple(attrs)) return self.safe_repr({}) def __eq__(self,other): if not isinstance(other,Node): return 0 if len(self)!=len(other): return 0 for i in range(len(self)): if not self[i]==other[i]: return 0 return 1 def __ne__(self,other): return not self==other def filter(self,cls): return [x for x in self if isinstance(x,cls)] #return filter( lambda x:isinstance(x,cls), self ) def deepfilter(self,cls): " bottom-up " return [x for x in self.nodes() if isinstance(x,cls)] def find(self,cls): for x in self: if isinstance(x,cls): return x return None def deepfind(self,cls): " bottom-up isinstance search " for x in self: if isinstance(x,Node): if isinstance(x,cls): return x node = x.deepfind(cls) if node is not None: return node if isinstance(self,cls): return self return None def leaves(self): for i in self: if isinstance( i, Node ): for j in i.leaves(): yield j else: yield i def nodes(self): " bottom-up iteration " for i in self: if isinstance( i, Node ): for j in i.nodes(): yield j yield self def deeplen(self): i=0 if not self.lock2: self.lock2=1 for item in self: i+=1 if isinstance(item,Node): i+=item.deeplen() self.lock2=0 else: i+=1 return i def deepstr(self,level=0,comment=False,nl='\n',indent=' '): if self.deeplen() < 4: nl = ""; indent = "" #else: #nl="\n"; indent = " " s = [] if not self.lock1: self.lock1=1 for item in self: if isinstance(item,Node): s.append( indent*(level+1)+item.deepstr(level+1,False,nl,indent) ) else: s.append( indent*(level+1)+repr(item) ) self.lock1=0 else: for item in self: if isinstance(item,Node): s.append( indent*(level+1)+"" ) else: s.append( indent*(level+1)+"%s"%repr(item) ) s = "%s(%s)"%(self.__class__.__name__,nl+string.join(s,","+nl)) if comment: s = '#' + s.replace('\n','\n#') return s def clone(self): items = [] for item in self: if isinstance(item,Node): item = item.clone() items.append(item) # we skip any attributes... return self.__class__(*items) def fastclone(self): # XX is it faster ??? #print "clone" nodes = [self] idxs = [0] itemss = [ [] ] while nodes: assert len(nodes)==len(idxs)==len(itemss) node = nodes[-1] items = itemss[-1] assert idxs[-1] == len(items) while idxs[-1]==len(node): # pop _node = node.__class__( *items ) _node.__dict__.update( node.__dict__ ) nodes.pop(-1) idxs.pop(-1) itemss.pop(-1) if not nodes: #for node0 in self.nodes(): #for node1 in _node.nodes(): #assert node0 is not node1 #assert _node == self return _node # Done !! node = nodes[-1] items = itemss[-1] items.append(_node) # set idxs[-1] += 1 assert idxs[-1] == len(items) #assert idxs[-1] < len(node), str( (node,nodes,idxs,itemss) ) _node = node[ idxs[-1] ] # while idxs[-1] instance ' # children first for x in self: if isinstance(x,Node): x.expose(cls) # now the tricky bit i=0 while i < len(self): if isinstance(self[i],cls): node=self.pop(i) for x in node: assert not isinstance(x,cls) # pass on some attributes if hasattr(node,'lines') and not hasattr(x,'lines'): x.lines=node.lines if hasattr(node,'file') and not hasattr(x,'file'): x.file=node.file self.insert(i,x) # expose i=i+1 assert i<=len(self) else: i=i+1 def get_parent( self, item ): # XX 25% CPU time here XX assert self != item if item in self: return self for child in self: if isinstance(child, Node): parent = child.get_parent(item) if parent is not None: return parent return None def expose_node( self, item ): assert self != item parent = self.get_parent(item) idx = parent.index( item ) parent[idx:idx+1] = item[:] def delete(self,cls): ' delete any subtree ' for x in self: if isinstance(x,Node): x.delete(cls) # now the tricky bit i=0 while i < len(self): if isinstance(self[i],cls): self.pop(i) else: i=i+1 def deeprm(self,item): ' remove any items matching ' for x in self: if isinstance(x,Node): x.deeprm(item) # now the tricky bit i=0 while i < len(self): if self[i] == item: self.pop(i) else: i=i+1 def idem(self,cls): " is made idempotent " # children first for x in self: if isinstance(x,Node): x.idem(cls) if isinstance(self,cls): # now the tricky bit i=0 while i < len(self): if isinstance(self[i],cls): node = self.pop(i) for x in node: assert not isinstance(x,cls) self.insert(i,x) # idempotent i=i+1 assert i<=len(self) else: i=i+1 if __name__=="__main__": node = Node( 'a', Node(1,2), Node(Node(Node(),1)) ) print node print node.clone()