1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2005-2008 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 namespace Antlr.Runtime {
34     using Antlr.Runtime.Tree;
35 
36     using ArgumentNullException = System.ArgumentNullException;
37     using Exception = System.Exception;
38     using NonSerialized = System.NonSerializedAttribute;
39     using SerializationInfo = System.Runtime.Serialization.SerializationInfo;
40     using StreamingContext = System.Runtime.Serialization.StreamingContext;
41 
42     /** <summary>The root of the ANTLR exception hierarchy.</summary>
43      *
44      *  <remarks>
45      *  To avoid English-only error messages and to generally make things
46      *  as flexible as possible, these exceptions are not created with strings,
47      *  but rather the information necessary to generate an error.  Then
48      *  the various reporting methods in Parser and Lexer can be overridden
49      *  to generate a localized error message.  For example, MismatchedToken
50      *  exceptions are built with the expected token type.
51      *  So, don't expect getMessage() to return anything.
52      *
53      *  Note that as of Java 1.4, you can access the stack trace, which means
54      *  that you can compute the complete trace of rules from the start symbol.
55      *  This gives you considerable context information with which to generate
56      *  useful error messages.
57      *
58      *  ANTLR generates code that throws exceptions upon recognition error and
59      *  also generates code to catch these exceptions in each rule.  If you
60      *  want to quit upon first error, you can turn off the automatic error
61      *  handling mechanism using rulecatch action, but you still need to
62      *  override methods mismatch and recoverFromMismatchSet.
63      *
64      *  In general, the recognition exceptions can track where in a grammar a
65      *  problem occurred and/or what was the expected input.  While the parser
66      *  knows its state (such as current input symbol and line info) that
67      *  state can change before the exception is reported so current token index
68      *  is computed and stored at exception time.  From this info, you can
69      *  perhaps print an entire line of input not just a single token, for example.
70      *  Better to just say the recognizer had a problem and then let the parser
71      *  figure out a fancy report.
72      *  </remarks>
73      */
74     [System.Serializable]
75     public class RecognitionException : Exception {
76         /** <summary>What input stream did the error occur in?</summary> */
77         private IIntStream _input;
78 
79         /** <summary>What is index of token/char were we looking at when the error occurred?</summary> */
80         private int _index;
81 
82         /** <summary>
83          *  The current Token when an error occurred.  Since not all streams
84          *  can retrieve the ith Token, we have to track the Token object.
85          *  For parsers.  Even when it's a tree parser, token might be set.
86          *  </summary>
87          */
88         private IToken _token;
89 
90         /** <summary>
91          *  If this is a tree parser exception, node is set to the node with
92          *  the problem.
93          *  </summary>
94          */
95         private object _node;
96 
97         /** <summary>The current char when an error occurred. For lexers.</summary> */
98         private int _c;
99 
100         /** <summary>
101          *  Track the line (1-based) at which the error occurred in case this is
102          *  generated from a lexer.  We need to track this since the
103          *  unexpected char doesn't carry the line info.
104          *  </summary>
105          */
106         private int _line;
107 
108         /// <summary>
109         /// The 0-based index into the line where the error occurred.
110         /// </summary>
111         private int _charPositionInLine;
112 
113         /** <summary>
114          *  If you are parsing a tree node stream, you will encounter som
115          *  imaginary nodes w/o line/col info.  We now search backwards looking
116          *  for most recent token with line/col info, but notify getErrorHeader()
117          *  that info is approximate.
118          *  </summary>
119          */
120         private bool _approximateLineInfo;
121 
122         /** <summary>Used for remote debugger deserialization</summary> */
RecognitionException()123         public RecognitionException()
124             : this("A recognition error occurred.", null, null) {
125         }
126 
RecognitionException(IIntStream input)127         public RecognitionException(IIntStream input)
128             : this("A recognition error occurred.", input, null) {
129         }
130 
RecognitionException(string message)131         public RecognitionException(string message)
132             : this(message, null, null) {
133         }
134 
RecognitionException(string message, IIntStream input)135         public RecognitionException(string message, IIntStream input)
136             : this(message, input, null) {
137         }
138 
RecognitionException(string message, Exception innerException)139         public RecognitionException(string message, Exception innerException)
140             : this(message, null, innerException) {
141         }
142 
RecognitionException(string message, IIntStream input, Exception innerException)143         public RecognitionException(string message, IIntStream input, Exception innerException)
144             : base(message, innerException) {
145             this._input = input;
146             if (input != null) {
147                 this._index = input.Index;
148                 if (input is ITokenStream) {
149                     this._token = ((ITokenStream)input).LT(1);
150                     this._line = _token.Line;
151                     this._charPositionInLine = _token.CharPositionInLine;
152                 }
153                 if (input is ITreeNodeStream) {
154                     ExtractInformationFromTreeNodeStream(input);
155                 } else if (input is ICharStream) {
156                     this._c = input.LA(1);
157                     this._line = ((ICharStream)input).Line;
158                     this._charPositionInLine = ((ICharStream)input).CharPositionInLine;
159                 } else {
160                     this._c = input.LA(1);
161                 }
162             }
163         }
164 
RecognitionException(SerializationInfo info, StreamingContext context)165         protected RecognitionException(SerializationInfo info, StreamingContext context)
166             : base(info, context) {
167             if (info == null)
168                 throw new ArgumentNullException("info");
169 
170             _index = info.GetInt32("Index");
171             _c = info.GetInt32("C");
172             _line = info.GetInt32("Line");
173             _charPositionInLine = info.GetInt32("CharPositionInLine");
174             _approximateLineInfo = info.GetBoolean("ApproximateLineInfo");
175         }
176 
177         /** <summary>Return the token type or char of the unexpected input element</summary> */
178         public virtual int UnexpectedType {
179             get {
180                 if (_input is ITokenStream) {
181                     return _token.Type;
182                 }
183 
184                 ITreeNodeStream treeNodeStream = _input as ITreeNodeStream;
185                 if (treeNodeStream != null) {
186                     ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor;
187                     return adaptor.GetType(_node);
188                 }
189 
190                 return _c;
191             }
192         }
193 
194         public bool ApproximateLineInfo {
195             get {
196                 return _approximateLineInfo;
197             }
198             protected set {
199                 _approximateLineInfo = value;
200             }
201         }
202 
203         public IIntStream Input {
204             get {
205                 return _input;
206             }
207             protected set {
208                 _input = value;
209             }
210         }
211 
212         public IToken Token {
213             get {
214                 return _token;
215             }
216             set {
217                 _token = value;
218             }
219         }
220 
221         public object Node {
222             get {
223                 return _node;
224             }
225             protected set {
226                 _node = value;
227             }
228         }
229 
230         public int Character {
231             get {
232                 return _c;
233             }
234             protected set {
235                 _c = value;
236             }
237         }
238 
239         public int Index {
240             get {
241                 return _index;
242             }
243             protected set {
244                 _index = value;
245             }
246         }
247 
248         public int Line {
249             get {
250                 return _line;
251             }
252             set {
253                 _line = value;
254             }
255         }
256 
257         public int CharPositionInLine {
258             get {
259                 return _charPositionInLine;
260             }
261             set {
262                 _charPositionInLine = value;
263             }
264         }
265 
GetObjectData(SerializationInfo info, StreamingContext context)266         public override void GetObjectData(SerializationInfo info, StreamingContext context) {
267             if (info == null)
268                 throw new ArgumentNullException("info");
269 
270             base.GetObjectData(info, context);
271             info.AddValue("Index", _index);
272             info.AddValue("C", _c);
273             info.AddValue("Line", _line);
274             info.AddValue("CharPositionInLine", _charPositionInLine);
275             info.AddValue("ApproximateLineInfo", _approximateLineInfo);
276         }
277 
ExtractInformationFromTreeNodeStream(IIntStream input)278         protected virtual void ExtractInformationFromTreeNodeStream(IIntStream input) {
279             ITokenStreamInformation streamInformation = input as ITokenStreamInformation;
280             if (streamInformation != null) {
281                 IToken lastToken = streamInformation.LastToken;
282                 IToken lastRealToken = streamInformation.LastRealToken;
283                 if (lastRealToken != null) {
284                     this._token = lastRealToken;
285                     this._line = lastRealToken.Line;
286                     this._charPositionInLine = lastRealToken.CharPositionInLine;
287                     this._approximateLineInfo = lastRealToken.Equals(lastToken);
288                 }
289             } else {
290                 ITreeNodeStream nodes = (ITreeNodeStream)input;
291                 this._node = nodes.LT(1);
292                 ITreeAdaptor adaptor = nodes.TreeAdaptor;
293                 IToken payload = adaptor.GetToken(_node);
294                 if (payload != null) {
295                     this._token = payload;
296                     if (payload.Line <= 0) {
297                         // imaginary node; no line/pos info; scan backwards
298                         int i = -1;
299                         object priorNode = nodes.LT(i);
300                         while (priorNode != null) {
301                             IToken priorPayload = adaptor.GetToken(priorNode);
302                             if (priorPayload != null && priorPayload.Line > 0) {
303                                 // we found the most recent real line / pos info
304                                 this._line = priorPayload.Line;
305                                 this._charPositionInLine = priorPayload.CharPositionInLine;
306                                 this._approximateLineInfo = true;
307                                 break;
308                             }
309                             --i;
310                             priorNode = nodes.LT(i);
311                         }
312                     } else { // node created from real token
313                         this._line = payload.Line;
314                         this._charPositionInLine = payload.CharPositionInLine;
315                     }
316                 } else if (this._node is Tree.ITree) {
317                     this._line = ((Tree.ITree)this._node).Line;
318                     this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine;
319                     if (this._node is CommonTree) {
320                         this._token = ((CommonTree)this._node).Token;
321                     }
322                 } else {
323                     int type = adaptor.GetType(this._node);
324                     string text = adaptor.GetText(this._node);
325                     this._token = new CommonToken(type, text);
326                 }
327             }
328         }
329     }
330 }
331