//
//  ANTLRTreeWizard.m
//  ANTLR
//
//  Created by Alan Condit on 6/18/10.
// [The "BSD licence"]
// Copyright (c) 2010 Alan Condit
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import "ANTLRTreeWizard.h"
#import "ANTLRTreePatternLexer.h"
#import "ANTLRTreePatternParser.h"
#import "ANTLRIntArray.h"

@implementation ANTLRVisitor

+ (ANTLRVisitor *)newANTLRVisitor:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
{
    return [[ANTLRVisitor alloc] initWithAction:anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2];
}

- (id) initWithAction:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
{
    if ((self = [super init]) != nil) {
        action = anAction;
        actor = anActor;
        if ( actor ) [actor retain];
        object1 = anObject1;
        if ( object1 ) [object1 retain];
        object2 = anObject2;
        if ( object2 ) [object2 retain];
    }
    return self;
}

- (void) dealloc
{
#ifdef DEBUG_DEALLOC
    NSLog( @"called dealloc in ANTLRVisitor" );
#endif
    if ( actor ) [actor release];
    if ( object1 ) [object1 release];
    if ( object2 ) [object2 release];
    [super dealloc];
}

- (void) visit:(ANTLRCommonTree *)t Parent:(ANTLRCommonTree *)parent ChildIndex:(NSInteger)childIndex Map:(ANTLRMap *)labels
{
    switch (action) {
        case 0:
            [(ANTLRMap *)object2 /* labels */ clear];
            if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:object2 /* labels */] ) {
                [self visit:t Parent:parent ChildIndex:childIndex Map:object2 /* labels */];
            }
            break;
        case 1:
            if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:nil] ) {
                [(AMutableArray *)object2/* subtrees */ addObject:t];
            }
            break;
    }
    // [self visit:t];
    return;
}

- (void) visit:(ANTLRCommonTree *)t
{
    [object1 addObject:t];
    return;
}

@synthesize action;
@synthesize actor;
@synthesize object1;
@synthesize object2;
@end

/** When using %label:TOKENNAME in a tree for parse(), we must
 *  track the label.
 */
@implementation ANTLRTreePattern

@synthesize label;
@synthesize hasTextArg;

+ (ANTLRCommonTree *)newANTLRTreePattern:(id<ANTLRToken>)payload
{
    return (ANTLRCommonTree *)[[ANTLRTreePattern alloc] initWithToken:payload];
}

- (id) initWithToken:(id<ANTLRToken>)payload
{
    self = [super initWithToken:payload];
    if ( self != nil ) {
    }
    return (ANTLRCommonTree *)self;
}

- (void) dealloc
{
#ifdef DEBUG_DEALLOC
    NSLog( @"called dealloc in ANTLRTreePattern" );
#endif
    if ( label ) [label release];
    [super dealloc];
}

- (NSString *)toString
{
    if ( label != nil ) {
        return [NSString stringWithFormat:@"\% %@ : %@", label, [super toString]];
    }
    else {
        return [super toString];				
    }
}

@end

@implementation ANTLRWildcardTreePattern

+ (ANTLRWildcardTreePattern *)newANTLRWildcardTreePattern:(id<ANTLRToken>)payload
{
    return(ANTLRWildcardTreePattern *)[[ANTLRWildcardTreePattern alloc] initWithToken:(id<ANTLRToken>)payload];
}

- (id) initWithToken:(id<ANTLRToken>)payload
{
    self = [super initWithToken:payload];
    if ( self != nil ) {
    }
    return self;
}

@end

/** This adaptor creates TreePattern objects for use during scan() */
@implementation ANTLRTreePatternTreeAdaptor

+ (ANTLRTreePatternTreeAdaptor *)newTreeAdaptor
{
    return [[ANTLRTreePatternTreeAdaptor alloc] init];
}

- (id) init
{
    self = [super init];
    if ( self != nil ) {
    }
    return self;
}

