xref: /aosp_15_r20/external/antlr/runtime/ObjC/Framework/TokenRewriteStream.m (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
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