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 "Foundation/NSObjCRuntime.h"
28#import "RecognitionException.h"
29#import "TokenStream.h"
30#import "TreeNodeStream.h"
31#import "BufferedTokenStream.h"
32
33@implementation RecognitionException
34
35@synthesize input;
36@synthesize index;
37@synthesize token;
38@synthesize node;
39@synthesize c;
40@synthesize line;
41@synthesize charPositionInLine;
42@synthesize approximateLineInfo;
43
44+ (id) newException
45{
46	return [[RecognitionException alloc] init];
47}
48
49+ (id) newException:(id<IntStream>) anInputStream
50{
51	return [[RecognitionException alloc] initWithStream:anInputStream];
52}
53
54+ (id) newException:(id<IntStream>) anInputStream reason:(NSString *)aReason
55{
56	return [[RecognitionException alloc] initWithStream:anInputStream reason:aReason];
57}
58
59- (id) init
60{
61	self = [super initWithName:@"Recognition Exception" reason:@"Recognition Exception" userInfo:nil];
62	if ( self != nil ) {
63	}
64	return self;
65}
66
67- (id) initWithStream:(id<IntStream>)anInputStream reason:(NSString *)aReason
68{
69	self = [super initWithName:NSStringFromClass([self class]) reason:aReason userInfo:nil];
70	if ( self != nil ) {
71		[self setStream:anInputStream];
72		index = input.index;
73
74		Class inputClass = [input class];
75		if ([inputClass conformsToProtocol:@protocol(TokenStream)]) {
76			[self setToken:[(id<TokenStream>)input LT:1]];
77			line = token.line;
78			charPositionInLine = token.charPositionInLine;
79		} else if ([inputClass conformsToProtocol:@protocol(CharStream)]) {
80			c = (unichar)[input LA:1];
81			line = ((id<CharStream>)input).getLine;
82			charPositionInLine = ((id<CharStream>)input).getCharPositionInLine;
83		} else if ([inputClass conformsToProtocol:@protocol(TreeNodeStream)]) {
84			[self setNode:[(id<TreeNodeStream>)input LT:1]];
85			line = [node line];
86			charPositionInLine = [node charPositionInLine];
87		} else {
88			c = (unichar)[input LA:1];
89		}
90	}
91	return self;
92}
93
94- (id) initWithStream:(id<IntStream>)anInputStream
95{
96	self = [super initWithName:NSStringFromClass([self class]) reason:@"Runtime Exception" userInfo:nil];
97	if ( self != nil ) {
98        self.input = anInputStream;
99        self.index = input.index;
100        if ( [anInputStream isKindOfClass:[BufferedTokenStream class]] ) {
101            self.token = [(id<TokenStream>)anInputStream LT:1];
102            self.line = [token line];
103            self.charPositionInLine = [token charPositionInLine];
104           if ( [input conformsToProtocol:objc_getProtocol("TreeNodeStream")] ) {
105               [self extractInformationFromTreeNodeStream:anInputStream];
106           }
107           else if ( [[anInputStream class] instancesRespondToSelector:@selector(LA1:)] ) {
108               c = [anInputStream LA:1];
109               if ( [[anInputStream class] instancesRespondToSelector:@selector(getLine)] )
110                   line = [anInputStream getLine];
111               if ( [[anInputStream class] instancesRespondToSelector:@selector(getCharPositionInLine)] )
112                   charPositionInLine = [anInputStream getCharPositionInLine];
113           }
114           else {
115               c = [anInputStream LA:1];
116           }
117        }
118	}
119	return self;
120}
121
122- (id) initWithName:(NSString *)aName reason:(NSString *)aReason userInfo:(NSDictionary *)aUserInfo
123{
124	self = [super initWithName:aName reason:aReason userInfo:aUserInfo];
125	if ( self != nil ) {
126    }
127    return self;
128}
129
130- (void) dealloc
131{
132#ifdef DEBUG_DEALLOC
133    NSLog( @"called dealloc in RecognitionException" );
134#endif
135	if ( input ) [input release];
136	if ( token ) [token release];
137	if ( node ) [node release];
138	[super dealloc];
139}
140
141- (void) extractInformationFromTreeNodeStream:(id<TreeNodeStream>)anInput
142{
143    id<TreeNodeStream> nodes = anInput;
144    node = [nodes LT:1];
145    id<TreeAdaptor> adaptor = [nodes getTreeAdaptor];
146    id<Token> payload = [adaptor getToken:node];
147    if ( payload != nil ) {
148        token = payload;
149        if ( payload.line <= 0 ) {
150            // imaginary node; no line/pos info; scan backwards
151            int i = -1;
152            id priorNode = [nodes LT:i];
153            while ( priorNode != nil ) {
154                id<Token> priorPayload = [adaptor getToken:priorNode];
155                if ( priorPayload!=nil && priorPayload.line > 0 ) {
156                    // we found the most recent real line / pos info
157                    line = priorPayload.line;
158                    charPositionInLine = priorPayload.charPositionInLine;
159                    approximateLineInfo = YES;
160                    break;
161                }
162                --i;
163                priorNode = [nodes LT:i];
164            }
165        }
166        else { // node created from real token
167            line = payload.line;
168            charPositionInLine = payload.charPositionInLine;
169        }
170    }
171    else if ( [self.node isKindOfClass:[CommonTree class]] ) {
172        line = ((id<Tree>)node).line;
173        charPositionInLine = ((id<Tree>)node).charPositionInLine;
174        if ( [node isMemberOfClass:[CommonTree class]]) {
175            token = ((CommonTree *)node).token;
176        }
177    }
178    else {
179        NSInteger type = [adaptor getType:node];
180        NSString *text = [adaptor getText:node];
181        self.token = [CommonToken newToken:type Text:text];
182    }
183}
184
185- (NSInteger) unexpectedType
186{
187	if (token) {
188		return token.type;
189    } else if (node) {
190        return [node type];
191	} else {
192		return c;
193	}
194}
195
196- (id<Token>)getUnexpectedToken
197{
198    return token;
199}
200
201- (NSString *) description
202{
203	//NSMutableString *desc = [[NSMutableString alloc] initWithString:NSStringFromClass([self class])];
204	NSMutableString *desc = [NSMutableString stringWithString:[self className]];
205	if (token) {
206		[desc appendFormat:@" token:%@", token];
207	} else if (node) {
208		[desc appendFormat:@" node:%@", node];
209	} else {
210		[desc appendFormat:@" char:%c", c];
211	}
212	[desc appendFormat:@" line:%d position:%d", line, charPositionInLine];
213	return desc;
214}
215
216//----------------------------------------------------------
217//  input
218//----------------------------------------------------------
219- (id<IntStream>) getStream
220{
221    return input;
222}
223
224- (void) setStream: (id<IntStream>) aStream
225{
226    if ( input != aStream ) {
227        if ( input ) [input release];
228        if ( aStream ) [aStream retain];
229        input = aStream;
230    }
231}
232
233//----------------------------------------------------------
234//  token
235//----------------------------------------------------------
236- (id<Token>) getToken
237{
238    return token;
239}
240
241- (void) setToken: (id<Token>) aToken
242{
243    if (token != aToken) {
244        if ( token ) [token release];
245        if ( aToken ) [aToken retain];
246        token = aToken;
247    }
248}
249
250//----------------------------------------------------------
251//  node
252//----------------------------------------------------------
253- (id<BaseTree>) getNode
254{
255    return node;
256}
257
258- (void) setNode: (id<BaseTree>) aNode
259{
260    if (node != aNode) {
261        if ( node ) [node release];
262        if ( aNode ) [aNode retain];
263        node = aNode;
264    }
265}
266
267- (NSString *)getMessage
268{
269    return @"Fix getMessage in RecognitionException";
270}
271
272- (NSUInteger)charPositionInLine
273{
274    return charPositionInLine;
275}
276
277- (void)setCharPositionInLine:(NSUInteger)aPos
278{
279    charPositionInLine = aPos;
280}
281
282@end
283