- (ANTLRCommonTree *)createTreePattern:(id<ANTLRToken>)payload
{
    return (ANTLRCommonTree *)[super create:payload];
}
          
@end

@implementation ANTLRTreeWizard

// TODO: build indexes for the wizard

/** During fillBuffer(), we can make a reverse index from a set
 *  of token types of interest to the list of indexes into the
 *  node stream.  This lets us convert a node pointer to a
 *  stream index semi-efficiently for a list of interesting
 *  nodes such as function definition nodes (you'll want to seek
 *  to their bodies for an interpreter).  Also useful for doing
 *  dynamic searches; i.e., go find me all PLUS nodes.
 protected Map tokenTypeToStreamIndexesMap;
 
 ** If tokenTypesToReverseIndex set to INDEX_ALL then indexing
 *  occurs for all token types.
 public static final Set INDEX_ALL = new HashSet();
 
 ** A set of token types user would like to index for faster lookup.
 *  If this is INDEX_ALL, then all token types are tracked.  If nil,
 *  then none are indexed.
 protected Set tokenTypesToReverseIndex = nil;
 */

+ (ANTLRTreeWizard *) newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor
{
    return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor];
}

+ (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
{
    return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor Map:aTokenNameToTypeMap];
}

+ (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
{
    return [[ANTLRTreeWizard alloc] initWithTokenNames:anAdaptor TokenNames:theTokNams];
}

+ (ANTLRTreeWizard *)newANTLRTreeWizardWithTokenNames:(NSArray *)theTokNams
{
    return [[ANTLRTreeWizard alloc] initWithTokenNames:theTokNams];
}

- (id) init
{
    if ((self = [super init]) != nil) {
    }
    return self;
}

- (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor
{
    if ((self = [super init]) != nil) {
        adaptor = anAdaptor;
        if ( adaptor ) [adaptor retain];
    }
    return self;
}
            
- (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
{
    if ((self = [super init]) != nil) {
        adaptor = anAdaptor;
        if ( adaptor ) [adaptor retain];
        tokenNameToTypeMap = aTokenNameToTypeMap;
   }
    return self;
}

- (id) initWithTokenNames:(NSArray *)theTokNams
{
    if ((self = [super init]) != nil) {
#pragma warning Fix initWithTokenNames.
        // adaptor = anAdaptor;
        //tokenNameToTypeMap = aTokenNameToTypeMap;
        tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
    }
    return self;
}
             
- (id) initWithTokenNames:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
{
    if ((self = [super init]) != nil) {
        adaptor = anAdaptor;
        if ( adaptor ) [adaptor retain];
        // tokenNameToTypeMap = aTokenNameToTypeMap;
        tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
    }
    return self;
}
            
- (void) dealloc
{
#ifdef DEBUG_DEALLOC
    NSLog( @"called dealloc in ANTLRTreePatternTreeAdaptor" );
#endif
    if ( adaptor ) [adaptor release];
    if ( tokenNameToTypeMap ) [tokenNameToTypeMap release];
    [super dealloc];
}

/** Compute a Map<String, Integer> that is an inverted index of
 *  tokenNames (which maps int token types to names).
 */
- (ANTLRMap *)computeTokenTypes:(NSArray *)theTokNams
{
    ANTLRMap *m = [ANTLRMap newANTLRMap];
    if ( theTokNams == nil ) {
        return m;
    }
    for (int ttype = ANTLRTokenTypeMIN; ttype < [theTokNams count]; ttype++) {
        NSString *name = (NSString *) [theTokNams objectAtIndex:ttype];
        [m putName:name TType:ttype];
    }
    return m;
}

/** Using the map of token names to token types, return the type. */
- (NSInteger)getTokenType:(NSString *)tokenName
{
    if ( tokenNameToTypeMap == nil ) {
        return ANTLRTokenTypeInvalid;
    }
    NSInteger aTType = (NSInteger)[tokenNameToTypeMap getTType:tokenName];
    if ( aTType != -1 ) {
        return aTType;
    }
    return ANTLRTokenTypeInvalid;
}

/** Walk the entire tree and make a node name to nodes mapping.
 *  For now, use recursion but later nonrecursive version may be
 *  more efficient.  Returns Map<Integer, List> where the List is
 *  of your AST node type.  The Integer is the token type of the node.
 *
 *  TODO: save this index so that find and visit are faster
 */
- (ANTLRMap *)index:(ANTLRCommonTree *)t
{
    ANTLRMap *m = [ANTLRMap newANTLRMap];
    [self _index:t Map:m];
    return m;
}

/** Do the work for index */
- (void) _index:(ANTLRCommonTree *)t Map:(ANTLRMap *)m
{
    if ( t==nil ) {
        return;
    }
#pragma warning Fix _index use of ANTLRMap.
    NSInteger ttype = [adaptor getType:t];
    ANTLRMap *elements = (ANTLRMap *)[m getName:ttype];
    if ( elements == nil ) {
        elements = [ANTLRMap newANTLRMapWithLen:100];
        [m putNode:ttype Node:elements];
    }
    [elements addObject:t];
    int n = [adaptor getChildCount:t];
    for (int i=0; i<n; i++) {
        ANTLRCommonTree * child = [adaptor getChild:t At:i];
        [self _index:child Map:m];
    }
}

/** Return a List of tree nodes with token type ttype */
- (AMutableArray *)find:(ANTLRCommonTree *)t Type:(NSInteger)ttype
{
#ifdef DONTUSENOMO
    final List nodes = new ArrayList();
    visit(t, ttype, new TreeWizard.Visitor() {
        public void visit(Object t) {
            [nodes addObject t];
        }
    } );
#endif
    AMutableArray *nodes = [AMutableArray arrayWithCapacity:100];
    ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:3 Actor:self Object:(id)nodes Object:nil];
    [self visit:t Type:ttype Visitor:contextVisitor];
    return nodes;
}

/** Return a List of subtrees matching pattern. */
- (AMutableArray *)find:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
{
    AMutableArray *subtrees = [AMutableArray arrayWithCapacity:100];
    // Create a TreePattern from the pattern
    ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
                                                                                     Wizard:self
                                                                                    Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    ANTLRCommonTree *tpattern = (ANTLRCommonTree *)[parser pattern];
    // don't allow invalid patterns
    if ( tpattern == nil ||
        [tpattern isNil] ||
        [tpattern class] == [ANTLRWildcardTreePattern class] )
    {
        return nil;
    }
    int rootTokenType = [tpattern type];
#ifdef DONTUSENOMO
    visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
        public void visit(Object t, Object parent, int childIndex, Map labels) {
            if ( _parse(t, tpattern, null) ) {
                subtrees.add(t);
            }
        }
    } );
#endif
    ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:1 Actor:self Object:tpattern Object:subtrees];
    [self visit:t Type:rootTokenType Visitor:contextVisitor];
    return subtrees;
}

