KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > core > ParseException


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.core;
54
55 import freemarker.template.utility.SecurityUtilities;
56
57 /**
58  * This exception is thrown when parse errors are encountered.
59  * You can explicitly create objects of this exception type by
60  * calling the method generateParseException in the generated
61  * parser.
62  *
63  * You can modify this class to customize your error reporting
64  * mechanisms so long as you retain the public fields.
65  */

66 public class ParseException extends java.io.IOException JavaDoc implements FMParserConstants {
67
68   /**
69    * This constructor is used by the method "generateParseException"
70    * in the generated parser. Calling this constructor generates
71    * a new object of this type with the fields "currentToken",
72    * "expectedTokenSequences", and "tokenImage" set. The boolean
73    * flag "specialConstructor" is also set to true to indicate that
74    * this constructor was used to create this object.
75    * This constructor calls its super class with the empty string
76    * to force the "toString" method of parent class "Throwable" to
77    * print the error message in the form:
78    * ParseException: <result of getMessage>
79    */

80   public ParseException(Token currentTokenVal,
81                         int[][] expectedTokenSequencesVal,
82                         String JavaDoc[] tokenImageVal
83                        )
84   {
85     super("");
86     specialConstructor = true;
87     currentToken = currentTokenVal;
88     expectedTokenSequences = expectedTokenSequencesVal;
89     tokenImage = tokenImageVal;
90   }
91
92   /**
93    * The following constructors are for use by you for whatever
94    * purpose you can think of. Constructing the exception in this
95    * manner makes the exception behave in the normal way - i.e., as
96    * documented in the class "Throwable". The fields "errorToken",
97    * "expectedTokenSequences", and "tokenImage" do not contain
98    * relevant information. The JavaCC generated code does not use
99    * these constructors.
100    */

101
102   protected ParseException() {
103     super();
104     specialConstructor = false;
105   }
106
107 /*
108   public ParseException(String message) {
109     super(message);
110     specialConstructor = false;
111   }
112 */

113
114   public ParseException(String JavaDoc message, int lineNumber, int columnNumber) {
115       super(message);
116       specialConstructor = false;
117       this.lineNumber = lineNumber;
118       this.columnNumber = columnNumber;
119   }
120
121   public ParseException(String JavaDoc message, TemplateObject tobj) {
122       super(message);
123       specialConstructor = false;
124       this.lineNumber = tobj.beginLine;
125       this.columnNumber = tobj.beginColumn;
126   }
127
128   /**
129    * This variable determines which constructor was used to create
130    * this object and thereby affects the semantics of the
131    * "getMessage" method (see below).
132    */

133   protected boolean specialConstructor;
134
135   /**
136    * This is the last token that has been consumed successfully. If
137    * this object has been created due to a parse error, the token
138    * following this token will (therefore) be the first error token.
139    */

140   public Token currentToken;
141
142   public int columnNumber, lineNumber;
143
144   /**
145    * Each entry in this array is an array of integers. Each array
146    * of integers represents a sequence of tokens (by their ordinal
147    * values) that is expected at this point of the parse.
148    */

149   public int[][] expectedTokenSequences;
150
151   /**
152    * This is a reference to the "tokenImage" array of the generated
153    * parser within which the parse error occurred. This array is
154    * defined in the generated ...Constants interface.
155    */

156   public String JavaDoc[] tokenImage;
157
158   /**
159    * This method has the standard behavior when this object has been
160    * created using the standard constructors. Otherwise, it uses
161    * "currentToken" and "expectedTokenSequences" to generate a parse
162    * error message and returns it. If this object has been created
163    * due to a parse error, and you do not catch it (it gets thrown
164    * from the parser), then this method is called during the printing
165    * of the final stack trace, and hence the correct error message
166    * gets displayed.
167    */

168   public String JavaDoc getMessage() {
169     if (!specialConstructor) {
170       return super.getMessage();
171     }
172     String JavaDoc retval = customGetMessage();
173     if (retval != null) {
174         return retval;
175     }
176     // The default JavaCC message generation stuff follows.
177
String JavaDoc expected = "";
178     int maxSize = 0;
179     for (int i = 0; i < expectedTokenSequences.length; i++) {
180       if (maxSize < expectedTokenSequences[i].length) {
181         maxSize = expectedTokenSequences[i].length;
182       }
183       for (int j = 0; j < expectedTokenSequences[i].length; j++) {
184         expected += tokenImage[expectedTokenSequences[i][j]] + " ";
185       }
186       if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
187         expected += "...";
188       }
189       expected += eol + " ";
190     }
191     retval = "Encountered \"";
192     Token tok = currentToken.next;
193     for (int i = 0; i < maxSize; i++) {
194       if (i != 0) retval += " ";
195       if (tok.kind == 0) {
196         retval += tokenImage[0];
197         break;
198       }
199       retval += add_escapes(tok.image);
200       tok = tok.next;
201     }
202     retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
203     retval += "." + eol;
204     if (expectedTokenSequences.length == 1) {
205       retval += "Was expecting:" + eol + " ";
206     } else {
207       retval += "Was expecting one of:" + eol + " ";
208     }
209     retval += expected;
210     return retval;
211   }
212
213   public int getLineNumber() {
214       return currentToken != null ?
215                              currentToken.next.beginLine :
216                              lineNumber;
217   }
218
219   public int getColumnNumber() {
220       return currentToken != null ?
221                              currentToken.next.beginColumn :
222                              columnNumber;
223   }
224
225   // Custom message generation
226

