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 "CommonTreeNodeStream.h"
28#import "TokenStream.h"
29#import "IntStream.h"
30#import "CharStream.h"
31#import "AMutableArray.h"
32#import "CommonTreeAdaptor.h"
33
34#ifndef DEBUG_DEALLOC
35#define DEBUG_DEALLOC
36#endif
37
38@implementation CommonTreeNodeStream
39
40@synthesize root;
41@synthesize tokens;
42@synthesize adaptor;
43@synthesize level;
44
45+ (CommonTreeNodeStream *) newCommonTreeNodeStream:(CommonTree *)theTree
46{
47    return [[CommonTreeNodeStream alloc] initWithTree:theTree];
48}
49
50+ (CommonTreeNodeStream *) newCommonTreeNodeStream:(id<TreeAdaptor>)anAdaptor Tree:(CommonTree *)theTree
51{
52    return [[CommonTreeNodeStream alloc] initWithTreeAdaptor:anAdaptor Tree:theTree];
53}
54
55- (id) initWithTree:(CommonTree *)theTree
56{
57    if ((self = [super init]) != nil ) {
58        adaptor = [[CommonTreeAdaptor newTreeAdaptor] retain];
59        root = [theTree retain];
60        navigationNodeEOF = [[adaptor createTree:TokenTypeEOF Text:@"EOF"] retain]; // set EOF
61        it = [[TreeIterator newANTRLTreeIteratorWithAdaptor:adaptor andTree:root] retain];
62        calls = [[IntArray newArrayWithLen:INITIAL_CALL_STACK_SIZE] retain];
63        /** Tree (nil A B C) trees like flat A B C streams */
64        hasNilRoot = NO;
65        level = 0;
66    }
67    return self;
68}
69
70- (id) initWithTreeAdaptor:(id<TreeAdaptor>)anAdaptor Tree:(CommonTree *)theTree
71{
72    if ((self = [super init]) != nil ) {
73        adaptor = [anAdaptor retain];
74        root = [theTree retain];
75        navigationNodeEOF = [[adaptor createTree:TokenTypeEOF Text:@"EOF"] retain]; // set EOF
76        //    it = [root objectEnumerator];
77        it = [[TreeIterator newANTRLTreeIteratorWithAdaptor:adaptor andTree:root] retain];
78        calls = [[IntArray newArrayWithLen:INITIAL_CALL_STACK_SIZE] retain];
79        /** Tree (nil A B C) trees like flat A B C streams */
80        hasNilRoot = NO;
81        level = 0;
82    }
83    //    eof = [self isEOF]; // make sure tree iterator returns the EOF we want
84    return self;
85}
86
87- (void)dealloc
88{
89#ifdef DEBUG_DEALLOC
90    NSLog( @"called dealloc in CommonTreeNodeStream" );
91#endif
92    if ( root ) [root release];
93    if ( tokens ) [tokens release];
94    if ( adaptor ) [adaptor release];
95    if ( it ) [it release];
96    if ( calls ) [calls release];
97    [super dealloc];
98}
99
100- (void) reset
101{
102    [super reset];
103    [it reset];
104    hasNilRoot = false;
105    level = 0;
106    if ( calls != nil )
107        [calls reset];  // [calls clear]; // in Java
108}
109
110/** Pull elements from tree iterator.  Track tree level 0..max_level.
111 *  If nil rooted tree, don't give initial nil and DOWN nor final UP.
112 */
113- (id) nextElement
114{
115    id t = [it nextObject];
116    //System.out.println("pulled "+adaptor.getType(t));
117    if ( t == [it up] ) {
118        level--;
119        if ( level==0 && hasNilRoot ) return [it nextObject]; // don't give last UP; get EOF
120    }
121    else if ( t == [it down] )
122        level++;
123    if ( level == 0 && [adaptor isNil:t] ) { // if nil root, scarf nil, DOWN
124        hasNilRoot = true;
125        t = [it nextObject]; // t is now DOWN, so get first real node next
126        level++;
127        t = [it nextObject];
128    }
129    return t;
130}
131
132- (BOOL) isEOF:(id<BaseTree>) aTree
133{
134    return [adaptor getType:(CommonTree *)aTree] == TokenTypeEOF;
135}
136
137- (void) setUniqueNavigationNodes:(BOOL) uniqueNavigationNodes
138{
139}
140
141- (id) getTreeSource
142{
143    return root;
144}
145
146- (NSString *) getSourceName
147{
148    return [[self getTokenStream] getSourceName];
149}
150
151- (id<TokenStream>) getTokenStream
152{
153    return tokens;
154}
155
156- (void) setTokenStream:(id<TokenStream>)theTokens
157{
158    if ( tokens != theTokens ) {
159        if ( tokens ) [tokens release];
160        [theTokens retain];
161    }
162    tokens = theTokens;
163}
164
165- (CommonTreeAdaptor *) getTreeAdaptor
166{
167    return adaptor;
168}
169
170- (void) setTreeAdaptor:(CommonTreeAdaptor *) anAdaptor
171{
172    if ( adaptor != anAdaptor ) {
173        if ( adaptor ) [adaptor release];
174        [anAdaptor retain];
175    }
176    adaptor = anAdaptor;
177}
178
179- (CommonTree *)getNode:(NSInteger) i
180{
181    @throw [RuntimeException newException:@"Absolute node indexes are meaningless in an unbuffered stream"];
182    return nil;
183}
184
185- (NSInteger) LA:(NSInteger) i
186{
187    return [adaptor getType:[self LT:i]];
188}
189
190/** Make stream jump to a new location, saving old location.
191 *  Switch back with pop().
192 */
193- (void) push:(NSInteger) anIndex
194{
195    if ( calls == nil ) {
196        calls = [[IntArray newArrayWithLen:INITIAL_CALL_STACK_SIZE] retain];
197    }
198    [calls push:p]; // save current anIndex
199    [self seek:anIndex];
200}
201
202/** Seek back to previous anIndex saved during last push() call.
203 *  Return top of stack (return anIndex).
204 */
205- (NSInteger) pop
206{
207    int ret = [calls pop];
208    [self seek:ret];
209    return ret;
210}
211
212// TREE REWRITE INTERFACE
213
214- (void) replaceChildren:(id) parent From:(NSInteger)startChildIndex To:(NSInteger)stopChildIndex With:(id) aTree
215{
216    if ( parent != nil ) {
217        [adaptor replaceChildren:parent From:startChildIndex To:stopChildIndex With:aTree];
218    }
219}
220
221- (NSString *) toStringFromNode:(id<BaseTree>)startNode ToNode:(id<BaseTree>)stopNode
222{
223    // we'll have to walk from start to stop in tree; we're not keeping
224    // a complete node stream buffer
225    return @"n/a";
226}
227
228/** For debugging; destructive: moves tree iterator to end. */
229- (NSString *) toTokenTypeString
230{
231    [self reset];
232    NSMutableString *buf = [NSMutableString stringWithCapacity:5];
233    id obj = [self LT:1];
234    NSInteger type = [adaptor getType:obj];
235    while ( type != TokenTypeEOF ) {
236        [buf appendString:@" "];
237        [buf appendString:[NSString stringWithFormat:@"%d", type]];
238        [self consume];
239        obj = [self LT:1];
240        type = [adaptor getType:obj];
241    }
242    return buf;
243}
244
245@synthesize it;
246@synthesize calls;
247@synthesize hasNilRoot;
248@end
249
250