- (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Type:(NSInteger)ttype
{
    return nil;
}

- (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Pattern:(NSString *)pattern
{
    return nil;
}

/** Visit every ttype node in t, invoking the visitor.  This is a quicker
 *  version of the general visit(t, pattern) method.  The labels arg
 *  of the visitor action method is never set (it's nil) since using
 *  a token type rather than a pattern doesn't let us set a label.
 */
- (void) visit:(ANTLRCommonTree *)t Type:(NSInteger)ttype Visitor:(ANTLRVisitor *)visitor
{
    [self _visit:t Parent:nil ChildIndex:0 Type:ttype Visitor:visitor];
}

/** Do the recursive work for visit */
- (void) _visit:(ANTLRCommonTree *)t
         Parent:(ANTLRCommonTree *)parent
     ChildIndex:(NSInteger)childIndex
           Type:(NSInteger)ttype
        Visitor:(ANTLRVisitor *)visitor
{
    if ( t == nil ) {
        return;
    }
    if ( [adaptor getType:t] == ttype ) {
        [visitor visit:t Parent:parent ChildIndex:childIndex Map:nil];
    }
    int n = [adaptor getChildCount:t];
    for (int i=0; i<n; i++) {
        ANTLRCommonTree * child = [adaptor getChild:t At:i];
        [self _visit:child Parent:t ChildIndex:i Type:ttype Visitor:visitor];
    }
}

/** For all subtrees that match the pattern, execute the visit action.
 *  The implementation uses the root node of the pattern in combination
 *  with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
 *  Patterns with wildcard roots are also not allowed.
 */
- (void)visit:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Visitor:(ANTLRVisitor *)visitor
{
    // Create a TreePattern from the pattern
    ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    ANTLRTreePatternParser *parser =
    [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    ANTLRCommonTree *tpattern = [parser pattern];
    // don't allow invalid patterns
    if ( tpattern == nil ||
        [tpattern isNil] ||
        [tpattern class] == [ANTLRWildcardTreePattern class] )
    {
        return;
    }
    ANTLRMapElement *labels = [ANTLRMap newANTLRMap]; // reused for each _parse
    int rootTokenType = [tpattern type];
#pragma warning This is another one of those screwy nested constructs that I have to figure out
#ifdef DONTUSENOMO
    visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
        public void visit(Object t, Object parent, int childIndex, Map unusedlabels) {
            // the unusedlabels arg is null as visit on token type doesn't set.
            labels.clear();
            if ( _parse(t, tpattern, labels) ) {
                visitor.visit(t, parent, childIndex, labels);
            }
        }
    });
#endif
    ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:0 Actor:self Object:tpattern Object:labels];
    [self visit:t Type:rootTokenType Visitor:contextVisitor];
}

/** Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
 *  on the various nodes and '.' (dot) as the node/subtree wildcard,
 *  return true if the pattern matches and fill the labels Map with
 *  the labels pointing at the appropriate nodes.  Return false if
 *  the pattern is malformed or the tree does not match.
 *
 *  If a node specifies a text arg in pattern, then that must match
 *  for that node in t.
 *
 *  TODO: what's a better way to indicate bad pattern? Exceptions are a hassle 
 */
- (BOOL)parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Map:(ANTLRMap *)labels
{
#ifdef DONTUSENOMO
    TreePatternLexer tokenizer = new TreePatternLexer(pattern);
    TreePatternParser parser =
    new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
    TreePattern tpattern = (TreePattern)parser.pattern();
    /*
     System.out.println("t="+((Tree)t).toStringTree());
     System.out.println("scant="+tpattern.toStringTree());
     */
    boolean matched = _parse(t, tpattern, labels);
    return matched;
#endif
    ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
                                                                                Wizard:self
                                                                               Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
    ANTLRCommonTree *tpattern = [parser pattern];
    /*
     System.out.println("t="+((Tree)t).toStringTree());
     System.out.println("scant="+tpattern.toStringTree());
     */
    //BOOL matched = [self _parse:t Pattern:tpattern Map:labels];
    //return matched;
    return [self _parse:t Pattern:tpattern Map:labels];
}

- (BOOL) parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
{
    return [self parse:t Pattern:pattern Map:nil];
}

/** Do the work for parse. Check to see if the t2 pattern fits the
 *  structure and token types in t1.  Check text if the pattern has
 *  text arguments on nodes.  Fill labels map with pointers to nodes
 *  in tree matched against nodes in pattern with labels.
 */
