1#!/usr/bin/env python
2""" ir.py - parse c declarations
3
4(c) 2002, 2003, 2004, 2005 Simon Burton <simon@arrowtheory.com>
5Released under GNU LGPL license.
6
7version 0.xx
8
9"""
10
11import sys
12#import cPickle as pickle
13import pickle
14
15#from lexer import Lexer
16from parse_core import Symbols #, Parser
17import node as node_module
18import cparse
19import genpyx
20
21class Node(genpyx.Node, node_module.Node):
22    """
23        tree structure
24    """
25    def __init__( self, *args, **kw ):
26        node_module.Node.__init__( self, *args, **kw )
27        self._marked = False
28    def get_marked( self ):
29        return self._marked
30    def set_marked( self, marked ):
31#    if marked:
32#      print "MARK", self
33        self._marked = marked
34    marked = property( get_marked, set_marked )
35
36#  def __getstate__( self ):
37#    return self.__class__, tuple( [ item.__getstate__() for item in self ] )
38#  def __setstate__( self, state ):
39#    cls, states = state
40#    states = list(states)
41#    for idx, state in enumerate(states):
42#      items[idx] = items[idx].__setstate__(
43    def __getstate__(self):
44        return str(self)
45    def __setstate__(self, state):
46        Node.__init__(self)
47        self[:] = eval(state)
48
49#  _unique_id = 0
50#  def get_unique_id(cls):
51#    Node._unique_id += 1
52#    return Node._unique_id
53#  get_unique_id = classmethod(get_unique_id)
54
55    def __hash__( self ):
56        return hash( tuple([hash(type(self))]+[hash(item) for item in self]) )
57
58    def clone(self):
59        l = []
60        for item in self:
61            if isinstance(item,Node):
62                item = item.clone()
63            l.append(item)
64        return self.__class__(*l, **self.__dict__)
65
66    def init_from( self, other ): # class method ?
67        # Warning: shallow init
68        self[:] = other
69        self.__dict__.update( other.__dict__ )
70        return self
71
72#  def is_struct(self):
73#    for x in self:
74#      if isinstance(x,Node):
75#        if x.is_struct():
76#          return 1
77#    return 0
78
79
80    #def explain(self):
81        #l = []
82        #for x in self:
83            #if isinstance(x,Node):
84                #l.append(x.explain())
85            #else:
86                #l.append(str(x))
87        #return string.join(l," ")
88            ##(self.__class__.__name__,string.join(l) )
89
90    def psource(self):
91        if hasattr(self,'lines'):
92#      print "# "+string.join(self.lines,"\n# ")+"\n"
93            print "# "+"\n# ".join(self.lines)+"\n"
94
95    def cstr(self,l=None):
96        """
97            Build a list of tokens; return the joined tokens string
98        """
99        if l is None:
100            l = []
101        for x in self:
102            if isinstance(x,Node):
103                x.cstr(l)
104            else:
105                l.insert(0,str(x)+' ')
106        s = ''.join(l)
107        return s
108
109    def ctype(self): # anon_clone
110        " return clone of self without identifiers "
111        #print "%s.ctype()"%self
112        l=[]
113        for x in self:
114            if isinstance(x,Node):
115                l.append(x.ctype())
116            else:
117                l.append(x)
118        #print "%s.__class__(*%s)"%(self,l)
119        return self.__class__(*l, **self.__dict__) # XX **self.__dict__ ?
120
121    def cbasetype(self):
122        " return ctype with all TypeAlias's replaced "
123        # WARNING: we cache results (so do not mutate self!!)
124        l=[]
125        for x in self:
126            if isinstance(x,Node):
127                l.append(x.cbasetype())
128            else:
129                l.append(x)
130        #print "%s.__class__(*%s)"%(self,l)
131        return self.__class__(*l, **self.__dict__) # XX **self.__dict__ ?
132
133    def signature( self, tank=None ):
134        if tank is None:
135            tank = {}
136        for node in self.nodes():
137            if not tank.has_key( type(node) ):
138                tank[ type(node) ] = {}
139                type(node).tank = tank[type(node)]
140            shape = tuple( [ type(_node).__name__ for _node in node ] )
141            if not tank[type(node)].has_key(shape):
142                tank[type(node)][shape] = []
143            tank[type(node)][shape].append( node )
144        return tank
145
146    def psig( self, tank=None ):
147        if tank is None:
148            tank = {}
149        tank = self.signature(tank)
150        for key in tank.keys():
151            print key.__name__
152            for shape in tank[key].keys():
153                print "  ", shape
154
155#
156#################################################
157
158class Named(genpyx.Named, Node):
159    " has a .name property "
160    def get_name(self):
161        if self:
162            assert type(self[0])==str
163            return self[0]
164        return None
165    def set_name(self, name):
166        if self:
167            self[0] = name
168        else:
169            self.append(name)
170    name = property(get_name,set_name)
171
172
173class BasicType(genpyx.BasicType, Named):
174    "float double void char int"
175    pass
176
177class Qualifier(genpyx.Qualifier, Named):
178    "register signed unsigned short long const volatile inline"
179    pass
180
181class StorageClass(genpyx.StorageClass, Named):
182    "extern static auto"
183    pass
184
185class Ellipses(genpyx.Ellipses, Named):
186    "..."
187    pass
188
189class GCCBuiltin(genpyx.GCCBuiltin, BasicType):
190    "things with __builtin prefix"
191    pass
192
193class Identifier(genpyx.Identifier, Named):
194    """
195        shape = +( str, +ConstExpr )
196    """
197    #def explain(self):
198        #if len(self)==1:
199            #return "%s"%self.name
200        #else:
201            #return "%s initialized to %s"%(self.name,
202                #Node(self[1]).explain()) # will handle Initializer
203
204#  def ctype(self):
205#    return self.__class__(*self[1:]) #.clone() ?
206
207#  def get_name(self):
208#    if self:
209#      return self[0]
210#  def set_name(self, name):
211#    if self:
212#      self[0] = name
213#    else:
214#      self.append(name)
215#  name = property(get_name,set_name)
216
217    def cstr(self,l=None):
218        if l is None:
219            l=[]
220        if len(self)>1:
221            assert len(self)==2
222            l.append( '%s = %s'%(self[0],self[1]) )
223        elif len(self)==1:
224            l.append( str(self[0]) )
225        return " ".join(l)
226
227class TypeAlias(genpyx.TypeAlias, Named):
228    """
229     typedefed things, eg. size_t
230
231    """
232    def cbasetype( self ):
233        node = self.typedef.cbasetype().get_rest()
234        return node
235
236class Function(genpyx.Function, Node):
237    """
238    """
239    #def explain(self):
240        #if len(self):
241            #return "function (%s), returning"%\
242                #", ".join( map(lambda x:x.explain(),self) )
243        #else:
244            #return "function returning"
245
246    def cstr(self,l):
247        #print '%s.cstr(%s)'%(self,l)
248        _l=[]
249        assert len(self)
250        i=0
251        while isinstance(self[i],Declarator):
252            _l.append( self[i].cstr() )
253            i=i+1
254        l.append( '(%s)'% ', '.join(_l) )
255        while i<len(self):
256            self[i].cstr(l)
257            i=i+1
258        return " ".join(l)
259
260    def return_type(self):
261        node = self[-1]
262        #assert isinstance(node,DeclarationSpecifiers)
263        return Declarator( Identifier(), node )
264    ret = property(return_type)
265
266    def get_args(self):
267        args = [ arg for arg in self[:-1] if not arg.is_void() ]
268        return args
269    args = property(get_args)
270
271    def arg_types(self):
272        return [ AbstractDeclarator().init_from( arg.ctype() ) for arg in self[:-1]]
273
274    def is_varargs(self):
275        for node in self.nodes():
276            if isinstance(node,Ellipses) or 'va_list' in node:
277#        print self, 'is_varargs'
278                return True
279#    print self, 'is_varargs'
280        return False
281#    return fn.deepfind(Ellipses) or fn.deepfind('va_list')
282
283    def ctype(self):
284        return Function(*self.arg_types()+[self[-1]]) # XX self[-1].ctype
285
286
287class Pointer(genpyx.Pointer, Node):
288    """
289    """
290    def get_spec(self):
291        if type(self[0])==TypeSpecifiers: # isinstance ??
292            return self[0]
293    spec = property(get_spec)
294
295    #def explain(self):
296        #return "pointer to"
297
298    def cstr(self,l):
299        assert len(self)
300        node=self[0]
301        l.insert(0,'*')
302        if isinstance(node,Function):
303            l.insert(0,'(')
304            l.append(')')
305        elif isinstance(node,Array):
306            l.insert(0,'(')
307            l.append(')')
308        return Node.cstr(self,l)
309
310class Array(genpyx.Array, Node):
311    """
312    """
313    #def explain(self):
314        #s=''
315        #if len(self):
316            #if type(self[0])==int:
317                #s='0 to %s '%(self[0]-1)
318        #return "array %sof"%s
319    def has_size(self):
320        try:
321            int(self.size)
322            return True
323        except:
324            return False
325
326    def get_size(self):
327        if type(self[-1])==str:
328            try: return int(self[-1])
329            except: return self[-1]
330        return self[-1] # None
331    size = property(get_size)
332
333    def get_spec(self):
334        if type(self[0])==TypeSpecifiers: # isinstance ??
335            return self[0]
336    spec = property(get_spec)
337
338    def to_pointer(self):
339        node = Pointer()
340        node.init_from( self.clone() )
341        node.pop() # pop the size element
342        return node
343
344    def cstr(self,l):
345        if self.size is None:
346            l.append('[]')
347        else:
348            l.append('[%s]'%self.size)
349        return Node( *self[:-1] ).cstr( l )
350
351class Tag(genpyx.Tag, Named):
352    " the tag of a Struct, Union or Enum "
353    pass
354
355class Taged(genpyx.Taged, Node):
356    "Struct, Union or Enum "
357    def get_tag(self):
358        if len(self):
359            tag = self[0]
360            assert type(tag)==Tag # isinstance ??
361        else:
362            tag = None
363        return tag
364    def set_tag(self,tag):
365        if len(self):
366            self[0] = tag
367        else:
368            self.append(tag)
369    tag = property( get_tag, set_tag )
370    def has_members(self):
371        return len(self)>1 # more than just a tag
372    def get_members(self):
373        return self[1:]
374    members = property(get_members) # fields ?
375
376    def ctype(self):
377        if not self.tag.name:
378            #print "# WARNING : anonymous struct " # OK i think
379            return self.clone()
380#    self = self.clone()
381#    return self[:1] # just the tag
382        return self.__class__( self.tag, **self.__dict__ ) # just the Tag
383#    return self.__class__( *self, **self.__dict__ )
384
385    def cbasetype(self):
386        return self.ctype() # is this enough ???
387#    return Node.cbasetype(self) # XX lookup my tag if i am empty ..?
388
389
390class Compound(genpyx.Compound, Taged):
391    "Struct or Union"
392
393    def cstr(self,_l=None):
394        assert isinstance( self[0], Tag )
395        tag=''
396        if len(self[0]):
397            tag=' '+self[0][0]
398        if isinstance(self,Struct):
399            l=[ 'struct%s '%tag ]
400        elif isinstance(self,Union):
401            l=[ 'union%s '%tag ]
402        if len(self)>1:
403            l.append(' { ')
404            for decl in self[1:]:
405                l.append( decl.cstr()+"; " )
406            l.append('} ')
407        if _l is None:
408            _l=[]
409        while l:
410            _l.insert( 0, l.pop() )
411        # XX empty struct with no tag -> "struct" XX
412        return "".join( _l )
413
414    def ctype(self):
415        tp = Taged.ctype(self)
416        for i in range(1,len(tp)):
417            tp[i] = StructDeclarator().init_from( tp[i] )
418        return tp
419
420class Struct(genpyx.Struct, Compound):
421    """
422    """
423    pass
424
425
426class Union(genpyx.Union, Compound):
427    """
428    """
429    pass
430
431
432class Enum(genpyx.Enum, Taged):
433    """
434    """
435    def cstr(self,_l=None):
436        assert isinstance( self[0], Tag )
437        tag=''
438        if len(self[0]):
439            tag=' '+self[0][0]
440        l=[ 'enum%s '%tag ]
441        if len(self)>1:
442            l.append(' { ')
443            for node in self[1:]:
444                l.append( node.cstr()+', ' )
445            l.append('} ')
446        if _l is None:
447            _l=[]
448        while l:
449            _l.insert( 0, l.pop() )
450        return ''.join( _l )
451
452class Declarator(genpyx.Declarator, Node):
453    """
454    """
455
456    def __eq__(self,other):
457        " unordered equality "
458        # ordering sometimes gets lost when we do a cbasetype
459        if not isinstance(other,Node):
460            return False
461        a, b = self[:], other[:]
462        a.sort()
463        b.sort()
464        return a == b
465
466    def __hash__( self ):
467        hs = [hash(item) for item in self]
468        hs.sort()
469        return hash( tuple([hash(type(self))]+hs) )
470
471    def transform(self):
472        return
473
474    def get_identifier(self):
475        if len(self)>1:
476            return self[0]
477    def set_identifier(self, identifier):
478        if len(self)>1:
479            self[0] = identifier
480        else:
481            self.insert(0,identifier)
482    identifier = property(get_identifier,set_identifier)
483
484    def get_spec(self):
485        spec = self[-1]
486        if type(spec)==TypeSpecifiers: # isinstance ??
487            return spec
488    spec = property(get_spec)
489
490    def get_type_alias(self):
491        if self.spec:
492            if isinstance(self.spec[0], TypeAlias):
493                return self.spec[0]
494    type_alias = property(get_type_alias)
495
496    def get_tagged(self):
497        if self.spec:
498            return self.spec.tagged # i am a tagged
499    tagged = property(get_tagged)
500
501    def get_compound(self):
502        if self.spec:
503            return self.spec.compound # i am a compound
504    compound = property(get_compound)
505
506    def get_struct(self):
507        if self.spec:
508            return self.spec.struct # i am a struct
509    struct = property(get_struct)
510
511    def get_union(self):
512        if self.spec:
513            return self.spec.union # i am a union
514    union = property(get_union)
515
516    def get_enum(self):
517        if self.spec:
518            return self.spec.enum # i am an enum
519    enum = property(get_enum)
520
521    def get_function(self):
522        if len(self)>1 and type(self[1])==Function: # isinstance ??
523            return self[1]
524    function = property(get_function)
525
526    def get_pointer(self):
527        if len(self)>1 and type(self[1])==Pointer: # isinstance ??
528            return self[1]
529    pointer = property(get_pointer)
530
531    def get_array(self):
532        if len(self)>1 and type(self[1])==Array: # isinstance ??
533            return self[1]
534    array = property(get_array)
535
536    def get_name(self):
537        if self.identifier:
538            return self.identifier.name
539    def set_name(self, name):
540        assert self.identifier is not None
541        self.identifier.name = name
542    name = property(get_name, set_name)
543
544    def get_rest(self): # XX needs a better name
545        if len(self)>1:
546            return self[1]
547        return self[0]
548
549    def pointer_to( self ):
550        " return Declarator pointing to self's type "
551        decl = Declarator(Identifier(), Pointer(self.get_rest().clone()))
552        return decl
553
554    def deref( self ):
555        " return (clone of) Declarator that self is pointing to "
556        node = self.ctype() # clone
557        pointer = node.pointer or node.array
558        assert pointer, "cannot dereference non-pointer"
559        node[1:2] = pointer
560        return node
561
562    def is_void(self):
563        return self.spec and BasicType('void') in self.spec
564
565    def is_pointer_to_fn(self):
566        return self.pointer and self.deref().function
567
568    def is_pointer_to_char(self):
569#    return self.ctype() == TransUnit("char *a;").transform()[0].ctype()
570        node = self.pointer or self.array
571        if node:
572            spec = node.spec
573            if spec and BasicType('char') in spec and not BasicType('unsigned') in spec:
574                return True
575        return False
576
577    def is_callback(self):
578        " i am a pointer to a function whose last arg is void* "
579        if self.is_pointer_to_fn():
580            fn = self.deref().function
581            if fn.args:
582                arg = fn.args[-1]
583                if arg.pointer and arg.deref().is_void():
584                    return True
585
586    def is_complete( self, tag_lookup ):
587        if self.tagged and self.tagged.tag.name in tag_lookup and not tag_lookup[self.tagged.tag.name].has_members():
588            return False
589        return True
590
591    def is_primative( self ):
592        "i am a char,short,int,float,double... "
593        spec = self.cbasetype().spec
594        return spec and spec.find(BasicType)
595
596    def is_pyxnative( self ):
597        # pyrex handles char* too
598        # but i don't know if we should make this the default
599        # sometimes we want to send a NULL, so ... XXX
600        self = self.cbasetype()
601        if self.is_void():
602            return False
603        if self.is_primative():
604            return True
605        if self.enum:
606            return True
607#    pointer = None
608#    if self.pointer:
609#      pointer = self.pointer
610#    elif self.array:
611#      pointer = self.array
612#    if pointer and pointer.spec:
613#      spec = pointer.spec
614#      if BasicType("char") in spec and not Qualifier("unsigned") in spec:
615#        # char*, const char*
616##        print self.deepstr()
617#        return True
618        return False
619
620    def cstr(self,l=None):
621        return Node.cstr(self,l).strip()
622
623    def ctype(self):
624        decl=Declarator()
625        decl.init_from( self.clone() )
626        decl.identifier = Identifier()
627        for i in range(1,len(decl)):
628            decl[i]=decl[i].ctype()
629        return decl
630
631    def cbasetype(self):
632        # WARNING: we cache results (so do not mutate self!!)
633        try:
634            # this cache improves performance by 50%
635            return self.__cbasetype.clone()
636        except AttributeError:
637            pass
638        decl = self.ctype() # gets rid of Identifier names
639        for i, node in enumerate(decl):
640            decl[i] = decl[i].cbasetype()
641#    return decl.get_rest()
642
643        done = False
644        while not done:
645            done = True
646            nodes = decl.deepfilter( TypeSpecifiers )
647            for node in nodes:
648                if node.deepfind( TypeSpecifiers ) != node:
649                    # this node has another TypeSpecifier;
650                    decl.expose_node( node )
651                    done = False
652                    break # start again...
653
654        # each TypeSpecifier needs to absorb primitive siblings (StorageClass, BasicType etc.)
655        nodes = decl.deepfilter( TypeSpecifiers )
656        for node in nodes:
657            parent = decl.get_parent(node)
658            i = 0
659            while i < len(parent):
660                assert not type(parent[i]) in (TypeAlias, Enum, Struct, Union)
661                if type(parent[i]) in (StorageClass, BasicType, Qualifier):
662                    node.append( parent.pop(i) )
663                else:
664                    i = i + 1
665
666        self.__cbasetype = decl.clone()
667        return decl
668
669    def invalidate(self):
670        # flush cache, etc.
671        try:
672            del self.__cbasetype
673        except AttributeError:
674            pass
675
676    def declare_str(self,name):
677        " return c string declaring name with same type as self "
678        tp = self.ctype()
679        tp.name = name
680        return tp.cstr()+";"
681
682class Typedef(genpyx.Typedef, Declarator):
683    def cstr(self,l=None):
684        return 'typedef ' + Declarator.cstr(self,l) #.strip()
685
686class AbstractDeclarator(genpyx.AbstractDeclarator, Declarator):
687    """ used in Function; may lack an identifier """
688
689    #def cstr(self,l=None):
690        #return Node.cstr(self,l)
691
692#  def ctype(self):
693#    # _type_ ignores the name of our identifier
694#    return Node.ctype(self)
695
696class FieldLength(genpyx.FieldLength, Node):
697    """
698    """
699    #def explain(self):
700        #return ""
701
702    def cstr(self,l):
703        l.append(':%s'%self[0])
704
705class StructDeclarator(genpyx.StructDeclarator, Declarator): # also used in Union
706    """
707    """
708    #def explain(self):
709        #flen = self.find(FieldLength)
710        #if flen is not None:
711            #i = self.index(flen)
712            #self.pop(i)
713            #s = Declarator.explain(self)
714            #self.insert(i,flen)
715            #width = flen[0]
716            #if width > 0:
717                #return s+" bitfield %s wide"%width
718            #else:
719                #return s+" alignment bitfield"
720        #else:
721            #return Declarator.explain(self)
722#  def ctype(self):
723#    return self
724    def get_field_length(self):
725        if len(self)>1 and isinstance( self[1], FieldLength ):
726            return self[1]
727    field_length = property(get_field_length)
728
729
730class DeclarationSpecifiers(genpyx.DeclarationSpecifiers, Node):
731#class TypeSpecifiers(Node):
732    """
733    """
734    def __eq__(self,other):
735        " unordered equality "
736        if not isinstance(other,Node):
737            return False
738        a, b = self[:], other[:]
739        a.sort()
740        b.sort()
741        return a == b
742
743    def __hash__( self ):
744        hs = [hash(item) for item in self]
745        hs.sort()
746        return hash( tuple([hash(type(self))]+hs) )
747
748#  def is_struct(self):
749#    return self.find(Struct) is not None
750
751
752class TypeSpecifiers(genpyx.TypeSpecifiers, DeclarationSpecifiers):
753    """
754    """
755    def get_tagged(self):
756        if self and isinstance(self[0],Taged):
757            return self[0]
758    tagged = property(get_tagged)
759
760    def get_compound(self):
761        if self and isinstance(self[0],Compound):
762            return self[0]
763    compound = property(get_compound)
764
765    def get_struct(self):
766        if self and isinstance(self[0],Struct):
767            return self[0]
768    struct = property(get_struct)
769
770    def get_union(self):
771        if self and isinstance(self[0],Union):
772            return self[0]
773    union = property(get_union)
774
775    def get_enum(self):
776        if self and isinstance(self[0],Enum):
777            return self[0]
778    enum = property(get_enum)
779
780    def cbasetype(self):
781        node = Node.cbasetype(self)
782#    node.expose( TypeSpecifiers )
783#    if node.deepfind(TypeSpecifiers) != node:
784        return node
785
786class Initializer(genpyx.Initializer, Node):
787    """
788    """
789    pass
790
791
792
793class Declaration(genpyx.Declaration, Node):
794    """
795    """
796    def do_spec(self):
797        " distribute DeclarationSpecifiers over each Declarator "
798        spec=self[0]
799        assert isinstance(spec,DeclarationSpecifiers), spec.deepstr()
800        self.pop(0)
801        for declarator in self:
802            assert isinstance(declarator,Declarator)
803            #if isinstance(declarator,DeclarationSpecifiers #huh?
804            ##for node in spec:
805                ##declarator.append(node.clone())
806            declarator.append(spec)
807
808    def transform(self):
809        # children go first
810        for node in self.nodes():
811            if isinstance(node,Declaration):
812                node.do_spec()
813            node.file = self.file # overkill ?
814        self.expose(Declaration)
815
816    #def explain(self):
817        #return string.join([x.explain() for x in self],", ")
818        #return string.join(map(lambda x:x.explain(),self),", ")
819
820
821class ParameterDeclaration(genpyx.ParameterDeclaration, Declaration):
822    """
823    """
824    pass
825
826
827class StructDeclaration(genpyx.StructDeclaration, Declaration):
828    """
829    """
830    pass
831
832
833class TransUnit(genpyx.TransUnit, Node):
834    """
835        Top level node.
836    """
837    def __init__( self, item ): # XX __init__ uses different signature ! XX
838        if type(item)==str:
839            node = cparse.TransUnit()
840            node.parse(item)
841        else:
842            node = item
843            assert isinstance( node, cparse.TransUnit ), str(node)
844        Node.__init__(self)
845        self[:] = [ self.convert(child) for child in node ]
846        self.__dict__.update( node.__dict__ )
847        assert "name" not in node.__dict__
848
849        self.syms = {} # map identifier names to their Declarator's
850        self.typedefs = {} # map names to Typedef's
851        self.tag_lookup = {} # map struct, union, enum tags to Taged's
852
853        # XX should call transform here XX
854
855#    print self.deepstr()
856    def __getstate__( self ):
857        nodes = tuple( [ repr(node) for node in self ] )
858        typedefs = tuple( [ (key,repr(val)) for key,val in self.typedefs.items() ] )
859        return nodes, typedefs
860    def __setstate__( self, state ):
861        Node.__init__(self)
862        nodes, typedefs = state
863        nodes = [ eval(node) for node in nodes ]
864        self[:] = nodes
865        typedefs = [ (key,eval(val)) for key,val in typedefs ]
866        self.typedefs = dict(typedefs)
867
868    def convert( self, node ):
869#    name = node.__class__.__name__
870#    cls = globals()[ name ]
871        cls = cls_lookup[ type(node) ]
872        _node = cls()
873        for child in node:
874            if isinstance(child, node_module.Node):
875                child = self.convert( child )
876            else:
877                assert child is None or type(child) in (str, int), type(child)
878            _node.append( child )
879        _node.__dict__.update( node.__dict__ )
880        return _node
881
882    def strip(self,files):
883        " leave only the declarations from <files> "
884        i=0
885        while i<len(self):
886            if self[i].file in files:
887                i=i+1
888            else:
889                self.pop(i)
890
891    def mark(self,cb,verbose=False):
892        " mark our child nodes such that cb(node).. mark dependants too. prune unmarked objects. "
893        # mark the nodes:
894        for node in self:
895            node.marked = cb(self, node)
896            if verbose and node.marked:
897                print '1:', node.cstr()
898        # propagate dependancy:
899        i=len(self)
900        while i:
901            i-=1 # we go backwards
902            for node in self[i].nodes(): # bottom-up search
903                if verbose and self[i].marked and not node.marked:
904                    print '2:', str(node), '<--', self[i].cstr()
905                node.marked = self[i].marked or node.marked
906                if type(node)==TypeAlias:
907                    if verbose and node.marked and not node.typedef.marked:
908                        print '3:', node.typedef.cstr(), '<--', node.cstr()
909                    node.typedef.marked = node.typedef.marked or node.marked
910                if isinstance(node, Taged):
911                    if node.tag.name in self.tag_lookup:
912                        _node = self.tag_lookup[ node.tag.name ] # look-up the def'n
913                        if verbose and node.marked and not _node.marked:
914                            print '4:', _node.cstr(), '<--', self[i].cstr()
915#            _node.marked = _node.marked or self[i].marked
916                        _node.marked = _node.marked or node.marked
917#          else:
918#            # this guy has no tag
919#            print "lost tag:", self[i].cstr()
920
921                 # XX struct defs acquire marks from members, but XX
922                 # XX ordinary definitions do not                 XX
923#        if node.marked and not self[i].marked:
924#          # one of my descendants is marked
925#          if verbose:
926#            print '5:', self[i].cstr(), '<--', node.cstr()
927#          self[i].marked = True
928#    if verbose:
929#      for node in self:
930#        print '-'*79
931#        if node.enum:
932#          print str(node.marked) + ': ' + node.cstr()
933        # prune:
934        f = open(".tmp/pruned.txt","w")
935        f.write("// This file autogenerated by '%s' .\n"%__file__)
936        f.write("// List of functions pruned from parse tree, for various reasons.\n\n")
937        i=0
938        while i<len(self):
939            if not self[i].marked:
940                if verbose: print 'pop:', self[i].cstr()
941                f.write( self[i].cstr() + "\n" )
942                self.pop(i)
943#      elif self[i].compound:
944#        # XXXX for now, rip out all struct members XXXX
945#        self[i].compound[1:] = [] # XX encapsulation
946#        i = i + 1
947            else:
948                i = i + 1
949        for key, value in self.syms.items():
950            if not value.marked:
951                del self.syms[key]
952        for key, value in self.typedefs.items():
953            if not value.marked:
954                del self.typedefs[key]
955        for key, value in self.tag_lookup.items():
956            if not value.marked:
957                del self.tag_lookup[key]
958#    sys.exit(1)
959
960    def assert_no_dups(self):
961        check={}
962        for node in self.nodes():
963            assert not check.has_key(id(node))
964            check[id(node)]=1
965
966    def transform(self, verbose=False, test_parse=False, test_types=False ):
967        i=0
968        while i < len(self):
969            if verbose: print "##"*25
970            declaration=self[i]
971
972            if verbose: declaration.psource()
973            if verbose: print declaration.deepstr(),'\n'
974            assert isinstance(declaration,Declaration)
975            if verbose: print "# expose declarators from declaration"
976
977            # STAGE 1
978            declaration.transform()
979
980            if verbose: print declaration.deepstr(),'\n'
981            self[i:i+1] = declaration # expose declarators from declaration
982
983            for j in range(len(declaration)):
984                declarator=self[i]
985
986                assert isinstance(declarator,Declarator)
987                if verbose: print "# declarator.transform()"
988
989                # STAGE 2
990                declarator.transform()
991
992                if verbose: print declarator.deepstr(),'\n'
993                if verbose: print "# self.visit_declarator(declarator)"
994
995                # STAGE 3
996                self[i] = declarator = self.visit_declarator(declarator)
997
998                # STAGE 4
999                if declarator.name:
1000                    if isinstance(declarator, Typedef):
1001                        if verbose: print "# typedef %s" % declarator.name
1002                        self.typedefs[ declarator.name ] = declarator
1003                    else:
1004                        if verbose: print "# sym %s" % declarator.name
1005                        self.syms[ declarator.name ] = declarator
1006
1007                for node in declarator.nodes():
1008                    if isinstance(node,Taged) and node.tag.name:
1009                        assert type(node.tag.name)==str, node.deepstr()
1010                        taged = self.tag_lookup.get( node.tag.name, None )
1011                        if taged is None:
1012                            if verbose: print "# tag lookup %s = %s" % (declarator.name, node.tag.name)
1013                            self.tag_lookup[ node.tag.name ] = node
1014                        elif not taged.has_members():
1015                            # this is (maybe) the definition of this tag
1016                            if verbose: print "# definition %s = %s" % (declarator.name, node.tag.name)
1017                            self.tag_lookup[ node.tag.name ] = node
1018
1019                # Annotate the TypeAlias's
1020                for node in declarator.deepfilter( TypeAlias ):
1021                    name = node[0]
1022                    assert type( name ) == str
1023                    node.typedef = self.typedefs[ name ]
1024
1025                if verbose: print declarator.deepstr(),'\n'
1026                #print declarator.ctype().deepstr(),'\n'
1027                #assert declarator.clone() == declarator
1028
1029                ###################################################
1030                # TESTS:
1031                if test_parse:
1032                    # test that parse of cstr gives same answer
1033                    cstr = declarator.cstr()+';\n'
1034                    if verbose: print '# '+cstr.replace('\n','\n# ')
1035                    #print
1036                    if isinstance(declarator,Typedef):
1037                        name = declarator[0][0]
1038                        assert type(name)==str
1039                        self.lexer.rmtypedef( name )
1040                    declaration = cparse.Declaration()
1041                    self.lexer.lex( cstr )
1042                    #print self.lexer.err_string()
1043                    declaration.parse(  self.lexer, Symbols() ) # use new name-space
1044                    #declaration.parse(  Lexer( cstr ), Symbols() )
1045                    declaration = self.convert(declaration)
1046                    declaration.transform()
1047                    assert len(declaration)==1
1048                    decl=declaration[0]
1049                    decl.transform()
1050                    decl = self.visit_declarator(decl)
1051                    if decl!=declarator:
1052                        if verbose: print "#???????????"
1053                        if verbose: print decl.deepstr(),'\n\n'
1054                        #if verbose: print declaration.deepstr(),'\n\n'
1055                        #assert 0
1056                    elif verbose: print '# OK\n'
1057
1058                if test_types:
1059                    node = declarator.ctype()
1060                    declare_str= node.declare_str("my_name")
1061                    if verbose: print "# declarator.ctype() "
1062                    if verbose: print node.deepstr(),"\n"
1063                    if verbose: print "#",declare_str.replace('\n','\n# '), '\n'
1064
1065                i=i+1
1066        return self
1067
1068    def visit(self,node):
1069        #print 'visit(%s)'%node
1070        for _node in node:
1071            if isinstance(_node,Declarator):
1072                _node = self.visit_declarator(_node) # XX replace _node
1073            elif isinstance(_node,Node):
1074                _node = self.visit(_node) # XX replace _node
1075        return node
1076
1077    def visit_declarator(self,decl):
1078        assert isinstance(decl,Declarator)
1079
1080        # STAGE 3.a
1081        tp = decl.deepfind(Typedef)
1082        if tp is not None:
1083            decl.deeprm(tp)
1084            tp.init_from( decl ) # warning: shallow init
1085            decl = tp
1086
1087        # STAGE 3.b
1088        i=len(decl)
1089        # accumulate nodes (they become the children of decl)
1090        children=[]
1091        while i:
1092            i=i-1
1093            node=decl.pop(i)
1094            if isinstance(node,Declarator):
1095                node = self.visit_declarator(node) # replace node
1096            else:
1097                node = self.visit(node) # replace node
1098            if isinstance(node,Pointer):
1099                node+=children
1100                children=[node]
1101            elif isinstance(node,Function):
1102                node+=children
1103                children=[node]
1104            elif isinstance(node,Array):
1105                while children:
1106                    node.insert(0,children.pop())
1107                children=[node]
1108                # array size (if any) at end
1109            #elif isinstance(node,Identifier):
1110                #node+=children
1111                #children=[node]
1112            else:
1113                # accumulate
1114                children.insert(0,node)
1115        decl[:]=children
1116        return decl
1117
1118    cstr = None
1119    ctype = None
1120    cbasetype = None
1121
1122
1123# remap the global class definitions in genpyx to
1124# point to the definitions in this module
1125gbl = globals()
1126for key, val in gbl.items():
1127    if type(val)==type:
1128        if issubclass(val,Node):
1129            setattr( genpyx, key, val )
1130assert genpyx.Node == Node
1131
1132cls_lookup = {
1133#  Node : Node ,
1134    cparse.BasicType : BasicType ,
1135    cparse.Qualifier : Qualifier ,
1136    cparse.StorageClass : StorageClass ,
1137    cparse.Ellipses : Ellipses ,
1138    cparse.GCCBuiltin : GCCBuiltin ,
1139    cparse.Identifier : Identifier ,
1140    cparse.TypeAlias : TypeAlias ,
1141    cparse.Function : Function ,
1142    cparse.Pointer : Pointer ,
1143    cparse.Array : Array ,
1144    cparse.Tag : Tag ,
1145    cparse.Compound : Compound ,
1146    cparse.Struct : Struct ,
1147    cparse.Union : Union ,
1148    cparse.Enum : Enum ,
1149    cparse.Declarator : Declarator ,
1150    cparse.Typedef : Typedef ,
1151    cparse.AbstractDeclarator : AbstractDeclarator ,
1152    cparse.FieldLength : FieldLength ,
1153    cparse.StructDeclarator : StructDeclarator ,
1154    cparse.DeclarationSpecifiers : TypeSpecifiers ,
1155    cparse.TypeSpecifiers : TypeSpecifiers ,
1156    cparse.Initializer : Initializer ,
1157    cparse.Declaration : Declaration ,
1158    cparse.ParameterDeclaration : ParameterDeclaration ,
1159    cparse.StructDeclaration : StructDeclaration ,
1160    cparse.TransUnit : TransUnit ,
1161}
1162
1163
1164