View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.parser;
18  
19  /**
20   * Token Manager Error.
21   */
22  public class TokenMgrException extends RuntimeException implements JavaccError {
23  
24      /**
25       * The version identifier for this Serializable class.
26       * Increment only if the <em>serialized</em> form of the
27       * class changes.
28       */
29      private static final long serialVersionUID = 1L;
30  
31      /*
32       * Ordinals for various reasons why an Error of this type can be thrown.
33       */
34  
35      /**
36       * Lexical error occurred.
37       */
38      public static final int LEXICAL_ERROR = 0;
39  
40      /**
41       * An attempt was made to create a second instance of a static token manager.
42       */
43      public static final int STATIC_LEXER_ERROR = 1;
44  
45      /**
46       * Tried to change to an invalid lexical state.
47       */
48      public static final int INVALID_LEXICAL_STATE = 2;
49  
50      /**
51       * Detected (and bailed out of) an infinite loop in the token manager.
52       */
53      public static final int LOOP_DETECTED = 3;
54  
55      /**
56        * Replaces unprintable characters by their espaced (or unicode escaped)
57        * equivalents in the given string
58        */
59       protected static String addEscapes(final String str) {
60          final StringBuilder retval = new StringBuilder();
61          char ch;
62          for (int i = 0; i < str.length(); i++) {
63            switch (str.charAt(i))
64            {
65               case 0 :
66                  continue;
67               case '\b':
68                  retval.append("//b");
69                  continue;
70               case '\t':
71                  retval.append("//t");
72                  continue;
73               case '\n':
74                  retval.append("//n");
75                  continue;
76               case '\f':
77                  retval.append("//f");
78                  continue;
79               case '\r':
80                  retval.append("//r");
81                  continue;
82               case '\"':
83                  retval.append("//\"");
84                  continue;
85               case '\'':
86                  retval.append("//\'");
87                  continue;
88               case '/':
89                  retval.append("////");
90                  continue;
91               default:
92                  if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
93                     final String s = "0000" + Integer.toString(ch, 16);
94                     retval.append("//u").append(s.substring(s.length() - 4));
95                  } else {
96                     retval.append(ch);
97                  }
98                  continue;
99            }
100         }
101         return retval.toString();
102      }
103 
104     /**
105      * Indicates the reason why the exception is thrown. It will have
106      * one of the above 4 values.
107      */
108     private final int errorCode;
109 
110     /**
111      * The lexer state.
112      */
113     @SuppressWarnings("unused") // not read currently
114     private int state;
115 
116     /**
117      * The current character.
118      */
119     private char current;
120 
121     /**
122      * Last correct input before error occurs.
123      */
124     private String after;
125 
126     /**
127      * Whether eof was reached whilst expecting more input.
128      */
129     private boolean eof;
130 
131     /**
132      * Error line.
133      */
134     private int line;
135 
136     /**
137      * Error column.
138      */
139     private int column;
140 
141     /**
142      * Constructs a new instance.
143      */
144     public TokenMgrException(final boolean EOFSeen, final int lexState, final int errorLine, final int errorColumn,
145                              final String errorAfter, final int curChar, final int reason) {
146         eof = EOFSeen;
147         state = lexState;
148         line = errorLine;
149         column = errorColumn;
150         after = errorAfter;
151         current = (char) curChar;
152         errorCode = reason;
153     }
154 
155     /** Constructor with message and reason. */
156     public TokenMgrException(final String message, final int reason) {
157         super(message);
158         errorCode = reason;
159     }
160 
161     @Override
162     public String getAfter() {
163         return after;
164     }
165 
166     @Override
167     public int getColumn() {
168         return column;
169     }
170 
171     /**
172      * Gets the reason why the exception is thrown.
173      *
174      * @return one of the 4 lexical error codes
175      */
176     public int getErrorCode() {
177         return errorCode;
178     }
179 
180     @Override
181     public int getLine() {
182         return line;
183     }
184 
185      /**
186      * Returns a detailed message for the Error when it is thrown by the
187      * token manager to indicate a lexical error.
188      *
189      * @return the message
190      */
191     @Override
192     public String getMessage() {
193         return "Lexical error at line "
194                 + line + ", column "
195                 + column + ".  Encountered: "
196                 + (eof ? "<EOF> "
197                    : StringParser.escapeString(String.valueOf(current), '"') + " (" + (int) current + "), ")
198                 + "after : " + StringParser.escapeString(after, '"');
199     }
200 }