- (BOOL) _parse:(ANTLRCommonTree *)t1 Pattern:(ANTLRCommonTree *)aTPattern Map:(ANTLRMap *)labels
{
    ANTLRTreePattern *tpattern;
    // make sure both are non-nil
    if ( t1 == nil || aTPattern == nil ) {
        return NO;
    }
    if ( [aTPattern isKindOfClass:[ANTLRWildcardTreePattern class]] ) {
        tpattern = (ANTLRTreePattern *)aTPattern;
    }
    // check roots (wildcard matches anything)
    if ( [tpattern class] != [ANTLRWildcardTreePattern class] ) {
        if ( [adaptor getType:t1] != [tpattern type] )
            return NO;
        // if pattern has text, check node text
        if ( tpattern.hasTextArg && ![[adaptor getText:t1] isEqualToString:[tpattern text]] ) {
            return NO;
        }
    }
    if ( tpattern.label != nil && labels!=nil ) {
        // map label in pattern to node in t1
        [labels putName:tpattern.label Node:t1];
    }
    // check children
    int n1 = [adaptor getChildCount:t1];
    int n2 = [tpattern getChildCount];
    if ( n1 != n2 ) {
        return NO;
    }
    for (int i=0; i<n1; i++) {
        ANTLRCommonTree * child1 = [adaptor getChild:t1 At:i];
        ANTLRCommonTree *child2 = (ANTLRCommonTree *)[tpattern getChild:i];
        if ( ![self _parse:child1 Pattern:child2 Map:labels] ) {
            return NO;
        }
    }
    return YES;
}

/** Create a tree or node from the indicated tree pattern that closely
 *  follows ANTLR tree grammar tree element syntax:
 *
 * 		(root child1 ... child2).
 *
 *  You can also just pass in a node: ID
 * 
 *  Any node can have a text argument: ID[foo]
 *  (notice there are no quotes around foo--it's clear it's a string).
 *
 *  nil is a special name meaning "give me a nil node".  Useful for
 *  making lists: (nil A B C) is a list of A B C.
 */
- (ANTLRCommonTree *) createTree:(NSString *)pattern
{
    ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
    ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:adaptor];
    ANTLRCommonTree * t = [parser pattern];
    return t;
}

/** Compare t1 and t2; return true if token types/text, structure match exactly.
 *  The trees are examined in their entirety so that (A B) does not match
 *  (A B C) nor (A (B C)). 
 // TODO: allow them to pass in a comparator
 *  TODO: have a version that is nonstatic so it can use instance adaptor
 *
 *  I cannot rely on the tree node's equals() implementation as I make
 *  no constraints at all on the node types nor interface etc... 
 */
- (BOOL)equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
{
    return [self _equals:t1 O2:t2 Adaptor:anAdaptor];
}

/** Compare type, structure, and text of two trees, assuming adaptor in
 *  this instance of a TreeWizard.
 */
- (BOOL)equals:(id)t1 O2:(id)t2
{
    return [self _equals:t1 O2:t2 Adaptor:adaptor];
}

- (BOOL) _equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
{
    // make sure both are non-nil
    if ( t1==nil || t2==nil ) {
        return NO;
    }
    // check roots
    if ( [anAdaptor getType:t1] != [anAdaptor getType:t2] ) {
        return NO;
    }
    if ( ![[anAdaptor getText:t1] isEqualTo:[anAdaptor getText:t2]] ) {
        return NO;
    }
    // check children
    NSInteger n1 = [anAdaptor getChildCount:t1];
    NSInteger n2 = [anAdaptor getChildCount:t2];
    if ( n1 != n2 ) {
        return NO;
    }
    for (int i=0; i<n1; i++) {
        ANTLRCommonTree * child1 = [anAdaptor getChild:t1 At:i];
        ANTLRCommonTree * child2 = [anAdaptor getChild:t2 At:i];
        if ( ![self _equals:child1 O2:child2 Adaptor:anAdaptor] ) {
            return NO;
        }
    }
    return YES;
}

// TODO: next stuff taken from CommonTreeNodeStream

/** Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
 *  You can override this method to alter how indexing occurs.  The
 *  default is to create a
 *
 *    Map<Integer token type,ArrayList<Integer stream index>>
 *
 *  This data structure allows you to find all nodes with type INT in order.
 *
 *  If you really need to find a node of type, say, FUNC quickly then perhaps
 *
 *    Map<Integertoken type, Map<Object tree node, Integer stream index>>
 *
 *  would be better for you.  The interior maps map a tree node to
 *  the index so you don't have to search linearly for a specific node.
 *
 *  If you change this method, you will likely need to change
 *  getNodeIndex(), which extracts information.
- (void)fillReverseIndex:(ANTLRCommonTree *)node Index:(NSInteger)streamIndex
{
    //System.out.println("revIndex "+node+"@"+streamIndex);
    if ( tokenTypesToReverseIndex == nil ) {
        return; // no indexing if this is empty (nothing of interest)
    }
    if ( tokenTypeToStreamIndexesMap == nil ) {
        tokenTypeToStreamIndexesMap = [ANTLRMap newANTLRMap]; // first indexing op
    }
    int tokenType = [adaptor getType:node];
    Integer tokenTypeI = new Integer(tokenType);
    if ( !(tokenTypesToReverseIndex == INDEX_ALL ||
            [tokenTypesToReverseIndex contains:tokenTypeI]) ) {
        return; // tokenType not of interest
    }
    NSInteger streamIndexI = streamIndex;
    AMutableArray *indexes = (AMutableArray *)[tokenTypeToStreamIndexesMap objectAtIndex:tokenTypeI];
    if ( indexes==nil ) {
        indexes = [AMutableArray arrayWithCapacity:100]; // no list yet for this token type
        indexes.add(streamIndexI); // not there yet, add
        [tokenTypeToStreamIndexesMap put:tokenTypeI Idexes:indexes];
    }
    else {
        if ( ![indexes contains:streamIndexI] ) {
            [indexes add:streamIndexI]; // not there yet, add
        }
    }
}
 
 ** Track the indicated token type in the reverse index.  Call this
 *  repeatedly for each type or use variant with Set argument to
 *  set all at once.
 * @param tokenType
public void reverseIndex:(NSInteger)tokenType
{
    if ( tokenTypesToReverseIndex == nil ) {
        tokenTypesToReverseIndex = [ANTLRMap newANTLRMap];
    }
    else if ( tokenTypesToReverseIndex == INDEX_ALL ) {
        return;
    }
    tokenTypesToReverseIndex.add(new Integer(tokenType));
}
 
** Track the indicated token types in the reverse index. Set
 *  to INDEX_ALL to track all token types.
public void reverseIndex(Set tokenTypes) {
    tokenTypesToReverseIndex = tokenTypes;
}
 
 ** Given a node pointer, return its index into the node stream.
 *  This is not its Token stream index.  If there is no reverse map
 *  from node to stream index or the map does not contain entries
 *  for node's token type, a linear search of entire stream is used.
 *
 *  Return -1 if exact node pointer not in stream.
public int getNodeIndex(Object node) {
    //System.out.println("get "+node);
    if ( tokenTypeToStreamIndexesMap==nil ) {
        return getNodeIndexLinearly(node);
    }
    int tokenType = adaptor.getType(node);
    Integer tokenTypeI = new Integer(tokenType);
    ArrayList indexes = (ArrayList)tokenTypeToStreamIndexesMap.get(tokenTypeI);
    if ( indexes==nil ) {
        //System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
        return getNodeIndexLinearly(node);
    }
    for (int i = 0; i < indexes.size(); i++) {
        Integer streamIndexI = (Integer)indexes.get(i);
        Object n = get(streamIndexI.intValue());
        if ( n==node ) {
            //System.out.println("found in index; stream index = "+streamIndexI);
            return streamIndexI.intValue(); // found it!
        }
    }
    return -1;
}
 
*/

@synthesize adaptor;
@synthesize tokenNameToTypeMap;
@end