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