227   private String JavaDoc customGetMessage() {
228       Token nextToken = currentToken.next;
229       int kind = nextToken.kind;
230       if (kind == EOF) {
231           StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Unexpected end of file reached.\n");
232           for (int i = 0; i<expectedTokenSequences.length; i++) {
233               int[] sequence = expectedTokenSequences[i];
234               switch (sequence[0]) {
235                   case END_FOREACH :
236                       buf.append("Unclosed foreach directive.\n");
237                       break;
238                   case END_LIST :
239                       buf.append("Unclosed list directive.\n");
240                       break;
241                   case END_SWITCH :
242                       buf.append("Unclosed switch directive.\n");
243                       break;
244                   case END_IF :
245                       buf.append("Unclosed if directive.\n");
246                       break;
247                   case END_COMPRESS :
248                       buf.append("Unclosed compress directive.\n");
249                       break;
250                   case END_MACRO :
251                       buf.append("Unclosed macro directive.\n");
252                       break;
253                   case END_FUNCTION :
254                       buf.append("Unclosed function directive.\n");
255                       break;
256                   case END_TRANSFORM :
257                       buf.append("Unclosed transform directive.\n");
258                       break;
259                   case END_ESCAPE :
260                       buf.append("Unclosed escape directive.\n");
261                       break;
262                   case END_NOESCAPE :
263                       buf.append("Unclosed noescape directive.\n");
264                       break;
265               }
266           }
267           return buf.toString();
268       }
269       if (kind == END_IF || kind == ELSE_IF || kind == ELSE) {
270           return "Found unexpected directive: "
271               + nextToken
272               + " on line " + nextToken.beginLine
273               + ", column " + nextToken.beginColumn
274               + "\nCheck whether you have a well-formed if-else block.";
275       }
276       return null;
277   }
278
279   /**
280    * The end of line string for this machine.
281    */

282   protected String JavaDoc eol = SecurityUtilities.getSystemProperty("line.separator", "\n");
283
284   /**
285    * Used to convert raw characters to their escaped version
286    * when these raw version cannot be used as part of an ASCII
287    * string literal.
288    */

289   protected String JavaDoc add_escapes(String JavaDoc str) {
290       StringBuffer JavaDoc retval = new StringBuffer JavaDoc();
291       char ch;
292       for (int i = 0; i < str.length(); i++) {
293         switch (str.charAt(i))
294         {
295            case 0 :
296               continue;
297            case '\b':
298               retval.append("\\b");
299               continue;
300            case '\t':
301               retval.append("\\t");
302               continue;
303            case '\n':
304               retval.append("\\n");
305               continue;
306            case '\f':
307               retval.append("\\f");
308               continue;
309            case '\r':
310               retval.append("\\r");
311               continue;
312            case '\"':
313               retval.append("\\\"");
314               continue;
315            case '\'':
316               retval.append("\\\'");
317               continue;
318            case '\\':
319               retval.append("\\\\");
320               continue;
321            default:
322               if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
323                  String JavaDoc s = "0000" + Integer.toString(ch, 16);
324                  retval.append("\\u" + s.substring(s.length() - 4, s.length()));
325               } else {
326                  retval.append(ch);
327               }
328               continue;
329         }
330       }
331       return retval.toString();
332    }
333
334 }
335
Popular Tags