1 // 2 // ANTLRTokenRewriteStream.m 3 // ANTLR 4 // 5 // Created by Alan Condit on 6/19/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 "ANTLRTokenRewriteStream.h" 33 #import "ANTLRRuntimeException.h" 34 35 static NSString *DEFAULT_PROGRAM_NAME = @"default"; 36 static NSInteger PROGRAM_INIT_SIZE = 100; 37 static NSInteger MIN_TOKEN_INDEX = 0; 38 39 extern NSInteger debug; 40 41 // Define the rewrite operation hierarchy 42 43 @implementation ANTLRRewriteOperation 44 45 @synthesize instructionIndex; 46 @synthesize rwIndex; 47 @synthesize text; 48 49 + (ANTLRRewriteOperation *) newANTLRRewriteOperation:(NSInteger)anIndex Text:(NSString *)theText 50 { 51 return [[ANTLRRewriteOperation alloc] initWithIndex:anIndex Text:theText]; 52 } 53 54 - (id) initWithIndex:(NSInteger)anIndex Text:(NSString *)theText 55 { 56 if ((self = [super init]) != nil) { 57 rwIndex = anIndex; 58 text = theText; 59 } 60 return self; 61 } 62 63 /** Execute the rewrite operation by possibly adding to the buffer. 64 * Return the rwIndex of the next token to operate on. 65 */ 66 - (NSInteger) execute:(NSString *)buf 67 { 68 return rwIndex; 69 } 70 71 - (NSString *)toString 72 { 73 NSString *opName = [self className]; 74 int $index = [self indexOf:'$' inString:opName]; 75 opName = [opName substringWithRange:NSMakeRange($index+1, [opName length])]; 76 return [NSString stringWithFormat:@"<%@%d:\"%@\">", opName, rwIndex, opName]; 77 } 78 79 - (NSInteger) indexOf:(char)aChar inString:(NSString *)aString 80 { 81 char indexedChar; 82 83 for( int i = 0; i < [aString length]; i++ ) { 84 indexedChar = [aString characterAtIndex:i]; 85 if (indexedChar == aChar) { 86 return i; 87 } 88 } 89 return -1; 90 } 91 92 @end 93 94 @implementation ANTLRInsertBeforeOp 95 96 + (ANTLRInsertBeforeOp *) newANTLRInsertBeforeOp:(NSInteger) anIndex Text:(NSString *)theText 97 { 98 return [[ANTLRInsertBeforeOp alloc] initWithIndex:anIndex Text:theText]; 99 } 100 101 - (id) initWithIndex:(NSInteger)anIndex Text:(NSString *)theText 102 { 103 if ((self = [super initWithIndex:anIndex Text:theText]) != nil) { 104 rwIndex = anIndex; 105 text = theText; 106 } 107 return self; 108 } 109 110 111 - (NSInteger) execute:(NSMutableString *)buf 112 { 113 [buf appendString:text]; 114 if ( ((ANTLRCommonToken *)[tokens objectAtIndex:rwIndex]).type != ANTLRTokenTypeEOF ) { 115 [buf appendString:[[tokens objectAtIndex:rwIndex] text]]; 116 } 117 return rwIndex+1; 118 } 119 120 @end 121 122 /** I'm going to try replacing range from x..y with (y-x)+1 ANTLRReplaceOp 123 * instructions. 124 */ 125 @implementation ANTLRReplaceOp 126 127 @synthesize lastIndex; 128 129 + (ANTLRReplaceOp *) newANTLRReplaceOp:(NSInteger)from ToIndex:(NSInteger)to Text:(NSString*)theText 130 { 131 return [[ANTLRReplaceOp alloc] initWithIndex:from ToIndex:to Text:theText]; 132 } 133 134 - (id) initWithIndex:(NSInteger)from ToIndex:(NSInteger)to Text:(NSString *)theText 135 { 136 if ((self = [super initWithIndex:from Text:theText]) != nil) { 137 lastIndex = to; 138 } 139 return self; 140 } 141 142 143 - (NSInteger) execute:(NSMutableString *)buf 144 { 145 if ( text!=nil ) { 146 [buf appendString:text]; 147 } 148 return lastIndex+1; 149 } 150 151 - (NSString *)toString 152 { 153 return [NSString stringWithFormat:@"<ANTLRReplaceOp@ %d..%d :>%@\n", rwIndex, lastIndex, text]; 154 } 155 156 @end 157 158 @implementation ANTLRDeleteOp 159 160 + (ANTLRDeleteOp *) newANTLRDeleteOp:(NSInteger)from ToIndex:(NSInteger)to 161 { 162 // super(from To:to, null); 163 return [[ANTLRDeleteOp alloc] initWithIndex:from ToIndex:to]; 164 } 165 166 - (id) initWithIndex:(NSInteger)from ToIndex:(NSInteger)to 167 { 168 if ((self = [super initWithIndex:from ToIndex:to Text:nil]) != nil) { 169 lastIndex = to; 170 } 171 return self; 172 } 173 174 - (NSString *)toString 175 { 176 return [NSString stringWithFormat:@"<DeleteOp@ %d..%d\n", rwIndex, lastIndex]; 177 } 178 179 @end 180 181 182 @implementation ANTLRTokenRewriteStream 183 184 @synthesize programs; 185 @synthesize lastRewriteTokenIndexes; 186 187 + (ANTLRTokenRewriteStream *)newANTLRTokenRewriteStream 188 { 189 return [[ANTLRTokenRewriteStream alloc] init]; 190 } 191 192 + (ANTLRTokenRewriteStream *)newANTLRTokenRewriteStream:(id<ANTLRTokenSource>) aTokenSource 193 { 194 return [[ANTLRTokenRewriteStream alloc] initWithTokenSource:aTokenSource]; 195 } 196 197 + (ANTLRTokenRewriteStream *)newANTLRTokenRewriteStream:(id<ANTLRTokenSource>) aTokenSource Channel:(NSInteger)aChannel 198 { 199 return [[ANTLRTokenRewriteStream alloc] initWithTokenSource:aTokenSource Channel:aChannel]; 200 } 201 202 - (id) init 203 { 204 if ((self = [super init]) != nil) { 205 programs = [ANTLRHashMap newANTLRHashMap]; 206 [programs addObject:[ANTLRMapElement newANTLRMapElementWithName:DEFAULT_PROGRAM_NAME Node:[ANTLRHashMap newANTLRHashMapWithLen:PROGRAM_INIT_SIZE]]]; 207 lastRewriteTokenIndexes = [ANTLRHashMap newANTLRHashMap]; 208 } 209 return self; 210 } 211 212 - (id)initWithTokenSource:(id<ANTLRTokenSource>)aTokenSource 213 { 214 if ((self = [super init]) != nil) { 215 programs = [ANTLRHashMap newANTLRHashMap]; 216 [programs addObject:[ANTLRMapElement newANTLRMapElementWithName:DEFAULT_PROGRAM_NAME Node:[ANTLRHashMap newANTLRHashMapWithLen:PROGRAM_INIT_SIZE]]]; 217 lastRewriteTokenIndexes = [ANTLRHashMap newANTLRHashMap]; 218 tokenSource = aTokenSource; 219 } 220 return self; 221 } 222 223 - (id)initWithTokenSource:(id<ANTLRTokenSource>)aTokenSource Channel:(NSInteger)aChannel 224 { 225 if ((self = [super init]) != nil) { 226 programs = [ANTLRHashMap newANTLRHashMap]; 227 [programs addObject:[ANTLRMapElement newANTLRMapElementWithName:DEFAULT_PROGRAM_NAME Node:[ANTLRHashMap newANTLRHashMapWithLen:PROGRAM_INIT_SIZE]]]; 228 lastRewriteTokenIndexes = [ANTLRHashMap newANTLRHashMap]; 229 tokenSource = aTokenSource; 230 channel = aChannel; 231 } 232 return self; 233 } 234 235 - (ANTLRHashMap *)getPrograms 236 { 237 return programs; 238 } 239 240 - (void)setPrograms:(ANTLRHashMap *)aProgList 241 { 242 programs = aProgList; 243 } 244 245 - (void) rollback:(NSInteger)instructionIndex 246 { 247 [self rollback:DEFAULT_PROGRAM_NAME Index:instructionIndex]; 248 } 249 250 /** Rollback the instruction stream for a program so that 251 * the indicated instruction (via instructionIndex) is no 252 * longer in the stream. UNTESTED! 253 */ 254 - (void) rollback:(NSString *)programName Index:(NSInteger)anInstructionIndex 255 { 256 id object; 257 ANTLRHashMap *is; 258 259 // AMutableArray *is = [programs get(programName)]; 260 is = [self getPrograms]; 261 object = [is getName:programName]; 262 if ( is != nil ) { 263 #pragma warning this has to be fixed 264 [programs insertObject:programName atIndex:anInstructionIndex]; 265 } 266 } 267 268 - (void) deleteProgram 269 { 270 [self deleteProgram:DEFAULT_PROGRAM_NAME]; 271 } 272 273 /** Reset the program so that no instructions exist */ 274 - (void) deleteProgram:(NSString *)programName 275 { 276 [self rollback:programName Index:MIN_TOKEN_INDEX]; 277 } 278 279 - (void) insertAfterToken:(id<ANTLRToken>)t Text:(NSString *)theText 280 { 281 [self insertAfterProgNam:DEFAULT_PROGRAM_NAME Index:[t getTokenIndex] Text:theText]; 282 } 283 284 - (void) insertAfterIndex:(NSInteger)anIndex Text:(NSString *)theText 285 { 286 [self insertAfterProgNam:DEFAULT_PROGRAM_NAME Index:(NSInteger)anIndex Text:(NSString *)theText]; 287 } 288 289 - (void) insertAfterProgNam:(NSString *)programName Index:(NSInteger)anIndex Text:(NSString *)theText 290 { 291 // to insert after, just insert before next rwIndex (even if past end) 292 [self insertBeforeProgName:programName Index:anIndex+1 Text:theText]; 293 //addToSortedRewriteList(programName, new InsertAfterOp(rwIndex,text)); 294 } 295 296 297 298 299 300 301 302 303 304 - (void) insertBeforeToken:(id<ANTLRToken>)t Text:(NSString *)theText 305 { 306 [self insertBeforeProgName:DEFAULT_PROGRAM_NAME Index:[t getTokenIndex] Text:theText]; 307 } 308 309 - (void) insertBeforeIndex:(NSInteger)anIndex Text:(NSString *)theText 310 { 311 [self insertBeforeProgName:DEFAULT_PROGRAM_NAME Index:anIndex Text:theText]; 312 } 313 314 - (void) insertBeforeProgName:(NSString *)programName Index:(NSInteger)rwIndex Text:(NSString *)theText 315 { 316 //addToSortedRewriteList(programName, new ANTLRInsertBeforeOp(rwIndex,text)); 317 ANTLRRewriteOperation *op = [ANTLRInsertBeforeOp newANTLRInsertBeforeOp:rwIndex Text:theText]; 318 ANTLRHashMap *rewrites = [self getProgram:programName]; 319 op.instructionIndex = [rewrites count]; 320 [rewrites addObject:op]; 321 } 322 323 - (void) replaceFromIndex:(NSInteger)anIndex Text:(NSString *)theText 324 { 325 [self replaceProgNam:DEFAULT_PROGRAM_NAME FromIndex:anIndex ToIndex:anIndex Text:theText]; 326 } 327 328 - (void) replaceFromIndex:(NSInteger)from ToIndex:(NSInteger)to Text:(NSString *)theText 329 { 330 [self replaceProgNam:DEFAULT_PROGRAM_NAME FromIndex:from ToIndex:to Text:theText]; 331 } 332 333 - (void) replaceFromToken:(id<ANTLRToken>)anIndexT Text:(NSString *)theText 334 { 335 [self replaceProgNam:DEFAULT_PROGRAM_NAME FromIndex:[anIndexT getTokenIndex] ToIndex:[anIndexT getTokenIndex] Text:theText]; 336 } 337 338 - (void) replaceFromToken:(id<ANTLRToken>)from ToToken:(id<ANTLRToken>)to Text:(NSString *)theText 339 { 340 [self replaceProgNam:DEFAULT_PROGRAM_NAME FromIndex:[from getTokenIndex] ToIndex:[to getTokenIndex] Text:theText]; 341 } 342 343 - (void) replaceProgNam:(NSString *)programName Token:(id<ANTLRToken>)from Token:(id<ANTLRToken>)to Text:(NSString *)theText 344 { 345 [self replaceProgNam:programName FromIndex:[from getTokenIndex] ToIndex:[to getTokenIndex] Text:theText]; 346 } 347 348 - (void) replaceProgNam:(NSString *)programName FromIndex:(NSInteger)from ToIndex:(NSInteger)to Text:(NSString *)theText 349 { 350 if ( from > to || from < 0 || to < 0 || to >= [tokens count] ) { 351 @throw [ANTLRIllegalArgumentException newException:[NSString stringWithFormat:@"replace: range invalid: %d..%d size=%d\n", from, to, [tokens count]]]; 352 } 353 ANTLRRewriteOperation *op = [ANTLRReplaceOp newANTLRReplaceOp:from ToIndex:to Text:theText]; 354 ANTLRHashMap *rewrites = (ANTLRHashMap *)[lastRewriteTokenIndexes getName:programName]; 355 op.instructionIndex = [rewrites count]; 356 [rewrites addObject:op]; 357 } 358 359 - (void) delete:(NSInteger)anIndex 360 { 361 [self delete:DEFAULT_PROGRAM_NAME FromIndex:(NSInteger)anIndex ToIndex:(NSInteger)anIndex]; 362 } 363 364 - (void) delete:(NSInteger)from ToIndex:(NSInteger)to 365 { 366 [self delete:DEFAULT_PROGRAM_NAME FromIndex:from ToIndex:to]; 367 } 368 369 - (void) deleteToken:(id<ANTLRToken>)anIndexT 370 { 371 [self delete:DEFAULT_PROGRAM_NAME FromIndex:[anIndexT getTokenIndex] ToIndex:[anIndexT getTokenIndex]]; 372 } 373 374 - (void) deleteFromToken:(id<ANTLRToken>)from ToToken:(id<ANTLRToken>)to 375 { 376 [self delete:DEFAULT_PROGRAM_NAME FromIndex:[from getTokenIndex] ToIndex:[to getTokenIndex]]; 377 } 378 379 - (void) delete:(NSString *)programName FromToken:(id<ANTLRToken>)from ToToken:(id<ANTLRToken>)to 380 { 381 [self replaceProgNam:programName FromIndex:[from getTokenIndex] ToIndex:[to getTokenIndex] Text:nil]; 382 } 383 384 - (void) delete:(NSString *)programName FromIndex:(NSInteger)from ToIndex:(NSInteger)to 385 { 386 [self replaceProgNam:programName FromIndex:from ToIndex:to Text:nil]; 387 } 388 389 - (NSInteger)getLastRewriteTokenIndex 390 { 391 return [self getLastRewriteTokenIndex:DEFAULT_PROGRAM_NAME]; 392 } 393 394 - (NSInteger)getLastRewriteTokenIndex:(NSString *)programName 395 { 396 #pragma warning fix this to look up the hashed name 397 NSInteger anInt = -1; 398 ANTLRMapElement *node = [lastRewriteTokenIndexes lookup:programName Scope:0]; 399 if ( node != nil ) { 400 anInt = [lastRewriteTokenIndexes hash:programName]; 401 } 402 return anInt; 403 } 404 405 - (void)setLastRewriteTokenIndex:(NSString *)programName Index:(NSInteger)anInt 406 { 407 [lastRewriteTokenIndexes insertObject:programName atIndex:anInt]; 408 } 409 410 -(ANTLRHashMap *) getProgram:(NSString *)name 411 { 412 ANTLRHashMap *is = (ANTLRHashMap *)[programs getName:name]; 413 if ( is == nil ) { 414 is = [self initializeProgram:name]; 415 } 416 return is; 417 } 418 419 -(ANTLRHashMap *) initializeProgram:(NSString *)name 420 { 421 ANTLRHashMap *is = [ANTLRHashMap newANTLRHashMapWithLen:PROGRAM_INIT_SIZE]; 422 [is putName:name Node:nil]; 423 return is; 424 } 425 426 - (NSString *)toOriginalString 427 { 428 [super fill]; 429 return [self toOriginalString:MIN_TOKEN_INDEX End:[tokens count]-1]; 430 } 431 432 - (NSString *)toOriginalString:(NSInteger)start End:(NSInteger)end 433 { 434 NSMutableString *buf = [NSMutableString stringWithCapacity:100]; 435 for (int i = start; i >= MIN_TOKEN_INDEX && i <= end && i< [tokens count]; i++) { 436 if ( [[lastRewriteTokenIndexes objectAtIndex:i] type] != ANTLRTokenTypeEOF ) 437 [buf appendString:[[tokens objectAtIndex:i] text]]; 438 } 439 return [NSString stringWithString:buf]; 440 } 441 442 - (NSString *)toString 443 { 444 [super fill]; 445 return [self toStringFromStart:MIN_TOKEN_INDEX ToEnd:[tokens count]-1]; 446 } 447 448 - (NSString *)toString:(NSString *)programName 449 { 450 [super fill]; 451 return [self toString:programName FromStart:MIN_TOKEN_INDEX ToEnd:[[programs objectAtIndex:MIN_TOKEN_INDEX] count]-1]; 452 } 453 454 - (NSString *)toStringFromStart:(NSInteger)start ToEnd:(NSInteger)end 455 { 456 return [self toString:DEFAULT_PROGRAM_NAME FromStart:start ToEnd:end]; 457 } 458 459 - (NSString *)toString:(NSString *)programName FromStart:(NSInteger)start ToEnd:(NSInteger)end 460 { 461 ANTLRHashMap *rewrites = (ANTLRHashMap *)[programs getName:programName]; 462 463 // ensure start/end are in range 464 if ( end > [tokens count]-1 ) end = [tokens count]-1; 465 if ( start < 0 ) 466 start = 0; 467 468 if ( rewrites == nil || [rewrites count] == 0 ) { 469 return [self toOriginalString:start End:end]; // no instructions to execute 470 } 471 NSMutableString *buf = [NSMutableString stringWithCapacity:100]; 472 473 // First, optimize instruction stream 474 ANTLRHashMap *indexToOp = [self reduceToSingleOperationPerIndex:rewrites]; 475 476 // Walk buffer, executing instructions and emitting tokens 477 int i = start; 478 while ( i <= end && i < [tokens count] ) { 479 ANTLRRewriteOperation *op = (ANTLRRewriteOperation *)[indexToOp objectAtIndex:i]; 480 [indexToOp setObject:nil atIndex:i]; // remove so any left have rwIndex size-1 481 id<ANTLRToken>t = (id<ANTLRToken>) [tokens objectAtIndex:i]; 482 if ( op == nil ) { 483 // no operation at that rwIndex, just dump token 484 if ( t.type != ANTLRTokenTypeEOF ) 485 [buf appendString:t.text]; 486 i++; // move to next token 487 } 488 else { 489 i = [op execute:buf]; // execute operation and skip 490 } 491 } 492 493 // include stuff after end if it's last rwIndex in buffer 494 // So, if they did an insertAfter(lastValidIndex, "foo"), include 495 // foo if end==lastValidIndex. 496 //if ( end == [tokens size]-1 ) { 497 if ( end == [tokens count]-1 ) { 498 // Scan any remaining operations after last token 499 // should be included (they will be inserts). 500 int i2 = 0; 501 while ( i2 < [indexToOp count] - 1 ) { 502 ANTLRRewriteOperation *op = [indexToOp objectAtIndex:i2]; 503 if ( op.rwIndex >= [tokens count]-1 ) { 504 [buf appendString:op.text]; 505 } 506 } 507 } 508 return [NSString stringWithString:buf]; 509 } 510 511 /** We need to combine operations and report invalid operations (like 512 * overlapping replaces that are not completed nested). Inserts to 513 * same rwIndex need to be combined etc... Here are the cases: 514 * 515 * I.i.u I.j.v leave alone, nonoverlapping 516 * I.i.u I.i.v combine: Iivu 517 * 518 * R.i-j.u R.x-y.v | i-j in x-y delete first R 519 * R.i-j.u R.i-j.v delete first R 520 * R.i-j.u R.x-y.v | x-y in i-j ERROR 521 * R.i-j.u R.x-y.v | boundaries overlap ERROR 522 * 523 * I.i.u R.x-y.v | i in x-y delete I 524 * I.i.u R.x-y.v | i not in x-y leave alone, nonoverlapping 525 * R.x-y.v I.i.u | i in x-y ERROR 526 * R.x-y.v I.x.u R.x-y.uv (combine, delete I) 527 * R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping 528 * 529 * I.i.u = insert u before op @ rwIndex i 530 * R.x-y.u = replace x-y indexed tokens with u 531 * 532 * First we need to examine replaces. For any replace op: 533 * 534 * 1. wipe out any insertions before op within that range. 535 * 2. Drop any replace op before that is contained completely within 536 * that range. 537 * 3. Throw exception upon boundary overlap with any previous replace. 538 * 539 * Then we can deal with inserts: 540 * 541 * 1. for any inserts to same rwIndex, combine even if not adjacent. 542 * 2. for any prior replace with same left boundary, combine this 543 * insert with replace and delete this replace. 544 * 3. throw exception if rwIndex in same range as previous replace 545 * 546 * Don't actually delete; make op null in list. Easier to walk list. 547 * Later we can throw as we add to rwIndex -> op map. 548 * 549 * Note that I.2 R.2-2 will wipe out I.2 even though, technically, the 550 * inserted stuff would be before the replace range. But, if you 551 * add tokens in front of a method body '{' and then delete the method 552 * body, I think the stuff before the '{' you added should disappear too. 553 * 554 * Return a map from token rwIndex to operation. 555 */ 556 - (ANTLRHashMap *)reduceToSingleOperationPerIndex:(ANTLRHashMap *)rewrites 557 { 558 //System.out.println("rewrites="+rewrites); 559 if (debug > 1) NSLog(@"rewrites=%@\n", [rewrites getName:DEFAULT_PROGRAM_NAME]); 560 // WALK REPLACES 561 for (int i = 0; i < [rewrites count]; i++) { 562 ANTLRRewriteOperation *op = (ANTLRRewriteOperation *)[rewrites objectAtIndex:i]; 563 if ( op==nil ) 564 continue; 565 if ( !([[op class] isKindOfClass:[ANTLRReplaceOp class]]) ) 566 continue; 567 ANTLRReplaceOp *rop = (ANTLRReplaceOp *)[rewrites objectAtIndex:i]; 568 // Wipe prior inserts within range 569 //List inserts = getKindOfOps(rewrites, ANTLRInsertBeforeOp.class, i); 570 ANTLRHashMap *inserts = [self getKindOfOps:rewrites KindOfClass:[ANTLRInsertBeforeOp class] Index:i]; 571 for (int j = 0; j < [inserts size]; j++) { 572 ANTLRInsertBeforeOp *iop = (ANTLRInsertBeforeOp *)[inserts objectAtIndex:j]; 573 if ( iop.rwIndex >= rop.rwIndex && iop.rwIndex <= rop.lastIndex ) { 574 // delete insert as it's a no-op. 575 [rewrites insertObject:nil atIndex:iop.instructionIndex]; 576 } 577 } 578 // Drop any prior replaces contained within 579 ANTLRHashMap *prevReplaces = [self getKindOfOps:rewrites KindOfClass:[ANTLRReplaceOp class] Index:i]; 580 for (int j = 0; j < [prevReplaces count]; j++) { 581 ANTLRReplaceOp *prevRop = (ANTLRReplaceOp *) [prevReplaces objectAtIndex:j]; 582 if ( prevRop.rwIndex>=rop.rwIndex && prevRop.lastIndex <= rop.lastIndex ) { 583 // delete replace as it's a no-op. 584 [rewrites setObject:nil atIndex:prevRop.instructionIndex]; 585 continue; 586 } 587 // throw exception unless disjoint or identical 588 BOOL disjoint = prevRop.lastIndex<rop.rwIndex || prevRop.rwIndex > rop.lastIndex; 589 BOOL same = prevRop.rwIndex==rop.rwIndex && prevRop.lastIndex==rop.lastIndex; 590 if ( !disjoint && !same ) { 591 @throw [ANTLRIllegalArgumentException newException: 592 [NSString stringWithFormat:@"replace op boundaries of %@, overlap with previous %@\n", rop, prevRop]]; 593 } 594 } 595 } 596 597 // WALK INSERTS 598 for (int i = 0; i < [rewrites count]; i++) { 599 ANTLRRewriteOperation *op = (ANTLRRewriteOperation *)[rewrites objectAtIndex:i]; 600 if ( op == nil ) 601 continue; 602 if ( !([[op class] isKindOfClass:[ANTLRInsertBeforeOp class]]) ) 603 continue; 604 ANTLRInsertBeforeOp *iop = (ANTLRInsertBeforeOp *)[rewrites objectAtIndex:i]; 605 // combine current insert with prior if any at same rwIndex 606 ANTLRHashMap *prevInserts = (ANTLRHashMap *)[self getKindOfOps:rewrites KindOfClass:[ANTLRInsertBeforeOp class] Index:i]; 607 for (int j = 0; j < [prevInserts count]; j++) { 608 ANTLRInsertBeforeOp *prevIop = (ANTLRInsertBeforeOp *) [prevInserts objectAtIndex:j]; 609 if ( prevIop.rwIndex == iop.rwIndex ) { // combine objects 610 // convert to strings...we're in process of toString'ing 611 // whole token buffer so no lazy eval issue with any templates 612 iop.text = [self catOpText:iop.text PrevText:prevIop.text]; 613 // delete redundant prior insert 614 [rewrites setObject:nil atIndex:prevIop.instructionIndex]; 615 } 616 } 617 // look for replaces where iop.rwIndex is in range; error 618 ANTLRHashMap *prevReplaces = (ANTLRHashMap *)[self getKindOfOps:rewrites KindOfClass:[ANTLRReplaceOp class] Index:i]; 619 for (int j = 0; j < [prevReplaces count]; j++) { 620 ANTLRReplaceOp *rop = (ANTLRReplaceOp *) [prevReplaces objectAtIndex:j]; 621 if ( iop.rwIndex == rop.rwIndex ) { 622 rop.text = [self catOpText:iop.text PrevText:rop.text]; 623 [rewrites setObject:nil atIndex:i]; // delete current insert 624 continue; 625 } 626 if ( iop.rwIndex >= rop.rwIndex && iop.rwIndex <= rop.lastIndex ) { 627 @throw [ANTLRIllegalArgumentException newException:[NSString stringWithFormat:@"insert op %d within boundaries of previous %d", iop, rop]]; 628 } 629 } 630 } 631 // System.out.println("rewrites after="+rewrites); 632 ANTLRHashMap *m = [ANTLRHashMap newANTLRHashMapWithLen:15]; 633 for (int i = 0; i < [rewrites count]; i++) { 634 ANTLRRewriteOperation *op = (ANTLRRewriteOperation *)[rewrites objectAtIndex:i]; 635 if ( op == nil ) 636 continue; // ignore deleted ops 637 if ( [m objectAtIndex:op.rwIndex] != nil ) { 638 @throw [ANTLRRuntimeException newException:@"should only be one op per rwIndex\n"]; 639 } 640 //[m put(new Integer(op.rwIndex), op); 641 [m setObject:op atIndex:op.rwIndex]; 642 } 643 //System.out.println("rwIndex to op: "+m); 644 if (debug > 1) NSLog(@"rwIndex to op %d\n", (NSInteger)m); 645 return m; 646 } 647 648 - (NSString *)catOpText:(id)a PrevText:(id)b 649 { 650 NSString *x = @""; 651 NSString *y = @""; 652 if ( a != nil ) 653 x = [a toString]; 654 if ( b != nil ) 655 y = [b toString]; 656 return [NSString stringWithFormat:@"%@%@",x, y]; 657 } 658 659 - (ANTLRHashMap *)getKindOfOps:(ANTLRHashMap *)rewrites KindOfClass:(Class)kind 660 { 661 return [self getKindOfOps:rewrites KindOfClass:kind Index:[rewrites count]]; 662 } 663 664 /** Get all operations before an rwIndex of a particular kind */ 665 - (ANTLRHashMap *)getKindOfOps:(ANTLRHashMap *)rewrites KindOfClass:(Class)kind Index:(NSInteger)before 666 { 667 ANTLRHashMap *ops = [ANTLRHashMap newANTLRHashMapWithLen:15]; 668 for (int i = 0; i < before && i < [rewrites count]; i++) { 669 ANTLRRewriteOperation *op = (ANTLRRewriteOperation *)[rewrites objectAtIndex:i]; 670 if ( op == nil ) 671 continue; // ignore deleted 672 if ( [op isKindOfClass:(Class)kind] ) 673 [ops addObject:op]; 674 } 675 return ops; 676 } 677 678 - (NSMutableString *)toDebugString 679 { 680 return [self toDebugStringFromStart:MIN_TOKEN_INDEX ToEnd:[tokens count]-1]; 681 } 682 683 - (NSMutableString *)toDebugStringFromStart:(NSInteger)start ToEnd:(NSInteger)end 684 { 685 NSMutableString *buf = [NSMutableString stringWithCapacity:100]; 686 for (int i = start; i >= MIN_TOKEN_INDEX && i <= end && i < [tokens count]; i++) { 687 [buf appendString:[[tokens objectAtIndex:i] text]]; 688 } 689 return [NSString stringWithString:buf]; 690 } 691 692 @end 693