1// [The "BSD licence"]
2// Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9//    notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11//    notice, this list of conditions and the following disclaimer in the
12//    documentation and/or other materials provided with the distribution.
13// 3. The name of the author may not be used to endorse or promote products
14//    derived from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27
28#import "ANTLRStringStream.h"
29
30extern NSInteger debug;
31
32@implementation ANTLRStringStream
33
34@synthesize data;
35@synthesize n;
36@synthesize index;
37@synthesize line;
38@synthesize charPositionInLine;
39@synthesize markDepth;
40@synthesize markers;
41@synthesize lastMarker;
42@synthesize name;
43@synthesize charState;
44
45+ newANTLRStringStream
46{
47    return [[ANTLRStringStream alloc] init];
48}
49
50+ newANTLRStringStream:(NSString *)aString;
51{
52    return [[ANTLRStringStream alloc] initWithString:aString];
53}
54
55
56+ newANTLRStringStream:(char *)myData Count:(NSInteger)numBytes;
57{
58    return [[ANTLRStringStream alloc] initWithData:myData Count:numBytes];
59}
60
61
62- (id) init
63{
64	if ((self = [super init]) != nil) {
65        n = 0;
66        index = 0;
67        line = 1;
68        charPositionInLine = 0;
69        markDepth = 0;
70		markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:10];
71        [markers retain];
72        [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based,
73        charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain];
74	}
75	return self;
76}
77
78- (id) initWithString:(NSString *) theString
79{
80	if ((self = [super init]) != nil) {
81		//[self setData:[NSString stringWithString:theString]];
82        data = [theString retain];
83        n = [data length];
84        index = 0;
85        line = 1;
86        charPositionInLine = 0;
87        markDepth = 0;
88		markers = [[ANTLRPtrBuffer newANTLRPtrBufferWithLen:10] retain];
89        [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based,
90        charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain];
91	}
92	return self;
93}
94
95- (id) initWithStringNoCopy:(NSString *) theString
96{
97	if ((self = [super init]) != nil) {
98		//[self setData:theString];
99        data = [theString retain];
100        n = [data length];
101        index = 0;
102        line = 1;
103        charPositionInLine = 0;
104        markDepth = 0;
105		markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100];
106        [markers retain];
107        [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based,
108        charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain];
109	}
110	return self;
111}
112
113- (id) initWithData:(char *)myData Count:(NSInteger)numBytes
114{
115    if ((self = [super init]) != nil) {
116        data = [NSString stringWithCString:myData encoding:NSASCIIStringEncoding];
117        n = numBytes;
118        index = 0;
119        line = 1;
120        charPositionInLine = 0;
121        markDepth = 0;
122		markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100];
123        [markers retain];
124        [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based,
125        charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain];
126    }
127    return( self );
128}
129
130- (void) dealloc
131{
132#ifdef DEBUG_DEALLOC
133    NSLog( @"called dealloc in ANTLRStringStream" );
134#endif
135    if ( markers && [markers count] ) {
136        [markers removeAllObjects];
137        [markers release];
138        markers = nil;
139    }
140    if ( data ) {
141        [data release];
142        data = nil;
143    }
144	[super dealloc];
145}
146
147- (id) copyWithZone:(NSZone *)aZone
148{
149    ANTLRStringStream *copy;
150	
151    copy = [[[self class] allocWithZone:aZone] init];
152    //    copy = [super copyWithZone:aZone]; // allocation occurs here
153    if ( data != nil )
154        copy.data = [self.data copyWithZone:aZone];
155    copy.n = n;
156    copy.index = index;
157    copy.line = line;
158    copy.charPositionInLine = charPositionInLine;
159    copy.markDepth = markDepth;
160    if ( markers != nil )
161        copy.markers = [markers copyWithZone:nil];
162    copy.lastMarker = lastMarker;
163    if ( name != nil )
164        copy.name = [self.name copyWithZone:aZone];
165    return copy;
166}
167
168// reset the streams charState
169// the streams content is not reset!
170- (void) reset
171{
172	index = 0;
173	line = 1;
174	charPositionInLine = 0;
175	markDepth = 0;
176    if ( markers && [markers count] )
177        [markers removeAllObjects];
178    [markers addObject:[NSNull null]];  // ANTLR generates code that assumes markers to be 1-based,
179                                        // thus the initial null in the array!
180}
181
182// read one character off the stream, tracking line numbers and character positions
183// automatically.
184// Override this in subclasses if you want to avoid the overhead of automatic line/pos
185// handling. Do not call super in that case.
186- (void) consume 
187{
188	if ( index < n ) {
189		charPositionInLine++;
190		if ( [data characterAtIndex:index] == '\n' ) {
191			line++;
192			charPositionInLine=0;
193		}
194		index++;
195	}
196}
197
198// implement the lookahead method used in lexers
199- (NSInteger) LA:(NSInteger) i 
200{
201    NSInteger c;
202    if ( i == 0 )
203        return 0; // undefined
204    if ( i < 0 ) {
205        i++;
206        if ( index+i-1 < 0 ) {
207		    return ANTLRCharStreamEOF;
208		}
209	}
210    if ( (index+i-1) >= n ) {
211		return ANTLRCharStreamEOF;
212	}
213    c = [data characterAtIndex:index+i-1];
214	return (NSInteger)c;
215}
216
217- (NSInteger) LT:(NSInteger)i
218{
219    return [self LA:i];
220}
221
222- (NSInteger) size 
223{
224	return n;
225}
226
227// push the current charState of the stream onto a stack
228// returns the depth of the stack, to be used as a marker to rewind the stream.
229// Note: markers are 1-based!
230- (NSInteger) mark 
231{
232    if (debug > 1) NSLog(@"mark entry -- markers=%x, markDepth=%d\n", (int)markers, markDepth);
233    if ( markers == nil ) {
234        markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100];
235		[markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based,
236        markDepth = markers.ptr;
237    }
238    markDepth++;
239	ANTLRCharStreamState *State = nil;
240	if ( (markDepth) >= [markers count] ) {
241        if ( markDepth > 1 ) {
242            State = [ANTLRCharStreamState newANTLRCharStreamState];
243            [State retain];
244        }
245        if ( markDepth == 1 )
246            State = charState;
247		[markers insertObject:State atIndex:markDepth];
248        if (debug > 1) NSLog(@"mark save State %x at %d, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)State, markDepth, State.index, State.line, State.charPositionInLine);
249	}
250	else {
251        if (debug > 1) NSLog(@"mark retrieve markers=%x markDepth=%d\n", (NSUInteger)markers, markDepth);
252        State = [markers objectAtIndex:markDepth];
253        [State retain];
254        State = (ANTLRCharStreamState *)[markers objectAtIndex:markDepth];
255        if (debug > 1) NSLog(@"mark retrieve charState %x from %d, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)State, markDepth, State.index, State.line, State.charPositionInLine);
256	}
257    State.index = index;
258	State.line = line;
259	State.charPositionInLine = charPositionInLine;
260	lastMarker = markDepth;
261    if (debug > 1) NSLog(@"mark exit -- markers=%x, charState=%x, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)markers, (NSUInteger)State, State.index, State.line, State.charPositionInLine);
262	return markDepth;
263}
264
265- (void) rewind:(NSInteger) marker 
266{
267    ANTLRCharStreamState *State;
268    if (debug > 1) NSLog(@"rewind entry -- markers=%x marker=%d\n", (NSUInteger)markers, marker);
269    if ( marker == 1 )
270        State = charState;
271    else
272        State = (ANTLRCharStreamState *)[markers objectAtIndex:marker];
273    if (debug > 1) NSLog(@"rewind entry -- marker=%d charState=%x, index=%d, line=%d, charPositionInLine=%d\n", marker, (NSUInteger)charState, charState.index, charState.line, charState.charPositionInLine);
274	// restore stream charState
275	[self seek:State.index];
276	line = State.line;
277	charPositionInLine = charState.charPositionInLine;
278	[self release:marker];
279    if (debug > 1) NSLog(@"rewind exit -- marker=%d charState=%x, index=%d, line=%d, charPositionInLine=%d\n", marker, (NSUInteger)charState, charState.index, charState.line, charState.charPositionInLine);
280}
281
282- (void) rewind
283{
284	[self rewind:lastMarker];
285}
286
287// remove stream states on top of 'marker' from the marker stack
288// returns the new markDepth of the stack.
289// Note: unfortunate naming for Objective-C, but to keep close to the Java target this is named release:
290- (void) release:(NSInteger) marker 
291{
292	// unwind any other markers made after marker and release marker
293	markDepth = marker;
294	markDepth--;
295    if (debug > 1) NSLog(@"release:marker= %d, markDepth = %d\n", marker, markDepth);
296}
297
298// when seeking forward we must handle character position and line numbers.
299// seeking backward already has the correct line information on the markers stack, 
300// so we just take it from there.
301- (void) seek:(NSInteger) anIndex 
302{
303    if (debug > 1) NSLog(@"seek entry -- seekIndex=%d index=%d\n", anIndex, index);
304	if ( anIndex <= index ) {
305		index = anIndex; // just jump; don't update stream charState (line, ...)
306        if (debug > 1) NSLog(@"seek exit return -- index=%d index=%d\n", anIndex, index);
307		return;
308	}
309	// seek forward, consume until index hits anIndex
310	while ( index < anIndex ) {
311		[self consume];
312	}
313    if (debug > 1) NSLog(@"seek exit end -- index=%d index=%d\n", anIndex, index);
314}
315
316// get a substring from our raw data.
317- (NSString *) substring:(NSInteger)startIndex To:(NSInteger)stopIndex 
318{
319    NSRange theRange = NSMakeRange(startIndex, stopIndex-startIndex);
320	return [data substringWithRange:theRange];
321}
322
323// get a substring from our raw data.
324- (NSString *) substringWithRange:(NSRange) theRange 
325{
326	return [data substringWithRange:theRange];
327}
328
329
330- (ANTLRPtrBuffer *)getMarkers
331{
332    return markers;
333}
334
335- (void) setMarkers:(ANTLRPtrBuffer *)aMarkerList
336{
337    markers = aMarkerList;
338}
339
340- (NSString *)getSourceName
341{
342    return name;
343}
344
345- (void) setSourceName:(NSString *)aName
346{
347    if ( name != aName ) {
348        if ( name ) [name release];
349        if ( aName ) [aName retain];
350        name = aName;
351    }
352}
353
354
355- (ANTLRCharStreamState *)getCharState
356{
357    return charState;
358}
359
360- (void) setCharState:(ANTLRCharStreamState *)aCharState
361{
362    charState = aCharState;
363}
364
365- (NSString *)toString
366{
367    return [NSString stringWithString:data];
368}
369
370//---------------------------------------------------------- 
371//  data 
372//---------------------------------------------------------- 
373- (NSString *) getData
374{
375    return data; 
376}
377
378- (void) setData: (NSString *) aData
379{
380    if (data != aData) {
381        if ( data ) [data release];
382        data = [NSString stringWithString:aData];
383        [data retain];
384    }
385}
386
387@end
388