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#import "ANTLRRewriteRuleElementStream.h"
28
29@implementation ANTLRRewriteRuleElementStream
30
31@synthesize cursor;
32@synthesize dirty;
33@synthesize isSingleElement;
34@synthesize singleElement;
35@synthesize elements;
36@synthesize elementDescription;
37@synthesize treeAdaptor;
38
39+ (ANTLRRewriteRuleElementStream *) newANTLRRewriteRuleElementStream:(id<ANTLRTreeAdaptor>)aTreeAdaptor
40                                                         description:(NSString *)anElementDescription
41{
42    return [[ANTLRRewriteRuleElementStream alloc] initWithTreeAdaptor:aTreeAdaptor
43                                                          description:anElementDescription];
44}
45
46+ (ANTLRRewriteRuleElementStream *) newANTLRRewriteRuleElementStream:(id<ANTLRTreeAdaptor>)aTreeAdaptor
47                                                         description:(NSString *)anElementDescription
48                                                             element:(id)anElement
49{
50    return [[ANTLRRewriteRuleElementStream alloc] initWithTreeAdaptor:aTreeAdaptor
51                                                          description:anElementDescription
52                                                              element:anElement];
53}
54
55+ (ANTLRRewriteRuleElementStream *) newANTLRRewriteRuleElementStream:(id<ANTLRTreeAdaptor>)aTreeAdaptor
56                                                         description:(NSString *)anElementDescription
57                                                            elements:(NSArray *)theElements;
58{
59    return [[ANTLRRewriteRuleElementStream alloc] initWithTreeAdaptor:aTreeAdaptor
60                                                          description:anElementDescription
61                                                             elements:theElements];
62}
63
64- (id) initWithTreeAdaptor:(id<ANTLRTreeAdaptor>)aTreeAdaptor description:(NSString *)anElementDescription
65{
66    if ((self = [super init]) != nil) {
67        cursor = 0;
68        dirty = NO;
69        [self setDescription:anElementDescription];
70        [self setTreeAdaptor:aTreeAdaptor];
71        dirty = NO;
72        isSingleElement = YES;
73        singleElement = nil;
74        elements = nil;
75    }
76    return self;
77}
78
79- (id) initWithTreeAdaptor:(id<ANTLRTreeAdaptor>)aTreeAdaptor description:(NSString *)anElementDescription element:(id)anElement
80{
81    if ((self = [super init]) != nil) {
82        cursor = 0;
83        dirty = NO;
84        [self setDescription:anElementDescription];
85        [self setTreeAdaptor:aTreeAdaptor];
86        dirty = NO;
87        isSingleElement = YES;
88        singleElement = nil;
89        elements = nil;
90        [self addElement:anElement];
91    }
92    return self;
93}
94
95- (id) initWithTreeAdaptor:(id<ANTLRTreeAdaptor>)aTreeAdaptor description:(NSString *)anElementDescription elements:(NSArray *)theElements
96{
97    self = [super init];
98    if (self) {
99        cursor = 0;
100        dirty = NO;
101        [self setDescription:anElementDescription];
102        [self setTreeAdaptor:aTreeAdaptor];
103        dirty = NO;
104        singleElement = nil;
105        isSingleElement = NO;
106        elements = [[AMutableArray arrayWithArray:theElements] retain];
107    }
108    return self;
109}
110
111- (void) dealloc
112{
113#ifdef DEBUG_DEALLOC
114    NSLog( @"called dealloc in ANTLRRewriteRuleElementStream" );
115#endif
116    if ( singleElement && isSingleElement ) [singleElement release];
117    else if ( elements && !isSingleElement ) [elements release];
118    [self setDescription:nil];
119    [self setTreeAdaptor:nil];
120    [super dealloc];
121}
122
123- (void)reset
124{
125    cursor = 0;
126    dirty = YES;
127}
128
129- (id<ANTLRTreeAdaptor>) getTreeAdaptor
130{
131    return treeAdaptor;
132}
133
134- (void) setTreeAdaptor:(id<ANTLRTreeAdaptor>)aTreeAdaptor
135{
136    if (treeAdaptor != aTreeAdaptor) {
137        if ( treeAdaptor ) [treeAdaptor release];
138        treeAdaptor = aTreeAdaptor;
139        [treeAdaptor retain];
140    }
141}
142
143- (void) addElement: (id)anElement
144{
145    if (anElement == nil)
146        return;
147    if (elements != nil) {
148        [elements addObject:anElement];
149        return;
150        }
151    if (singleElement == nil) {
152        singleElement = anElement;
153        singleElement = [anElement retain];
154        return;
155    }
156    isSingleElement = NO;
157    elements = [[AMutableArray arrayWithCapacity:5] retain];
158    [elements addObject:singleElement];
159    singleElement = nil;  // balance previous retain in initializer/addElement
160    [elements addObject:anElement];
161}
162
163- (void) setElement: (id)anElement
164{
165    if (anElement == nil)
166        return;
167    if (elements != nil) {
168        [elements addObject:anElement];
169        return;
170        }
171    if (singleElement == nil) {
172        singleElement = anElement;
173        singleElement = [anElement retain];
174        return;
175    }
176    isSingleElement = NO;
177    elements = [[AMutableArray arrayWithCapacity:5] retain];
178    [elements addObject:singleElement];
179    singleElement = nil;  // balance previous retain in initializer/addElement
180    [elements addObject:anElement];
181}
182
183- (id<ANTLRBaseTree>) nextTree
184{
185    NSInteger n = [self size];
186    if ( dirty && (cursor >= 0 && n == 1)) {
187        // if out of elements and size is 1, dup
188        id element = [self _next];
189        return [self copyElement:element];
190    }
191    // test size above then fetch
192    id element = [self _next];
193    return element;
194}
195
196- (id) _next       // internal: TODO: redesign if necessary. maybe delegate
197{
198    NSInteger n = [self size];
199    if (n == 0) {
200        @throw [NSException exceptionWithName:@"RewriteEmptyStreamException" reason:nil userInfo:nil];// TODO: fill in real exception
201    }
202    if ( cursor >= n ) {
203        if ( n == 1 ) {
204            return [self toTree:singleElement]; // will be dup'ed in -next
205        }
206        @throw [NSException exceptionWithName:@"RewriteCardinalityException" reason:nil userInfo:nil];// TODO: fill in real exception
207    }
208    if (singleElement != nil) {
209        cursor++;
210        return [self toTree:singleElement];
211    }
212    id el = [elements objectAtIndex:cursor];
213    cursor++;
214    return [self toTree:el];
215}
216
217- (BOOL) hasNext
218{
219    return (singleElement != nil && cursor < 1) ||
220            (elements != nil && cursor < [elements count]);
221}
222
223- (NSInteger) size
224{
225    NSInteger n = 0;
226    if (singleElement != nil)
227        n = 1;
228    if (elements != nil)
229        return [elements count];
230    return n;
231}
232
233- (id) copyElement:(id)element
234{
235    [self doesNotRecognizeSelector:_cmd];   // subclass responsibility
236    return nil;
237}
238
239- (id<ANTLRBaseTree>) toTree:(id)element
240{
241    return element;
242}
243
244- (NSString *) getDescription
245{
246    return elementDescription;
247}
248
249- (void) setDescription:(NSString *) description
250{
251    if ( description != nil && description != elementDescription ) {
252        if (elementDescription != nil) [elementDescription release];
253        elementDescription = [NSString stringWithString:description];
254        [elementDescription retain];
255    }
256}
257
258@end
259