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    *      http://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       * The version identifier for this Serializable class.
25       * Increment only if the <em>serialized</em> form of the
26       * class changes.
27       */
28      private static final long serialVersionUID = 1L;
29  
30      /*
31       * Ordinals for various reasons why an Error of this type can be thrown.
32       */
33      /**
34       * Lexical error occurred.
35       */
36      public static final int LEXICAL_ERROR = 0;
37      /**
38       * An attempt was made to create a second instance of a static token manager.
39       */
40      public static final int STATIC_LEXER_ERROR = 1;
41      /**
42       * Tried to change to an invalid lexical state.
43       */
44      public static final int INVALID_LEXICAL_STATE = 2;
45      /**
46       * Detected (and bailed out of) an infinite loop in the token manager.
47       */
48      public static final int LOOP_DETECTED = 3;
49      /**
50        * Replaces unprintable characters by their espaced (or unicode escaped)
51        * equivalents in the given string
52        */
53       protected static String addEscapes(final String str) {
54          final StringBuilder retval = new StringBuilder();
55          char ch;
56          for (int i = 0; i < str.length(); i++) {
57            switch (str.charAt(i))
58            {
59               case 0 :
60                  continue;
61               case '\b':
62                  retval.append("//b");
63                  continue;
64               case '\t':
65                  retval.append("//t");
66                  continue;
67               case '\n':
68                  retval.append("//n");
69                  continue;
70               case '\f':
71                  retval.append("//f");
72                  continue;
73               case '\r':
74                  retval.append("//r");
75                  continue;
76               case '\"':
77                  retval.append("//\"");
78                  continue;
79               case '\'':
80                  retval.append("//\'");
81                  continue;
82               case '/':
83                  retval.append("////");
84                  continue;
85               default:
86                  if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
87                     final String s = "0000" + Integer.toString(ch, 16);
88                     retval.append("//u").append(s.substring(s.length() - 4));
89                  } else {
90                     retval.append(ch);
91                  }
92                  continue;
93            }
94          }
95          return retval.toString();
96       }
97      /**
98       * Indicates the reason why the exception is thrown. It will have
99       * one of the above 4 values.
100      */
101     private final int errorCode;
102     /**
103      * The lexer state.
104      */
105     @SuppressWarnings("unused") // not read currently
106     private int state;
107     /**
108      * The current character.
109      */
110     private char current;
111     /**
112      * Last correct input before error occurs.
113      */
114     private String after;
115     /**
116      * Whether eof was reached whilst expecting more input.
117      */
118     private boolean eof;
119     /**
120      * Error line.
121      */
122     private int line;
123 
124     /**
125      * Error column.
126      */
127     private int column;
128 
129     /**
130      * Constructs a new instance.
131      */
132     public TokenMgrException(final boolean EOFSeen, final int lexState, final int errorLine, final int errorColumn,
133                              final String errorAfter, final int curChar, final int reason) {
134         eof = EOFSeen;
135         state = lexState;
136         line = errorLine;
137         column = errorColumn;
138         after = errorAfter;
139         current = (char) curChar;
140         errorCode = reason;
141     }
142 
143     /** Constructor with message and reason. */
144     public TokenMgrException(final String message, final int reason) {
145         super(message);
146         errorCode = reason;
147     }
148 
149     @Override
150     public String getAfter() {
151         return after;
152     }
153 
154     @Override
155     public int getColumn() {
156         return column;
157     }
158 
159     /**
160      * Gets the reason why the exception is thrown.
161      * @return one of the 4 lexical error codes
162      */
163     public int getErrorCode() {
164         return errorCode;
165     }
166 
167     @Override
168     public int getLine() {
169         return line;
170     }
171 
172      /**
173      * Returns a detailed message for the Error when it is thrown by the
174      * token manager to indicate a lexical error.
175      * @return the message
176      */
177     @Override
178     public String getMessage() {
179         return "Lexical error at line "
180                 + line + ", column "
181                 + column + ".  Encountered: "
182                 + (eof ? "<EOF> "
183                    : StringParser.escapeString(String.valueOf(current), '"') + " (" + (int) current + "), ")
184                 + "after : " + StringParser.escapeString(after, '"');
185     }
186 }