Home | History | Annotate | Download | only in Framework
      1 //
      2 //  ANTLRTreeWizard.m
      3 //  ANTLR
      4 //
      5 //  Created by Alan Condit on 6/18/10.
      6 // [The "BSD licence"]
      7 // Copyright (c) 2010 Alan Condit
      8 // All rights reserved.
      9 //
     10 // Redistribution and use in source and binary forms, with or without
     11 // modification, are permitted provided that the following conditions
     12 // are met:
     13 // 1. Redistributions of source code must retain the above copyright
     14 //    notice, this list of conditions and the following disclaimer.
     15 // 2. Redistributions in binary form must reproduce the above copyright
     16 //    notice, this list of conditions and the following disclaimer in the
     17 //    documentation and/or other materials provided with the distribution.
     18 // 3. The name of the author may not be used to endorse or promote products
     19 //    derived from this software without specific prior written permission.
     20 //
     21 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 #import "ANTLRTreeWizard.h"
     33 #import "ANTLRTreePatternLexer.h"
     34 #import "ANTLRTreePatternParser.h"
     35 #import "ANTLRIntArray.h"
     36 
     37 @implementation ANTLRVisitor
     38 
     39 + (ANTLRVisitor *)newANTLRVisitor:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
     40 {
     41     return [[ANTLRVisitor alloc] initWithAction:anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2];
     42 }
     43 
     44 - (id) initWithAction:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
     45 {
     46     if ((self = [super init]) != nil) {
     47         action = anAction;
     48         actor = anActor;
     49         if ( actor ) [actor retain];
     50         object1 = anObject1;
     51         if ( object1 ) [object1 retain];
     52         object2 = anObject2;
     53         if ( object2 ) [object2 retain];
     54     }
     55     return self;
     56 }
     57 
     58 - (void) dealloc
     59 {
     60 #ifdef DEBUG_DEALLOC
     61     NSLog( @"called dealloc in ANTLRVisitor" );
     62 #endif
     63     if ( actor ) [actor release];
     64     if ( object1 ) [object1 release];
     65     if ( object2 ) [object2 release];
     66     [super dealloc];
     67 }
     68 
     69 - (void) visit:(ANTLRCommonTree *)t Parent:(ANTLRCommonTree *)parent ChildIndex:(NSInteger)childIndex Map:(ANTLRMap *)labels
     70 {
     71     switch (action) {
     72         case 0:
     73             [(ANTLRMap *)object2 /* labels */ clear];
     74             if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:object2 /* labels */] ) {
     75                 [self visit:t Parent:parent ChildIndex:childIndex Map:object2 /* labels */];
     76             }
     77             break;
     78         case 1:
     79             if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:nil] ) {
     80                 [(AMutableArray *)object2/* subtrees */ addObject:t];
     81             }
     82             break;
     83     }
     84     // [self visit:t];
     85     return;
     86 }
     87 
     88 - (void) visit:(ANTLRCommonTree *)t
     89 {
     90     [object1 addObject:t];
     91     return;
     92 }
     93 
     94 @synthesize action;
     95 @synthesize actor;
     96 @synthesize object1;
     97 @synthesize object2;
     98 @end
     99 
    100 /** When using %label:TOKENNAME in a tree for parse(), we must
    101  *  track the label.
    102  */
    103 @implementation ANTLRTreePattern
    104 
    105 @synthesize label;
    106 @synthesize hasTextArg;
    107 
    108 + (ANTLRCommonTree *)newANTLRTreePattern:(id<ANTLRToken>)payload
    109 {
    110     return (ANTLRCommonTree *)[[ANTLRTreePattern alloc] initWithToken:payload];
    111 }
    112 
    113 - (id) initWithToken:(id<ANTLRToken>)payload
    114 {
    115     self = [super initWithToken:payload];
    116     if ( self != nil ) {
    117     }
    118     return (ANTLRCommonTree *)self;
    119 }
    120 
    121 - (void) dealloc
    122 {
    123 #ifdef DEBUG_DEALLOC
    124     NSLog( @"called dealloc in ANTLRTreePattern" );
    125 #endif
    126     if ( label ) [label release];
    127     [super dealloc];
    128 }
    129 
    130 - (NSString *)toString
    131 {
    132     if ( label != nil ) {
    133         return [NSString stringWithFormat:@"\% %@ : %@", label, [super toString]];
    134     }
    135     else {
    136         return [super toString];				
    137     }
    138 }
    139 
    140 @end
    141 
    142 @implementation ANTLRWildcardTreePattern
    143 
    144 + (ANTLRWildcardTreePattern *)newANTLRWildcardTreePattern:(id<ANTLRToken>)payload
    145 {
    146     return(ANTLRWildcardTreePattern *)[[ANTLRWildcardTreePattern alloc] initWithToken:(id<ANTLRToken>)payload];
    147 }
    148 
    149 - (id) initWithToken:(id<ANTLRToken>)payload
    150 {
    151     self = [super initWithToken:payload];
    152     if ( self != nil ) {
    153     }
    154     return self;
    155 }
    156 
    157 @end
    158 
    159 /** This adaptor creates TreePattern objects for use during scan() */
    160 @implementation ANTLRTreePatternTreeAdaptor
    161 
    162 + (ANTLRTreePatternTreeAdaptor *)newTreeAdaptor
    163 {
    164     return [[ANTLRTreePatternTreeAdaptor alloc] init];
    165 }
    166 
    167 - (id) init
    168 {
    169     self = [super init];
    170     if ( self != nil ) {
    171     }
    172     return self;
    173 }
    174 
    175 - (ANTLRCommonTree *)createTreePattern:(id<ANTLRToken>)payload
    176 {
    177     return (ANTLRCommonTree *)[super create:payload];
    178 }
    179           
    180 @end
    181 
    182 @implementation ANTLRTreeWizard
    183 
    184 // TODO: build indexes for the wizard
    185 
    186 /** During fillBuffer(), we can make a reverse index from a set
    187  *  of token types of interest to the list of indexes into the
    188  *  node stream.  This lets us convert a node pointer to a
    189  *  stream index semi-efficiently for a list of interesting
    190  *  nodes such as function definition nodes (you'll want to seek
    191  *  to their bodies for an interpreter).  Also useful for doing
    192  *  dynamic searches; i.e., go find me all PLUS nodes.
    193  protected Map tokenTypeToStreamIndexesMap;
    194  
    195  ** If tokenTypesToReverseIndex set to INDEX_ALL then indexing
    196  *  occurs for all token types.
    197  public static final Set INDEX_ALL = new HashSet();
    198  
    199  ** A set of token types user would like to index for faster lookup.
    200  *  If this is INDEX_ALL, then all token types are tracked.  If nil,
    201  *  then none are indexed.
    202  protected Set tokenTypesToReverseIndex = nil;
    203  */
    204 
    205 + (ANTLRTreeWizard *) newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor
    206 {
    207     return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor];
    208 }
    209 
    210 + (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
    211 {
    212     return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor Map:aTokenNameToTypeMap];
    213 }
    214 
    215 + (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
    216 {
    217     return [[ANTLRTreeWizard alloc] initWithTokenNames:anAdaptor TokenNames:theTokNams];
    218 }
    219 
    220 + (ANTLRTreeWizard *)newANTLRTreeWizardWithTokenNames:(NSArray *)theTokNams
    221 {
    222     return [[ANTLRTreeWizard alloc] initWithTokenNames:theTokNams];
    223 }
    224 
    225 - (id) init
    226 {
    227     if ((self = [super init]) != nil) {
    228     }
    229     return self;
    230 }
    231 
    232 - (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor
    233 {
    234     if ((self = [super init]) != nil) {
    235         adaptor = anAdaptor;
    236         if ( adaptor ) [adaptor retain];
    237     }
    238     return self;
    239 }
    240             
    241 - (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
    242 {
    243     if ((self = [super init]) != nil) {
    244         adaptor = anAdaptor;
    245         if ( adaptor ) [adaptor retain];
    246         tokenNameToTypeMap = aTokenNameToTypeMap;
    247    }
    248     return self;
    249 }
    250 
    251 - (id) initWithTokenNames:(NSArray *)theTokNams
    252 {
    253     if ((self = [super init]) != nil) {
    254 #pragma warning Fix initWithTokenNames.
    255         // adaptor = anAdaptor;
    256         //tokenNameToTypeMap = aTokenNameToTypeMap;
    257         tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
    258     }
    259     return self;
    260 }
    261              
    262 - (id) initWithTokenNames:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
    263 {
    264     if ((self = [super init]) != nil) {
    265         adaptor = anAdaptor;
    266         if ( adaptor ) [adaptor retain];
    267         // tokenNameToTypeMap = aTokenNameToTypeMap;
    268         tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
    269     }
    270     return self;
    271 }
    272             
    273 - (void) dealloc
    274 {
    275 #ifdef DEBUG_DEALLOC
    276     NSLog( @"called dealloc in ANTLRTreePatternTreeAdaptor" );
    277 #endif
    278     if ( adaptor ) [adaptor release];
    279     if ( tokenNameToTypeMap ) [tokenNameToTypeMap release];
    280     [super dealloc];
    281 }
    282 
    283 /** Compute a Map<String, Integer> that is an inverted index of
    284  *  tokenNames (which maps int token types to names).
    285  */
    286 - (ANTLRMap *)computeTokenTypes:(NSArray *)theTokNams
    287 {
    288     ANTLRMap *m = [ANTLRMap newANTLRMap];
    289     if ( theTokNams == nil ) {
    290         return m;
    291     }
    292     for (int ttype = ANTLRTokenTypeMIN; ttype < [theTokNams count]; ttype++) {
    293         NSString *name = (NSString *) [theTokNams objectAtIndex:ttype];
    294         [m putName:name TType:ttype];
    295     }
    296     return m;
    297 }
    298 
    299 /** Using the map of token names to token types, return the type. */
    300 - (NSInteger)getTokenType:(NSString *)tokenName
    301 {
    302     if ( tokenNameToTypeMap == nil ) {
    303         return ANTLRTokenTypeInvalid;
    304     }
    305     NSInteger aTType = (NSInteger)[tokenNameToTypeMap getTType:tokenName];
    306     if ( aTType != -1 ) {
    307         return aTType;
    308     }
    309     return ANTLRTokenTypeInvalid;
    310 }
    311 
    312 /** Walk the entire tree and make a node name to nodes mapping.
    313  *  For now, use recursion but later nonrecursive version may be
    314  *  more efficient.  Returns Map<Integer, List> where the List is
    315  *  of your AST node type.  The Integer is the token type of the node.
    316  *
    317  *  TODO: save this index so that find and visit are faster
    318  */
    319 - (ANTLRMap *)index:(ANTLRCommonTree *)t
    320 {
    321     ANTLRMap *m = [ANTLRMap newANTLRMap];
    322     [self _index:t Map:m];
    323     return m;
    324 }
    325 
    326 /** Do the work for index */
    327 - (void) _index:(ANTLRCommonTree *)t Map:(ANTLRMap *)m
    328 {
    329     if ( t==nil ) {
    330         return;
    331     }
    332 #pragma warning Fix _index use of ANTLRMap.
    333     NSInteger ttype = [adaptor getType:t];
    334     ANTLRMap *elements = (ANTLRMap *)[m getName:ttype];
    335     if ( elements == nil ) {
    336         elements = [ANTLRMap newANTLRMapWithLen:100];
    337         [m putNode:ttype Node:elements];
    338     }
    339     [elements addObject:t];
    340     int n = [adaptor getChildCount:t];
    341     for (int i=0; i<n; i++) {
    342         ANTLRCommonTree * child = [adaptor getChild:t At:i];
    343         [self _index:child Map:m];
    344     }
    345 }
    346 
    347 /** Return a List of tree nodes with token type ttype */
    348 - (AMutableArray *)find:(ANTLRCommonTree *)t Type:(NSInteger)ttype
    349 {
    350 #ifdef DONTUSENOMO
    351     final List nodes = new ArrayList();
    352     visit(t, ttype, new TreeWizard.Visitor() {
    353         public void visit(Object t) {
    354             [nodes addObject t];
    355         }
    356     } );
    357 #endif
    358     AMutableArray *nodes = [AMutableArray arrayWithCapacity:100];
    359     ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:3 Actor:self Object:(id)nodes Object:nil];
    360     [self visit:t Type:ttype Visitor:contextVisitor];
    361     return nodes;
    362 }
    363 
    364 /** Return a List of subtrees matching pattern. */
    365 - (AMutableArray *)find:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
    366 {
    367     AMutableArray *subtrees = [AMutableArray arrayWithCapacity:100];
    368     // Create a TreePattern from the pattern
    369     ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    370     ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
    371                                                                                      Wizard:self
    372                                                                                     Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    373     ANTLRCommonTree *tpattern = (ANTLRCommonTree *)[parser pattern];
    374     // don't allow invalid patterns
    375     if ( tpattern == nil ||
    376         [tpattern isNil] ||
    377         [tpattern class] == [ANTLRWildcardTreePattern class] )
    378     {
    379         return nil;
    380     }
    381     int rootTokenType = [tpattern type];
    382 #ifdef DONTUSENOMO
    383     visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
    384         public void visit(Object t, Object parent, int childIndex, Map labels) {
    385             if ( _parse(t, tpattern, null) ) {
    386                 subtrees.add(t);
    387             }
    388         }
    389     } );
    390 #endif
    391     ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:1 Actor:self Object:tpattern Object:subtrees];
    392     [self visit:t Type:rootTokenType Visitor:contextVisitor];
    393     return subtrees;
    394 }
    395 
    396 - (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Type:(NSInteger)ttype
    397 {
    398     return nil;
    399 }
    400 
    401 - (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Pattern:(NSString *)pattern
    402 {
    403     return nil;
    404 }
    405 
    406 /** Visit every ttype node in t, invoking the visitor.  This is a quicker
    407  *  version of the general visit(t, pattern) method.  The labels arg
    408  *  of the visitor action method is never set (it's nil) since using
    409  *  a token type rather than a pattern doesn't let us set a label.
    410  */
    411 - (void) visit:(ANTLRCommonTree *)t Type:(NSInteger)ttype Visitor:(ANTLRVisitor *)visitor
    412 {
    413     [self _visit:t Parent:nil ChildIndex:0 Type:ttype Visitor:visitor];
    414 }
    415 
    416 /** Do the recursive work for visit */
    417 - (void) _visit:(ANTLRCommonTree *)t
    418          Parent:(ANTLRCommonTree *)parent
    419      ChildIndex:(NSInteger)childIndex
    420            Type:(NSInteger)ttype
    421         Visitor:(ANTLRVisitor *)visitor
    422 {
    423     if ( t == nil ) {
    424         return;
    425     }
    426     if ( [adaptor getType:t] == ttype ) {
    427         [visitor visit:t Parent:parent ChildIndex:childIndex Map:nil];
    428     }
    429     int n = [adaptor getChildCount:t];
    430     for (int i=0; i<n; i++) {
    431         ANTLRCommonTree * child = [adaptor getChild:t At:i];
    432         [self _visit:child Parent:t ChildIndex:i Type:ttype Visitor:visitor];
    433     }
    434 }
    435 
    436 /** For all subtrees that match the pattern, execute the visit action.
    437  *  The implementation uses the root node of the pattern in combination
    438  *  with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
    439  *  Patterns with wildcard roots are also not allowed.
    440  */
    441 - (void)visit:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Visitor:(ANTLRVisitor *)visitor
    442 {
    443     // Create a TreePattern from the pattern
    444     ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    445     ANTLRTreePatternParser *parser =
    446     [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    447     ANTLRCommonTree *tpattern = [parser pattern];
    448     // don't allow invalid patterns
    449     if ( tpattern == nil ||
    450         [tpattern isNil] ||
    451         [tpattern class] == [ANTLRWildcardTreePattern class] )
    452     {
    453         return;
    454     }
    455     ANTLRMapElement *labels = [ANTLRMap newANTLRMap]; // reused for each _parse
    456     int rootTokenType = [tpattern type];
    457 #pragma warning This is another one of those screwy nested constructs that I have to figure out
    458 #ifdef DONTUSENOMO
    459     visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
    460         public void visit(Object t, Object parent, int childIndex, Map unusedlabels) {
    461             // the unusedlabels arg is null as visit on token type doesn't set.
    462             labels.clear();
    463             if ( _parse(t, tpattern, labels) ) {
    464                 visitor.visit(t, parent, childIndex, labels);
    465             }
    466         }
    467     });
    468 #endif
    469     ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:0 Actor:self Object:tpattern Object:labels];
    470     [self visit:t Type:rootTokenType Visitor:contextVisitor];
    471 }
    472 
    473 /** Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
    474  *  on the various nodes and '.' (dot) as the node/subtree wildcard,
    475  *  return true if the pattern matches and fill the labels Map with
    476  *  the labels pointing at the appropriate nodes.  Return false if
    477  *  the pattern is malformed or the tree does not match.
    478  *
    479  *  If a node specifies a text arg in pattern, then that must match
    480  *  for that node in t.
    481  *
    482  *  TODO: what's a better way to indicate bad pattern? Exceptions are a hassle 
    483  */
    484 - (BOOL)parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Map:(ANTLRMap *)labels
    485 {
    486 #ifdef DONTUSENOMO
    487     TreePatternLexer tokenizer = new TreePatternLexer(pattern);
    488     TreePatternParser parser =
    489     new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
    490     TreePattern tpattern = (TreePattern)parser.pattern();
    491     /*
    492      System.out.println("t="+((Tree)t).toStringTree());
    493      System.out.println("scant="+tpattern.toStringTree());
    494      */
    495     boolean matched = _parse(t, tpattern, labels);
    496     return matched;
    497 #endif
    498     ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    499     ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
    500                                                                                 Wizard:self
    501                                                                                Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    502     ANTLRCommonTree *tpattern = [parser pattern];
    503     /*
    504      System.out.println("t="+((Tree)t).toStringTree());
    505      System.out.println("scant="+tpattern.toStringTree());
    506      */
    507     //BOOL matched = [self _parse:t Pattern:tpattern Map:labels];
    508     //return matched;
    509     return [self _parse:t Pattern:tpattern Map:labels];
    510 }
    511 
    512 - (BOOL) parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
    513 {
    514     return [self parse:t Pattern:pattern Map:nil];
    515 }
    516 
    517 /** Do the work for parse. Check to see if the t2 pattern fits the
    518  *  structure and token types in t1.  Check text if the pattern has
    519  *  text arguments on nodes.  Fill labels map with pointers to nodes
    520  *  in tree matched against nodes in pattern with labels.
    521  */
    522 - (BOOL) _parse:(ANTLRCommonTree *)t1 Pattern:(ANTLRCommonTree *)aTPattern Map:(ANTLRMap *)labels
    523 {
    524     ANTLRTreePattern *tpattern;
    525     // make sure both are non-nil
    526     if ( t1 == nil || aTPattern == nil ) {
    527         return NO;
    528     }
    529     if ( [aTPattern isKindOfClass:[ANTLRWildcardTreePattern class]] ) {
    530         tpattern = (ANTLRTreePattern *)aTPattern;
    531     }
    532     // check roots (wildcard matches anything)
    533     if ( [tpattern class] != [ANTLRWildcardTreePattern class] ) {
    534         if ( [adaptor getType:t1] != [tpattern type] )
    535             return NO;
    536         // if pattern has text, check node text
    537         if ( tpattern.hasTextArg && ![[adaptor getText:t1] isEqualToString:[tpattern text]] ) {
    538             return NO;
    539         }
    540     }
    541     if ( tpattern.label != nil && labels!=nil ) {
    542         // map label in pattern to node in t1
    543         [labels putName:tpattern.label Node:t1];
    544     }
    545     // check children
    546     int n1 = [adaptor getChildCount:t1];
    547     int n2 = [tpattern getChildCount];
    548     if ( n1 != n2 ) {
    549         return NO;
    550     }
    551     for (int i=0; i<n1; i++) {
    552         ANTLRCommonTree * child1 = [adaptor getChild:t1 At:i];
    553         ANTLRCommonTree *child2 = (ANTLRCommonTree *)[tpattern getChild:i];
    554         if ( ![self _parse:child1 Pattern:child2 Map:labels] ) {
    555             return NO;
    556         }
    557     }
    558     return YES;
    559 }
    560 
    561 /** Create a tree or node from the indicated tree pattern that closely
    562  *  follows ANTLR tree grammar tree element syntax:
    563  *
    564  * 		(root child1 ... child2).
    565  *
    566  *  You can also just pass in a node: ID
    567  * 
    568  *  Any node can have a text argument: ID[foo]
    569  *  (notice there are no quotes around foo--it's clear it's a string).
    570  *
    571  *  nil is a special name meaning "give me a nil node".  Useful for
    572  *  making lists: (nil A B C) is a list of A B C.
    573  */
    574 - (ANTLRCommonTree *) createTree:(NSString *)pattern
    575 {
    576     ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    577     ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:adaptor];
    578     ANTLRCommonTree * t = [parser pattern];
    579     return t;
    580 }
    581 
    582 /** Compare t1 and t2; return true if token types/text, structure match exactly.
    583  *  The trees are examined in their entirety so that (A B) does not match
    584  *  (A B C) nor (A (B C)). 
    585  // TODO: allow them to pass in a comparator
    586  *  TODO: have a version that is nonstatic so it can use instance adaptor
    587  *
    588  *  I cannot rely on the tree node's equals() implementation as I make
    589  *  no constraints at all on the node types nor interface etc... 
    590  */
    591 - (BOOL)equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
    592 {
    593     return [self _equals:t1 O2:t2 Adaptor:anAdaptor];
    594 }
    595 
    596 /** Compare type, structure, and text of two trees, assuming adaptor in
    597  *  this instance of a TreeWizard.
    598  */
    599 - (BOOL)equals:(id)t1 O2:(id)t2
    600 {
    601     return [self _equals:t1 O2:t2 Adaptor:adaptor];
    602 }
    603 
    604 - (BOOL) _equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
    605 {
    606     // make sure both are non-nil
    607     if ( t1==nil || t2==nil ) {
    608         return NO;
    609     }
    610     // check roots
    611     if ( [anAdaptor getType:t1] != [anAdaptor getType:t2] ) {
    612         return NO;
    613     }
    614     if ( ![[anAdaptor getText:t1] isEqualTo:[anAdaptor getText:t2]] ) {
    615         return NO;
    616     }
    617     // check children
    618     NSInteger n1 = [anAdaptor getChildCount:t1];
    619     NSInteger n2 = [anAdaptor getChildCount:t2];
    620     if ( n1 != n2 ) {
    621         return NO;
    622     }
    623     for (int i=0; i<n1; i++) {
    624         ANTLRCommonTree * child1 = [anAdaptor getChild:t1 At:i];
    625         ANTLRCommonTree * child2 = [anAdaptor getChild:t2 At:i];
    626         if ( ![self _equals:child1 O2:child2 Adaptor:anAdaptor] ) {
    627             return NO;
    628         }
    629     }
    630     return YES;
    631 }
    632 
    633 // TODO: next stuff taken from CommonTreeNodeStream
    634 
    635 /** Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
    636  *  You can override this method to alter how indexing occurs.  The
    637  *  default is to create a
    638  *
    639  *    Map<Integer token type,ArrayList<Integer stream index>>
    640  *
    641  *  This data structure allows you to find all nodes with type INT in order.
    642  *
    643  *  If you really need to find a node of type, say, FUNC quickly then perhaps
    644  *
    645  *    Map<Integertoken type, Map<Object tree node, Integer stream index>>
    646  *
    647  *  would be better for you.  The interior maps map a tree node to
    648  *  the index so you don't have to search linearly for a specific node.
    649  *
    650  *  If you change this method, you will likely need to change
    651  *  getNodeIndex(), which extracts information.
    652 - (void)fillReverseIndex:(ANTLRCommonTree *)node Index:(NSInteger)streamIndex
    653 {
    654     //System.out.println("revIndex "+node+"@"+streamIndex);
    655     if ( tokenTypesToReverseIndex == nil ) {
    656         return; // no indexing if this is empty (nothing of interest)
    657     }
    658     if ( tokenTypeToStreamIndexesMap == nil ) {
    659         tokenTypeToStreamIndexesMap = [ANTLRMap newANTLRMap]; // first indexing op
    660     }
    661     int tokenType = [adaptor getType:node];
    662     Integer tokenTypeI = new Integer(tokenType);
    663     if ( !(tokenTypesToReverseIndex == INDEX_ALL ||
    664             [tokenTypesToReverseIndex contains:tokenTypeI]) ) {
    665         return; // tokenType not of interest
    666     }
    667     NSInteger streamIndexI = streamIndex;
    668     AMutableArray *indexes = (AMutableArray *)[tokenTypeToStreamIndexesMap objectAtIndex:tokenTypeI];
    669     if ( indexes==nil ) {
    670         indexes = [AMutableArray arrayWithCapacity:100]; // no list yet for this token type
    671         indexes.add(streamIndexI); // not there yet, add
    672         [tokenTypeToStreamIndexesMap put:tokenTypeI Idexes:indexes];
    673     }
    674     else {
    675         if ( ![indexes contains:streamIndexI] ) {
    676             [indexes add:streamIndexI]; // not there yet, add
    677         }
    678     }
    679 }
    680  
    681  ** Track the indicated token type in the reverse index.  Call this
    682  *  repeatedly for each type or use variant with Set argument to
    683  *  set all at once.
    684  * @param tokenType
    685 public void reverseIndex:(NSInteger)tokenType
    686 {
    687     if ( tokenTypesToReverseIndex == nil ) {
    688         tokenTypesToReverseIndex = [ANTLRMap newANTLRMap];
    689     }
    690     else if ( tokenTypesToReverseIndex == INDEX_ALL ) {
    691         return;
    692     }
    693     tokenTypesToReverseIndex.add(new Integer(tokenType));
    694 }
    695  
    696 ** Track the indicated token types in the reverse index. Set
    697  *  to INDEX_ALL to track all token types.
    698 public void reverseIndex(Set tokenTypes) {
    699     tokenTypesToReverseIndex = tokenTypes;
    700 }
    701  
    702  ** Given a node pointer, return its index into the node stream.
    703  *  This is not its Token stream index.  If there is no reverse map
    704  *  from node to stream index or the map does not contain entries
    705  *  for node's token type, a linear search of entire stream is used.
    706  *
    707  *  Return -1 if exact node pointer not in stream.
    708 public int getNodeIndex(Object node) {
    709     //System.out.println("get "+node);
    710     if ( tokenTypeToStreamIndexesMap==nil ) {
    711         return getNodeIndexLinearly(node);
    712     }
    713     int tokenType = adaptor.getType(node);
    714     Integer tokenTypeI = new Integer(tokenType);
    715     ArrayList indexes = (ArrayList)tokenTypeToStreamIndexesMap.get(tokenTypeI);
    716     if ( indexes==nil ) {
    717         //System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
    718         return getNodeIndexLinearly(node);
    719     }
    720     for (int i = 0; i < indexes.size(); i++) {
    721         Integer streamIndexI = (Integer)indexes.get(i);
    722         Object n = get(streamIndexI.intValue());
    723         if ( n==node ) {
    724             //System.out.println("found in index; stream index = "+streamIndexI);
    725             return streamIndexI.intValue(); // found it!
    726         }
    727     }
    728     return -1;
    729 }
    730  
    731 */
    732 
    733 @synthesize adaptor;
    734 @synthesize tokenNameToTypeMap;
    735 @end
    736