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 }