xref: /aosp_15_r20/external/antlr/runtime/ObjC/Framework/UnbufferedCommonTreeNodeStream.m (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot// [The "BSD licence"]
2*16467b97STreehugger Robot// Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit
3*16467b97STreehugger Robot// All rights reserved.
4*16467b97STreehugger Robot//
5*16467b97STreehugger Robot// Redistribution and use in source and binary forms, with or without
6*16467b97STreehugger Robot// modification, are permitted provided that the following conditions
7*16467b97STreehugger Robot// are met:
8*16467b97STreehugger Robot// 1. Redistributions of source code must retain the above copyright
9*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer.
10*16467b97STreehugger Robot// 2. Redistributions in binary form must reproduce the above copyright
11*16467b97STreehugger Robot//    notice, this list of conditions and the following disclaimer in the
12*16467b97STreehugger Robot//    documentation and/or other materials provided with the distribution.
13*16467b97STreehugger Robot// 3. The name of the author may not be used to endorse or promote products
14*16467b97STreehugger Robot//    derived from this software without specific prior written permission.
15*16467b97STreehugger Robot//
16*16467b97STreehugger Robot// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*16467b97STreehugger Robot// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*16467b97STreehugger Robot// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*16467b97STreehugger Robot// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*16467b97STreehugger Robot// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*16467b97STreehugger Robot// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*16467b97STreehugger Robot// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*16467b97STreehugger Robot// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*16467b97STreehugger Robot// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*16467b97STreehugger Robot// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*16467b97STreehugger Robot
27*16467b97STreehugger Robot
28*16467b97STreehugger Robot#import "UnbufferedCommonTreeNodeStream.h"
29*16467b97STreehugger Robot#import "UnbufferedCommonTreeNodeStreamState.h"
30*16467b97STreehugger Robot#import "BaseTree.h"
31*16467b97STreehugger Robot#import "Token.h"
32*16467b97STreehugger Robot
33*16467b97STreehugger Robot#define INITIAL_LOOKAHEAD_BUFFER_SIZE 5
34*16467b97STreehugger Robot@implementation ANTLRUnbufferedCommonTreeNodeStream
35*16467b97STreehugger Robot
36*16467b97STreehugger Robot@synthesize root;
37*16467b97STreehugger Robot@synthesize currentNode;
38*16467b97STreehugger Robot@synthesize previousNode;
39*16467b97STreehugger Robot@synthesize treeAdaptor;
40*16467b97STreehugger Robot@synthesize tokenStream;
41*16467b97STreehugger Robot@synthesize nodeStack;
42*16467b97STreehugger Robot@synthesize indexStack;
43*16467b97STreehugger Robot@synthesize markers;
44*16467b97STreehugger Robot@synthesize lastMarker;
45*16467b97STreehugger Robot@synthesize currentChildIndex;
46*16467b97STreehugger Robot@synthesize absoluteNodeIndex;
47*16467b97STreehugger Robot@synthesize lookahead;
48*16467b97STreehugger Robot@synthesize head;
49*16467b97STreehugger Robot@synthesize tail;
50*16467b97STreehugger Robot
51*16467b97STreehugger Robot- (id) initWithTree:(CommonTree *)theTree
52*16467b97STreehugger Robot{
53*16467b97STreehugger Robot	return [self initWithTree:theTree treeAdaptor:nil];
54*16467b97STreehugger Robot}
55*16467b97STreehugger Robot
56*16467b97STreehugger Robot- (id) initWithTree:(CommonTree *)theTree treeAdaptor:(CommonTreeAdaptor *)theAdaptor
57*16467b97STreehugger Robot{
58*16467b97STreehugger Robot	if ((self = [super init]) != nil) {
59*16467b97STreehugger Robot		[self setRoot:theTree];
60*16467b97STreehugger Robot		if ( theAdaptor == nil )
61*16467b97STreehugger Robot			[self setTreeAdaptor:[CommonTreeAdaptor newTreeAdaptor]];
62*16467b97STreehugger Robot		else
63*16467b97STreehugger Robot			[self setTreeAdaptor:theAdaptor];
64*16467b97STreehugger Robot		nodeStack = [[NSMutableArray arrayWithCapacity:5] retain];
65*16467b97STreehugger Robot		indexStack = [[NSMutableArray arrayWithCapacity:5] retain];
66*16467b97STreehugger Robot		markers = [[PtrBuffer newPtrBufferWithLen:100] retain];
67*16467b97STreehugger Robot        // [markers insertObject:[NSNull null] atIndex:0];	// markers is one based - maybe fix this later
68*16467b97STreehugger Robot		lookahead = [NSMutableArray arrayWithCapacity:INITIAL_LOOKAHEAD_BUFFER_SIZE];	// lookahead is filled with [NSNull null] in -reset
69*16467b97STreehugger Robot        [lookahead retain];
70*16467b97STreehugger Robot		[self reset];
71*16467b97STreehugger Robot	}
72*16467b97STreehugger Robot	return self;
73*16467b97STreehugger Robot}
74*16467b97STreehugger Robot
75*16467b97STreehugger Robot- (void) dealloc
76*16467b97STreehugger Robot{
77*16467b97STreehugger Robot	[self setRoot:nil];
78*16467b97STreehugger Robot	[self setTreeAdaptor:nil];
79*16467b97STreehugger Robot
80*16467b97STreehugger Robot	[nodeStack release];	nodeStack = nil;
81*16467b97STreehugger Robot	[indexStack release];	indexStack = nil;
82*16467b97STreehugger Robot	[markers release];		markers = nil;
83*16467b97STreehugger Robot	[lookahead release];	lookahead = nil;
84*16467b97STreehugger Robot
85*16467b97STreehugger Robot	[super dealloc];
86*16467b97STreehugger Robot}
87*16467b97STreehugger Robot
88*16467b97STreehugger Robot- (void) reset
89*16467b97STreehugger Robot{
90*16467b97STreehugger Robot	currentNode = root;
91*16467b97STreehugger Robot	previousNode = nil;
92*16467b97STreehugger Robot	currentChildIndex = -1;
93*16467b97STreehugger Robot	absoluteNodeIndex = -1;
94*16467b97STreehugger Robot	head = tail = 0;
95*16467b97STreehugger Robot	[nodeStack removeAllObjects];
96*16467b97STreehugger Robot	[indexStack removeAllObjects];
97*16467b97STreehugger Robot	[markers removeAllObjects];
98*16467b97STreehugger Robot    // [markers insertObject:[NSNull null] atIndex:0];	// markers is one based - maybe fix this later
99*16467b97STreehugger Robot	[lookahead removeAllObjects];
100*16467b97STreehugger Robot	// TODO: this is not ideal, but works for now. optimize later
101*16467b97STreehugger Robot	int i;
102*16467b97STreehugger Robot	for (i = 0; i < INITIAL_LOOKAHEAD_BUFFER_SIZE; i++)
103*16467b97STreehugger Robot		[lookahead addObject:[NSNull null]];
104*16467b97STreehugger Robot}
105*16467b97STreehugger Robot
106*16467b97STreehugger Robot
107*16467b97STreehugger Robot#pragma mark ANTLRTreeNodeStream conformance
108*16467b97STreehugger Robot
109*16467b97STreehugger Robot- (id) LT:(NSInteger)k
110*16467b97STreehugger Robot{
111*16467b97STreehugger Robot	if (k == -1)
112*16467b97STreehugger Robot		return previousNode;
113*16467b97STreehugger Robot	if (k < 0)
114*16467b97STreehugger Robot		@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-LT: looking back more than one node unsupported for unbuffered streams" userInfo:nil];
115*16467b97STreehugger Robot	if (k == 0)
116*16467b97STreehugger Robot		return BaseTree.INVALID_NODE;
117*16467b97STreehugger Robot	[self fillBufferWithLookahead:k];
118*16467b97STreehugger Robot	return [lookahead objectAtIndex:(head+k-1) % [lookahead count]];
119*16467b97STreehugger Robot}
120*16467b97STreehugger Robot
121*16467b97STreehugger Robot- (id) treeSource
122*16467b97STreehugger Robot{
123*16467b97STreehugger Robot	return [self root];
124*16467b97STreehugger Robot}
125*16467b97STreehugger Robot
126*16467b97STreehugger Robot- (id<TreeAdaptor>) getTreeAdaptor;
127*16467b97STreehugger Robot{
128*16467b97STreehugger Robot	return treeAdaptor;
129*16467b97STreehugger Robot}
130*16467b97STreehugger Robot
131*16467b97STreehugger Robot- (void)setTreeAdaptor:(id<TreeAdaptor>)aTreeAdaptor
132*16467b97STreehugger Robot{
133*16467b97STreehugger Robot    if (treeAdaptor != aTreeAdaptor) {
134*16467b97STreehugger Robot        [aTreeAdaptor retain];
135*16467b97STreehugger Robot        [treeAdaptor release];
136*16467b97STreehugger Robot        treeAdaptor = aTreeAdaptor;
137*16467b97STreehugger Robot    }
138*16467b97STreehugger Robot}
139*16467b97STreehugger Robot
140*16467b97STreehugger Robot- (id<TokenStream>) getTokenStream
141*16467b97STreehugger Robot{
142*16467b97STreehugger Robot	return tokenStream;
143*16467b97STreehugger Robot}
144*16467b97STreehugger Robot
145*16467b97STreehugger Robot- (void) setTokenStream:(id<TokenStream>)aTokenStream
146*16467b97STreehugger Robot{
147*16467b97STreehugger Robot	if (tokenStream != aTokenStream) {
148*16467b97STreehugger Robot		[tokenStream release];
149*16467b97STreehugger Robot		[aTokenStream retain];
150*16467b97STreehugger Robot		tokenStream = aTokenStream;
151*16467b97STreehugger Robot	}
152*16467b97STreehugger Robot}
153*16467b97STreehugger Robot
154*16467b97STreehugger Robot- (void) setUsesUniqueNavigationNodes:(BOOL)flag
155*16467b97STreehugger Robot{
156*16467b97STreehugger Robot	shouldUseUniqueNavigationNodes = flag;
157*16467b97STreehugger Robot}
158*16467b97STreehugger Robot
159*16467b97STreehugger Robot- (id) nodeAtIndex:(NSUInteger) idx
160*16467b97STreehugger Robot{
161*16467b97STreehugger Robot	@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-nodeAtIndex: unsupported for unbuffered streams" userInfo:nil];
162*16467b97STreehugger Robot}
163*16467b97STreehugger Robot
164*16467b97STreehugger Robot- (NSString *) toString
165*16467b97STreehugger Robot{
166*16467b97STreehugger Robot	@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-toString unsupported for unbuffered streams" userInfo:nil];
167*16467b97STreehugger Robot}
168*16467b97STreehugger Robot
169*16467b97STreehugger Robot- (NSString *) toStringWithRange:(NSRange) aRange
170*16467b97STreehugger Robot{
171*16467b97STreehugger Robot	@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-toString: unsupported for unbuffered streams" userInfo:nil];
172*16467b97STreehugger Robot}
173*16467b97STreehugger Robot
174*16467b97STreehugger Robot- (NSString *) toStringFromNode:(id)startNode ToNode:(id)stopNode
175*16467b97STreehugger Robot{
176*16467b97STreehugger Robot	@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-toStringFromNode:toNode: unsupported for unbuffered streams" userInfo:nil];
177*16467b97STreehugger Robot}
178*16467b97STreehugger Robot
179*16467b97STreehugger Robot#pragma mark ANTLRIntStream conformance
180*16467b97STreehugger Robot
181*16467b97STreehugger Robot- (void) consume
182*16467b97STreehugger Robot{
183*16467b97STreehugger Robot	[self fillBufferWithLookahead:1];
184*16467b97STreehugger Robot	absoluteNodeIndex++;
185*16467b97STreehugger Robot	previousNode = [lookahead objectAtIndex:head];
186*16467b97STreehugger Robot	head = (head+1) % [lookahead count];
187*16467b97STreehugger Robot}
188*16467b97STreehugger Robot
189*16467b97STreehugger Robot- (NSInteger) LA:(NSUInteger) i
190*16467b97STreehugger Robot{
191*16467b97STreehugger Robot	CommonTree *node = [self LT:i];
192*16467b97STreehugger Robot	if (!node)
193*16467b97STreehugger Robot		return TokenTypeInvalid;
194*16467b97STreehugger Robot	int ttype = [node getType];
195*16467b97STreehugger Robot	return ttype;
196*16467b97STreehugger Robot}
197*16467b97STreehugger Robot
198*16467b97STreehugger Robot- (NSUInteger) mark
199*16467b97STreehugger Robot{
200*16467b97STreehugger Robot	ANTLRUnbufferedCommonTreeNodeStreamState *state = [[[ANTLRUnbufferedCommonTreeNodeStreamState alloc] init] retain];
201*16467b97STreehugger Robot	[state setCurrentNode:currentNode];
202*16467b97STreehugger Robot	[state setPreviousNode:previousNode];
203*16467b97STreehugger Robot	[state setIndexStackSize:[indexStack count]];
204*16467b97STreehugger Robot	[state setNodeStackSize:[nodeStack count]];
205*16467b97STreehugger Robot	[state setCurrentChildIndex:currentChildIndex];
206*16467b97STreehugger Robot	[state setAbsoluteNodeIndex:absoluteNodeIndex];
207*16467b97STreehugger Robot	unsigned int lookaheadSize = [self lookaheadSize];
208*16467b97STreehugger Robot	unsigned int k;
209*16467b97STreehugger Robot	for ( k = 0; k < lookaheadSize; k++) {
210*16467b97STreehugger Robot		[state addToLookahead:[self LT:k+1]];
211*16467b97STreehugger Robot	}
212*16467b97STreehugger Robot	[markers addObject:state];
213*16467b97STreehugger Robot	//[state release];
214*16467b97STreehugger Robot	return [markers count];
215*16467b97STreehugger Robot}
216*16467b97STreehugger Robot
217*16467b97STreehugger Robot- (NSUInteger) getIndex
218*16467b97STreehugger Robot{
219*16467b97STreehugger Robot	return absoluteNodeIndex + 1;
220*16467b97STreehugger Robot}
221*16467b97STreehugger Robot
222*16467b97STreehugger Robot- (void) rewind:(NSUInteger) marker
223*16467b97STreehugger Robot{
224*16467b97STreehugger Robot	if ( [markers count] < marker ) {
225*16467b97STreehugger Robot		return;
226*16467b97STreehugger Robot	}
227*16467b97STreehugger Robot	ANTLRUnbufferedCommonTreeNodeStreamState *state = [markers objectAtIndex:marker];
228*16467b97STreehugger Robot	[markers removeObjectAtIndex:marker];
229*16467b97STreehugger Robot
230*16467b97STreehugger Robot	absoluteNodeIndex = [state absoluteNodeIndex];
231*16467b97STreehugger Robot	currentChildIndex = [state currentChildIndex];
232*16467b97STreehugger Robot	currentNode = [state currentNode];
233*16467b97STreehugger Robot	previousNode = [state previousNode];
234*16467b97STreehugger Robot	// drop node and index stacks back to old size
235*16467b97STreehugger Robot	[nodeStack removeObjectsInRange:NSMakeRange([state nodeStackSize], [nodeStack count]-[state nodeStackSize])];
236*16467b97STreehugger Robot	[indexStack removeObjectsInRange:NSMakeRange([state indexStackSize], [indexStack count]-[state indexStackSize])];
237*16467b97STreehugger Robot
238*16467b97STreehugger Robot	head = tail = 0; // wack lookahead buffer and then refill
239*16467b97STreehugger Robot	[lookahead release];
240*16467b97STreehugger Robot	lookahead = [[NSMutableArray alloc] initWithArray:[state lookahead]];
241*16467b97STreehugger Robot	tail = [lookahead count];
242*16467b97STreehugger Robot	// make some room after the restored lookahead, so that the above line is not a bug ;)
243*16467b97STreehugger Robot	// this also ensures that a subsequent -addLookahead: will not immediately need to resize the buffer
244*16467b97STreehugger Robot	[lookahead addObjectsFromArray:[NSArray arrayWithObjects:[NSNull null], [NSNull null], [NSNull null], [NSNull null], [NSNull null], nil]];
245*16467b97STreehugger Robot}
246*16467b97STreehugger Robot
247*16467b97STreehugger Robot- (void) rewind
248*16467b97STreehugger Robot{
249*16467b97STreehugger Robot	[self rewind:[markers count]];
250*16467b97STreehugger Robot}
251*16467b97STreehugger Robot
252*16467b97STreehugger Robot- (void) release:(NSUInteger) marker
253*16467b97STreehugger Robot{
254*16467b97STreehugger Robot	@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-release: unsupported for unbuffered streams" userInfo:nil];
255*16467b97STreehugger Robot}
256*16467b97STreehugger Robot
257*16467b97STreehugger Robot- (void) seek:(NSUInteger) anIndex
258*16467b97STreehugger Robot{
259*16467b97STreehugger Robot	if ( anIndex < (NSUInteger) index )
260*16467b97STreehugger Robot		@throw [NSException exceptionWithName:@"ANTLRTreeException" reason:@"-seek: backwards unsupported for unbuffered streams" userInfo:nil];
261*16467b97STreehugger Robot	while ( (NSUInteger) index < anIndex ) {
262*16467b97STreehugger Robot		[self consume];
263*16467b97STreehugger Robot	}
264*16467b97STreehugger Robot}
265*16467b97STreehugger Robot
266*16467b97STreehugger Robot- (NSUInteger) size;
267*16467b97STreehugger Robot{
268*16467b97STreehugger Robot	return absoluteNodeIndex + 1;	// not entirely correct, but cheap.
269*16467b97STreehugger Robot}
270*16467b97STreehugger Robot
271*16467b97STreehugger Robot
272*16467b97STreehugger Robot#pragma mark Lookahead Handling
273*16467b97STreehugger Robot- (void) addLookahead:(id<BaseTree>)aNode
274*16467b97STreehugger Robot{
275*16467b97STreehugger Robot	[lookahead replaceObjectAtIndex:tail withObject:aNode];
276*16467b97STreehugger Robot	tail = (tail+1) % [lookahead count];
277*16467b97STreehugger Robot
278*16467b97STreehugger Robot	if ( tail == head ) {
279*16467b97STreehugger Robot		NSMutableArray *newLookahead = [[[NSMutableArray alloc] initWithCapacity:[lookahead count]*2] retain];
280*16467b97STreehugger Robot
281*16467b97STreehugger Robot		NSRange headRange = NSMakeRange(head, [lookahead count]-head);
282*16467b97STreehugger Robot		NSRange tailRange = NSMakeRange(0, tail);
283*16467b97STreehugger Robot
284*16467b97STreehugger Robot		[newLookahead addObjectsFromArray:[lookahead objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:headRange]]];
285*16467b97STreehugger Robot		[newLookahead addObjectsFromArray:[lookahead objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:tailRange]]];
286*16467b97STreehugger Robot
287*16467b97STreehugger Robot		unsigned int i;
288*16467b97STreehugger Robot		unsigned int lookaheadCount = [newLookahead count];
289*16467b97STreehugger Robot		for (i = 0; i < lookaheadCount; i++)
290*16467b97STreehugger Robot			[newLookahead addObject:[NSNull null]];
291*16467b97STreehugger Robot		[lookahead release];
292*16467b97STreehugger Robot		lookahead = newLookahead;
293*16467b97STreehugger Robot
294*16467b97STreehugger Robot		head = 0;
295*16467b97STreehugger Robot		tail = lookaheadCount;	// tail is the location the _next_ lookahead node will end up in, not the last element's idx itself!
296*16467b97STreehugger Robot	}
297*16467b97STreehugger Robot
298*16467b97STreehugger Robot}
299*16467b97STreehugger Robot
300*16467b97STreehugger Robot- (NSUInteger) lookaheadSize
301*16467b97STreehugger Robot{
302*16467b97STreehugger Robot	return tail < head
303*16467b97STreehugger Robot		? ([lookahead count] - head + tail)
304*16467b97STreehugger Robot		: (tail - head);
305*16467b97STreehugger Robot}
306*16467b97STreehugger Robot
307*16467b97STreehugger Robot- (void) fillBufferWithLookahead:(NSInteger)k
308*16467b97STreehugger Robot{
309*16467b97STreehugger Robot	unsigned int n = [self lookaheadSize];
310*16467b97STreehugger Robot	unsigned int i;
311*16467b97STreehugger Robot	id lookaheadObject = self; // any valid object would do.
312*16467b97STreehugger Robot	for (i=1; i <= k-n && lookaheadObject != nil; i++) {
313*16467b97STreehugger Robot		lookaheadObject = [self nextObject];
314*16467b97STreehugger Robot	}
315*16467b97STreehugger Robot}
316*16467b97STreehugger Robot
317*16467b97STreehugger Robot- (id) nextObject
318*16467b97STreehugger Robot{
319*16467b97STreehugger Robot	// NOTE: this could/should go into an NSEnumerator subclass for treenode streams.
320*16467b97STreehugger Robot	if (currentNode == nil) {
321*16467b97STreehugger Robot        if ( navigationNodeEOF == nil ) {
322*16467b97STreehugger Robot            navigationNodeEOF = [[TreeNavigationNodeEOF alloc] init];
323*16467b97STreehugger Robot        }
324*16467b97STreehugger Robot		[self addLookahead:navigationNodeEOF];
325*16467b97STreehugger Robot		return nil;
326*16467b97STreehugger Robot	}
327*16467b97STreehugger Robot	if (currentChildIndex == -1) {
328*16467b97STreehugger Robot		return [self handleRootNode];
329*16467b97STreehugger Robot	}
330*16467b97STreehugger Robot	if (currentChildIndex < (NSInteger)[currentNode getChildCount]) {
331*16467b97STreehugger Robot		return [self visitChild:currentChildIndex];
332*16467b97STreehugger Robot	}
333*16467b97STreehugger Robot	[self walkBackToMostRecentNodeWithUnvisitedChildren];
334*16467b97STreehugger Robot	if (currentNode != nil) {
335*16467b97STreehugger Robot		return [self visitChild:currentChildIndex];
336*16467b97STreehugger Robot	}
337*16467b97STreehugger Robot
338*16467b97STreehugger Robot	return nil;
339*16467b97STreehugger Robot}
340*16467b97STreehugger Robot
341*16467b97STreehugger Robot#pragma mark Node visiting
342*16467b97STreehugger Robot- (CommonTree *) handleRootNode
343*16467b97STreehugger Robot{
344*16467b97STreehugger Robot	CommonTree *node = currentNode;
345*16467b97STreehugger Robot	currentChildIndex = 0;
346*16467b97STreehugger Robot	if ([node isNil]) {
347*16467b97STreehugger Robot		node = [self visitChild:currentChildIndex];
348*16467b97STreehugger Robot	} else {
349*16467b97STreehugger Robot		[self addLookahead:node];
350*16467b97STreehugger Robot		if ([currentNode getChildCount] == 0) {
351*16467b97STreehugger Robot			currentNode = nil;
352*16467b97STreehugger Robot		}
353*16467b97STreehugger Robot	}
354*16467b97STreehugger Robot	return node;
355*16467b97STreehugger Robot}
356*16467b97STreehugger Robot
357*16467b97STreehugger Robot- (CommonTree *) visitChild:(NSInteger)childNumber
358*16467b97STreehugger Robot{
359*16467b97STreehugger Robot	CommonTree *node = nil;
360*16467b97STreehugger Robot
361*16467b97STreehugger Robot	[nodeStack addObject:currentNode];
362*16467b97STreehugger Robot	[indexStack addObject:[NSNumber numberWithInt:childNumber]];
363*16467b97STreehugger Robot	if (childNumber == 0 && ![currentNode isNil])
364*16467b97STreehugger Robot		[self addNavigationNodeWithType:TokenTypeDOWN];
365*16467b97STreehugger Robot
366*16467b97STreehugger Robot	currentNode = [currentNode getChild:childNumber];
367*16467b97STreehugger Robot	currentChildIndex = 0;
368*16467b97STreehugger Robot	node = currentNode;  // record node to return
369*16467b97STreehugger Robot	[self addLookahead:node];
370*16467b97STreehugger Robot	[self walkBackToMostRecentNodeWithUnvisitedChildren];
371*16467b97STreehugger Robot	return node;
372*16467b97STreehugger Robot}
373*16467b97STreehugger Robot
374*16467b97STreehugger Robot- (void) walkBackToMostRecentNodeWithUnvisitedChildren
375*16467b97STreehugger Robot{
376*16467b97STreehugger Robot	while (currentNode != nil && currentChildIndex >= (NSInteger)[currentNode getChildCount])
377*16467b97STreehugger Robot	{
378*16467b97STreehugger Robot		currentNode = (CommonTree *)[nodeStack lastObject];
379*16467b97STreehugger Robot		[nodeStack removeLastObject];
380*16467b97STreehugger Robot		currentChildIndex = [(NSNumber *)[indexStack lastObject] intValue];
381*16467b97STreehugger Robot		[indexStack removeLastObject];
382*16467b97STreehugger Robot		currentChildIndex++; // move to next child
383*16467b97STreehugger Robot		if (currentChildIndex >= (NSInteger)[currentNode getChildCount]) {
384*16467b97STreehugger Robot			if (![currentNode isNil]) {
385*16467b97STreehugger Robot				[self addNavigationNodeWithType:TokenTypeUP];
386*16467b97STreehugger Robot			}
387*16467b97STreehugger Robot			if (currentNode == root) { // we done yet?
388*16467b97STreehugger Robot				currentNode = nil;
389*16467b97STreehugger Robot			}
390*16467b97STreehugger Robot		}
391*16467b97STreehugger Robot	}
392*16467b97STreehugger Robot
393*16467b97STreehugger Robot}
394*16467b97STreehugger Robot
395*16467b97STreehugger Robot- (void) addNavigationNodeWithType:(NSInteger)tokenType
396*16467b97STreehugger Robot{
397*16467b97STreehugger Robot	// TODO: this currently ignores shouldUseUniqueNavigationNodes.
398*16467b97STreehugger Robot	switch (tokenType) {
399*16467b97STreehugger Robot		case TokenTypeDOWN: {
400*16467b97STreehugger Robot            if (navigationNodeDown == nil) {
401*16467b97STreehugger Robot                navigationNodeDown = [[TreeNavigationNodeDown alloc] init];
402*16467b97STreehugger Robot            }
403*16467b97STreehugger Robot			[self addLookahead:navigationNodeDown];
404*16467b97STreehugger Robot			break;
405*16467b97STreehugger Robot		}
406*16467b97STreehugger Robot		case TokenTypeUP: {
407*16467b97STreehugger Robot            if (navigationNodeUp == nil) {
408*16467b97STreehugger Robot                navigationNodeUp = [[TreeNavigationNodeUp alloc] init];
409*16467b97STreehugger Robot            }
410*16467b97STreehugger Robot			[self addLookahead:navigationNodeUp];
411*16467b97STreehugger Robot			break;
412*16467b97STreehugger Robot		}
413*16467b97STreehugger Robot	}
414*16467b97STreehugger Robot}
415*16467b97STreehugger Robot
416*16467b97STreehugger Robot#pragma mark Accessors
417*16467b97STreehugger Robot- (CommonTree *) root
418*16467b97STreehugger Robot{
419*16467b97STreehugger Robot    return root;
420*16467b97STreehugger Robot}
421*16467b97STreehugger Robot
422*16467b97STreehugger Robot- (void) setRoot: (CommonTree *) aRoot
423*16467b97STreehugger Robot{
424*16467b97STreehugger Robot    if (root != aRoot) {
425*16467b97STreehugger Robot        [aRoot retain];
426*16467b97STreehugger Robot        [root release];
427*16467b97STreehugger Robot        root = aRoot;
428*16467b97STreehugger Robot    }
429*16467b97STreehugger Robot}
430*16467b97STreehugger Robot
431*16467b97STreehugger Robot@end
432*16467b97STreehugger Robot
433