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 {
35     using Antlr.Runtime.Tree;
36 
37     using ArgumentException = System.ArgumentException;
38     using ArgumentNullException = System.ArgumentNullException;
39     using Exception = System.Exception;
40     using SerializationInfo = System.Runtime.Serialization.SerializationInfo;
41     using StreamingContext = System.Runtime.Serialization.StreamingContext;
42 
43     /** <summary>The root of the ANTLR exception hierarchy.</summary>
44      *
45      *  <remarks>
46      *  To avoid English-only error messages and to generally make things
47      *  as flexible as possible, these exceptions are not created with strings,
48      *  but rather the information necessary to generate an error.  Then
49      *  the various reporting methods in Parser and Lexer can be overridden
50      *  to generate a localized error message.  For example, MismatchedToken
51      *  exceptions are built with the expected token type.
52      *  So, don't expect getMessage() to return anything.
53      *
54      *  Note that as of Java 1.4, you can access the stack trace, which means
55      *  that you can compute the complete trace of rules from the start symbol.
56      *  This gives you considerable context information with which to generate
57      *  useful error messages.
58      *
59      *  ANTLR generates code that throws exceptions upon recognition error and
60      *  also generates code to catch these exceptions in each rule.  If you
61      *  want to quit upon first error, you can turn off the automatic error
62      *  handling mechanism using rulecatch action, but you still need to
63      *  override methods mismatch and recoverFromMismatchSet.
64      *
65      *  In general, the recognition exceptions can track where in a grammar a
66      *  problem occurred and/or what was the expected input.  While the parser
67      *  knows its state (such as current input symbol and line info) that
68      *  state can change before the exception is reported so current token index
69      *  is computed and stored at exception time.  From this info, you can
70      *  perhaps print an entire line of input not just a single token, for example.
71      *  Better to just say the recognizer had a problem and then let the parser
72      *  figure out a fancy report.
73      *  </remarks>
74      */
75     [System.Serializable]
76     public class RecognitionException : Exception
77     {
78         /** <summary>What input stream did the error occur in?</summary> */
79         private IIntStream _input;
80 
81         /** <summary>What is index of token/char were we looking at when the error occurred?</summary> */
82         private int _index;
83 
84         /** <summary>
85          *  The current Token when an error occurred.  Since not all streams
86          *  can retrieve the ith Token, we have to track the Token object.
87          *  For parsers.  Even when it's a tree parser, token might be set.
88          *  </summary>
89          */
90         private IToken _token;
91 
92         /** <summary>
93          *  If this is a tree parser exception, node is set to the node with
94          *  the problem.
95          *  </summary>
96          */
97         private object _node;
98 
99         /** <summary>The current char when an error occurred. For lexers.</summary> */
100         private int _c;
101 
102         /** <summary>
103          *  Track the line (1-based) at which the error occurred in case this is
104          *  generated from a lexer.  We need to track this since the
105          *  unexpected char doesn't carry the line info.
106          *  </summary>
107          */
108         private int _line;
109 
110         /// <summary>
111         /// The 0-based index into the line where the error occurred.
112         /// </summary>
113         private int _charPositionInLine;
114 
115         /** <summary>
116          *  If you are parsing a tree node stream, you will encounter som
117          *  imaginary nodes w/o line/col info.  We now search backwards looking
118          *  for most recent token with line/col info, but notify getErrorHeader()
119          *  that info is approximate.
120          *  </summary>
121          */
122         private bool _approximateLineInfo;
123 
124         /** <summary>Used for remote debugger deserialization</summary> */
RecognitionException()125         public RecognitionException()
126             : this("A recognition error occurred.", null, null)
127         {
128         }
129 
RecognitionException( IIntStream input )130         public RecognitionException( IIntStream input )
131             : this("A recognition error occurred.", input, null)
132         {
133         }
134 
RecognitionException(string message)135         public RecognitionException(string message)
136             : this(message, null, null)
137         {
138         }
139 
RecognitionException(string message, IIntStream input)140         public RecognitionException(string message, IIntStream input)
141             : this(message, input, null)
142         {
143         }
144 
RecognitionException(string message, Exception innerException)145         public RecognitionException(string message, Exception innerException)
146             : this(message, null, innerException)
147         {
148         }
149 
RecognitionException(string message, IIntStream input, Exception innerException)150         public RecognitionException(string message, IIntStream input, Exception innerException)
151             : base(message, innerException)
152         {
153             this._input = input;
154             if (input != null)
155             {
156                 this._index = input.Index;
157                 if (input is ITokenStream)
158                 {
159                     this._token = ((ITokenStream)input).LT(1);
160                     this._line = _token.Line;
161                     this._charPositionInLine = _token.CharPositionInLine;
162                 }
163 
164                 ITreeNodeStream tns = input as ITreeNodeStream;
165                 if (tns != null)
166                 {
167                     ExtractInformationFromTreeNodeStream(tns);
168                 }
169                 else
170                 {
171                     ICharStream charStream = input as ICharStream;
172                     if (charStream != null)
173                     {
174                         this._c = input.LA(1);
175                         this._line = ((ICharStream)input).Line;
176                         this._charPositionInLine = ((ICharStream)input).CharPositionInLine;
177                     }
178                     else
179                     {
180                         this._c = input.LA(1);
181                     }
182                 }
183             }
184         }
185 
RecognitionException(SerializationInfo info, StreamingContext context)186         protected RecognitionException(SerializationInfo info, StreamingContext context)
187             : base(info, context)
188         {
189             if (info == null)
190                 throw new ArgumentNullException("info");
191 
192             _index = info.GetInt32("Index");
193             _c = info.GetInt32("C");
194             _line = info.GetInt32("Line");
195             _charPositionInLine = info.GetInt32("CharPositionInLine");
196             _approximateLineInfo = info.GetBoolean("ApproximateLineInfo");
197         }
198 
199         /** <summary>Return the token type or char of the unexpected input element</summary> */
200         public virtual int UnexpectedType
201         {
202             get
203             {
204                 if ( _input is ITokenStream )
205                 {
206                     return _token.Type;
207                 }
208 
209                 ITreeNodeStream treeNodeStream = _input as ITreeNodeStream;
210                 if ( treeNodeStream != null )
211                 {
212                     ITreeAdaptor adaptor = treeNodeStream.TreeAdaptor;
213                     return adaptor.GetType( _node );
214                 }
215 
216                 return _c;
217             }
218         }
219 
220         public bool ApproximateLineInfo
221         {
222             get
223             {
224                 return _approximateLineInfo;
225             }
226             protected set
227             {
228                 _approximateLineInfo = value;
229             }
230         }
231 
232         public IIntStream Input
233         {
234             get
235             {
236                 return _input;
237             }
238             protected set
239             {
240                 _input = value;
241             }
242         }
243 
244         public IToken Token
245         {
246             get
247             {
248                 return _token;
249             }
250             set
251             {
252                 _token = value;
253             }
254         }
255 
256         public object Node
257         {
258             get
259             {
260                 return _node;
261             }
262             protected set
263             {
264                 _node = value;
265             }
266         }
267 
268         public int Character
269         {
270             get
271             {
272                 return _c;
273             }
274             protected set
275             {
276                 _c = value;
277             }
278         }
279 
280         public int Index
281         {
282             get
283             {
284                 return _index;
285             }
286             protected set
287             {
288                 _index = value;
289             }
290         }
291 
292         public int Line
293         {
294             get
295             {
296                 return _line;
297             }
298             set
299             {
300                 _line = value;
301             }
302         }
303 
304         public int CharPositionInLine
305         {
306             get
307             {
308                 return _charPositionInLine;
309             }
310             set
311             {
312                 _charPositionInLine = value;
313             }
314         }
315 
GetObjectData(SerializationInfo info, StreamingContext context)316         public override void GetObjectData(SerializationInfo info, StreamingContext context)
317         {
318             if (info == null)
319                 throw new ArgumentNullException("info");
320 
321             base.GetObjectData(info, context);
322             info.AddValue("Index", _index);
323             info.AddValue("C", _c);
324             info.AddValue("Line", _line);
325             info.AddValue("CharPositionInLine", _charPositionInLine);
326             info.AddValue("ApproximateLineInfo", _approximateLineInfo);
327         }
328 
ExtractInformationFromTreeNodeStream(ITreeNodeStream input)329         protected virtual void ExtractInformationFromTreeNodeStream(ITreeNodeStream input)
330         {
331             this._node = input.LT(1);
332             ITokenStreamInformation streamInformation = input as ITokenStreamInformation;
333             if (streamInformation != null)
334             {
335                 IToken lastToken = streamInformation.LastToken;
336                 IToken lastRealToken = streamInformation.LastRealToken;
337                 if (lastRealToken != null)
338                 {
339                     this._token = lastRealToken;
340                     this._line = lastRealToken.Line;
341                     this._charPositionInLine = lastRealToken.CharPositionInLine;
342                     this._approximateLineInfo = lastRealToken.Equals(lastToken);
343                 }
344             }
345             else
346             {
347                 ITreeAdaptor adaptor = input.TreeAdaptor;
348                 IToken payload = adaptor.GetToken(_node);
349                 if (payload != null)
350                 {
351                     this._token = payload;
352                     if (payload.Line <= 0)
353                     {
354                         // imaginary node; no line/pos info; scan backwards
355                         int i = -1;
356                         object priorNode = input.LT(i);
357                         while (priorNode != null)
358                         {
359                             IToken priorPayload = adaptor.GetToken(priorNode);
360                             if (priorPayload != null && priorPayload.Line > 0)
361                             {
362                                 // we found the most recent real line / pos info
363                                 this._line = priorPayload.Line;
364                                 this._charPositionInLine = priorPayload.CharPositionInLine;
365                                 this._approximateLineInfo = true;
366                                 break;
367                             }
368                             --i;
369                             try
370                             {
371                                 priorNode = input.LT(i);
372                             }
373                             catch (ArgumentException)
374                             {
375                                 priorNode = null;
376                             }
377                         }
378                     }
379                     else
380                     {
381                         // node created from real token
382                         this._line = payload.Line;
383                         this._charPositionInLine = payload.CharPositionInLine;
384                     }
385                 }
386                 else if (this._node is Tree.ITree)
387                 {
388                     this._line = ((Tree.ITree)this._node).Line;
389                     this._charPositionInLine = ((Tree.ITree)this._node).CharPositionInLine;
390                     if (this._node is CommonTree)
391                     {
392                         this._token = ((CommonTree)this._node).Token;
393                     }
394                 }
395                 else
396                 {
397                     int type = adaptor.GetType(this._node);
398                     string text = adaptor.GetText(this._node);
399                     this._token = new CommonToken(type, text);
400                 }
401             }
402         }
403     }
404 }
405