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