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 685public 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. 698public 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. 708public 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