| using Lucene.Net.Support; |
| using System; |
| using System.Diagnostics.CodeAnalysis; |
| #if FEATURE_SERIALIZABLE_EXCEPTIONS |
| using System.Runtime.Serialization; |
| using System.Security.Permissions; |
| #endif |
| using System.Text; |
| |
| namespace Lucene.Net.QueryParsers.Classic |
| { |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /// <summary> |
| /// This exception is thrown when parse errors are encountered. |
| /// You can explicitly create objects of this exception type by |
| /// calling the method GenerateParseException in the generated |
| /// parser. |
| /// |
| /// You can modify this class to customize your error reporting |
| /// mechanisms so long as you retain the public fields. |
| /// </summary> |
| // LUCENENET: It is no longer good practice to use binary serialization. |
| // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568 |
| #if FEATURE_SERIALIZABLE_EXCEPTIONS |
| [Serializable] |
| #endif |
| public class ParseException : Exception |
| { |
| /// <summary> |
| /// This constructor is used by the method GenerateParseException() |
| /// in the generated parser. Calling this constructor generates |
| /// a new object of this type with the fields <paramref name="currentToken"/>, |
| /// <paramref name="expectedTokenSequences"/>, and <paramref name="tokenImage"/> set. |
| /// </summary> |
| public ParseException(Token currentToken, |
| int[][] expectedTokenSequences, |
| string[] tokenImage) |
| : base(Initialize(currentToken, expectedTokenSequences, tokenImage)) |
| { |
| this.CurrentToken = currentToken; |
| this.ExpectedTokenSequences = expectedTokenSequences; |
| this.TokenImage = tokenImage; |
| } |
| |
| /** |
| * The following constructors are for use by you for whatever |
| * purpose you can think of. Constructing the exception in this |
| * manner makes the exception behave in the normal way - i.e., as |
| * documented in the class "Throwable". The fields "errorToken", |
| * "expectedTokenSequences", and "tokenImage" do not contain |
| * relevant information. The JavaCC generated code does not use |
| * these constructors. |
| */ |
| |
| public ParseException() |
| { } |
| |
| public ParseException(string message) |
| : base(message) |
| { } |
| |
| public ParseException(string message, Exception innerException) |
| : base(message, innerException) |
| { } |
| |
| #if FEATURE_SERIALIZABLE_EXCEPTIONS |
| /// <summary> |
| /// Initializes a new instance of this class with serialized data. |
| /// </summary> |
| /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param> |
| /// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param> |
| protected ParseException(SerializationInfo info, StreamingContext context) |
| : base(info, context) |
| { |
| CurrentToken = (Token)info.GetValue("CurrentToken", typeof(Token)); |
| ExpectedTokenSequences = (int[][])info.GetValue("ExpectedTokenSequences", typeof(int[][])); |
| TokenImage = (string[])info.GetValue("TokenImage", typeof(string[])); |
| } |
| |
| [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] |
| public override void GetObjectData(SerializationInfo info, StreamingContext context) |
| { |
| base.GetObjectData(info, context); |
| info.AddValue("CurrentToken", CurrentToken, typeof(Token)); |
| info.AddValue("ExpectedTokenSequences", ExpectedTokenSequences, typeof(int[][])); |
| info.AddValue("TokenImage", TokenImage, typeof(string[])); |
| } |
| #endif |
| |
| /// <summary> |
| /// This is the last token that has been consumed successfully. If |
| /// this object has been created due to a parse error, the token |
| /// following this token will (therefore) be the first error token. |
| /// </summary> |
| public Token CurrentToken { get; set; } |
| |
| /// <summary> |
| /// Each entry in this array is an array of integers. Each array |
| /// of integers represents a sequence of tokens (by their ordinal |
| /// values) that is expected at this point of the parse. |
| /// </summary> |
| [WritableArray] |
| [SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")] |
| public int[][] ExpectedTokenSequences { get; set; } |
| |
| /// <summary> |
| /// This is a reference to the "tokenImage" array of the generated |
| /// parser within which the parse error occurred. This array is |
| /// defined in the generated ...Constants interface. |
| /// </summary> |
| [WritableArray] |
| [SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")] |
| public string[] TokenImage { get; set; } |
| |
| |
| /// <summary> |
| /// It uses <paramref name="currentToken"/> and <paramref name="expectedTokenSequences"/> to generate a parse |
| /// error message and returns it. If this object has been created |
| /// due to a parse error, and you do not catch it (it gets thrown |
| /// from the parser) the correct error message |
| /// gets displayed. |
| /// </summary> |
| private static string Initialize(Token currentToken, |
| int[][] expectedTokenSequences, |
| string[] tokenImage) |
| { |
| |
| StringBuilder expected = new StringBuilder(); |
| int maxSize = 0; |
| for (int i = 0; i < expectedTokenSequences.Length; i++) |
| { |
| if (maxSize < expectedTokenSequences[i].Length) |
| { |
| maxSize = expectedTokenSequences[i].Length; |
| } |
| for (int j = 0; j < expectedTokenSequences[i].Length; j++) |
| { |
| expected.Append(tokenImage[expectedTokenSequences[i][j]]).Append(' '); |
| } |
| if (expectedTokenSequences[i][expectedTokenSequences[i].Length - 1] != 0) |
| { |
| expected.Append("..."); |
| } |
| expected.Append(eol).Append(" "); |
| } |
| string retval = "Encountered \""; |
| Token tok = currentToken.Next; |
| for (int i = 0; i < maxSize; i++) |
| { |
| if (i != 0) |
| retval += " "; |
| if (tok.Kind == 0) |
| { |
| retval += tokenImage[0]; |
| break; |
| } |
| retval += (" " + tokenImage[tok.Kind]); |
| retval += " \""; |
| retval += AddEscapes(tok.Image); |
| retval += " \""; |
| tok = tok.Next; |
| } |
| retval += ("\" at line " + currentToken.Next.BeginLine + ", column " + currentToken.Next.BeginColumn); |
| retval += ("." + eol); |
| if (expectedTokenSequences.Length == 1) |
| { |
| retval += ("Was expecting:" + eol + " "); |
| } |
| else |
| { |
| retval += ("Was expecting one of:" + eol + " "); |
| } |
| retval += expected.ToString(); |
| return retval; |
| } |
| |
| /// <summary> |
| /// The end of line string for this machine. |
| /// </summary> |
| protected static string eol = Environment.NewLine; |
| |
| /// <summary> |
| /// Used to convert raw characters to their escaped version |
| /// when these raw version cannot be used as part of an ASCII |
| /// string literal. |
| /// </summary> |
| internal static string AddEscapes(string str) |
| { |
| StringBuilder retval = new StringBuilder(); |
| char ch; |
| for (int i = 0; i < str.Length; i++) |
| { |
| switch (str[i]) |
| { |
| |
| case (char) (0): |
| continue; |
| |
| case '\b': |
| retval.Append("\\b"); |
| continue; |
| |
| case '\t': |
| retval.Append("\\t"); |
| continue; |
| |
| case '\n': |
| retval.Append("\\n"); |
| continue; |
| |
| case '\f': |
| retval.Append("\\f"); |
| continue; |
| |
| case '\r': |
| retval.Append("\\r"); |
| continue; |
| |
| case '\"': |
| retval.Append("\\\""); |
| continue; |
| |
| case '\'': |
| retval.Append("\\\'"); |
| continue; |
| |
| case '\\': |
| retval.Append("\\\\"); |
| continue; |
| |
| default: |
| if ((ch = str[i]) < 0x20 || ch > 0x7e) |
| { |
| string s = "0000" + Convert.ToString(ch, 16); |
| retval.Append("\\u" + s.Substring(s.Length - 4, (s.Length) - (s.Length - 4))); |
| } |
| else |
| { |
| retval.Append(ch); |
| } |
| continue; |
| |
| } |
| } |
| return retval.ToString(); |
| } |
| } |
| } |