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