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