View Javadoc

1   package org.apache.velocity.runtime.parser;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import org.apache.velocity.exception.ExtendedParseException;
23  
24  
25  /**
26   * This is an extension of the ParseException, which also takes a
27   * template name.
28   *
29   * @see org.apache.velocity.runtime.parser.ParseException
30   *
31   * @author <a href="hps@intermeta.de">Henning P. Schmiedehausen</a>
32   * @version $Id: TemplateParseException.java 463298 2006-10-12 16:10:32Z henning $
33   */
34  public class TemplateParseException
35          extends ParseException
36          implements ExtendedParseException
37  {
38      private static final long serialVersionUID = -3146323135623083918L;
39  
40      /**
41       * This is the name of the template which contains the parsing error, or
42       * null if not defined.
43       */
44      private final String templateName;
45  
46      /**
47       * This constructor is used to add a template name
48       * to info cribbed from a ParseException generated in the parser.
49       * @param currentTokenVal
50       * @param expectedTokenSequencesVal
51       * @param tokenImageVal
52       * @param templateNameVal
53       */
54      public TemplateParseException(Token currentTokenVal, int [][] expectedTokenSequencesVal, String [] tokenImageVal,
55          String templateNameVal)
56      {
57          super(currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
58          this.templateName = templateNameVal;
59      }
60  
61      /**
62       * This constructor is used by the method "generateParseException"
63       * in the generated parser.  Calling this constructor generates
64       * a new object of this type with the fields "currentToken",
65       * "expectedTokenSequences", and "tokenImage" set.  The boolean
66       * flag "specialConstructor" is also set to true to indicate that
67       * this constructor was used to create this object.
68       * This constructor calls its super class with the empty string
69       * to force the "toString" method of parent class "Throwable" to
70       * print the error message in the form:
71       *     ParseException: <result of getMessage>
72       * @param currentTokenVal
73       * @param expectedTokenSequencesVal
74       * @param tokenImageVal
75       */
76      public TemplateParseException(Token currentTokenVal, int [][] expectedTokenSequencesVal, String [] tokenImageVal)
77      {
78          super(currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
79          templateName = "*unset*";
80      }
81  
82      /**
83       * The following constructors are for use by you for whatever
84       * purpose you can think of.  Constructing the exception in this
85       * manner makes the exception behave in the normal way - i.e., as
86       * documented in the class "Throwable".  The fields "errorToken",
87       * "expectedTokenSequences", and "tokenImage" do not contain
88       * relevant information.  The JavaCC generated code does not use
89       * these constructors.
90       */
91      public TemplateParseException()
92      {
93          super();
94          templateName = "*unset*";
95      }
96  
97      /**
98       * Creates a new TemplateParseException object.
99       *
100      * @param message TODO: DOCUMENT ME!
101      */
102     public TemplateParseException(String message)
103     {
104         super(message);
105         templateName = "*unset*";
106     }
107 
108     /**
109      * returns the Template name where this exception occured.
110      * @return The Template name where this exception occured.
111      */
112     public String getTemplateName()
113     {
114         return templateName;
115     }
116 
117     /**
118      * returns the line number where this exception occured.
119      * @return The line number where this exception occured.
120      */
121     public int getLineNumber()
122     {
123         if ((currentToken != null) && (currentToken.next != null))
124         {
125             return currentToken.next.beginLine;
126         }
127         else
128         {
129             return -1;
130         }
131     }
132 
133     /**
134      * returns the column number where this exception occured.
135      * @return The column number where this exception occured.
136      */
137     public int getColumnNumber()
138     {
139         if ((currentToken != null) && (currentToken.next != null))
140         {
141             return currentToken.next.beginColumn;
142         }
143         else
144         {
145             return -1;
146         }
147     }
148 
149     /**
150      * This method has the standard behavior when this object has been
151      * created using the standard constructors.  Otherwise, it uses
152      * "currentToken" and "expectedTokenSequences" to generate a parse
153      * error message and returns it.  If this object has been created
154      * due to a parse error, and you do not catch it (it gets thrown
155      * from the parser), then this method is called during the printing
156      * of the final stack trace, and hence the correct error message
157      * gets displayed.
158      * @return The error message.
159      */
160     public String getMessage()
161     {
162         if (!specialConstructor)
163         {
164             StringBuffer sb = new StringBuffer(super.getMessage());
165             appendTemplateInfo(sb);
166             return sb.toString();
167         }
168 
169         int maxSize = 0;
170 
171         StringBuffer expected = new StringBuffer();
172 
173         for (int i = 0; i < expectedTokenSequences.length; i++)
174         {
175             if (maxSize < expectedTokenSequences[i].length)
176             {
177                 maxSize = expectedTokenSequences[i].length;
178             }
179 
180             for (int j = 0; j < expectedTokenSequences[i].length; j++)
181             {
182                 expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
183             }
184 
185             if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0)
186             {
187                 expected.append("...");
188             }
189 
190             expected.append(eol).append("    ");
191         }
192 
193         StringBuffer retval = new StringBuffer("Encountered \"");
194         Token tok = currentToken.next;
195 
196         for (int i = 0; i < maxSize; i++)
197         {
198             if (i != 0)
199             {
200                 retval.append(" ");
201             }
202 
203             if (tok.kind == 0)
204             {
205                 retval.append(tokenImage[0]);
206                 break;
207             }
208 
209             retval.append(add_escapes(tok.image));
210             tok = tok.next;
211         }
212 
213         retval.append("\"");
214         appendTemplateInfo(retval);
215 
216         if (expectedTokenSequences.length == 1)
217         {
218             retval.append("Was expecting:").append(eol).append("    ");
219         }
220         else
221         {
222             retval.append("Was expecting one of:").append(eol).append("    ");
223         }
224 
225         // avoid JDK 1.3 StringBuffer.append(Object o) vs 1.4 StringBuffer.append(StringBuffer sb) gotcha.
226         retval.append(expected.toString());
227         return retval.toString();
228     }
229 
230     /**
231      * @param sb
232      */
233     protected void appendTemplateInfo(final StringBuffer sb)
234     {
235         sb.append(" at line ").append(getLineNumber())
236           .append(", column ").append(getColumnNumber());
237 
238         if (getTemplateName() != null)
239         {
240             sb.append(" of ").append(getTemplateName());
241         }
242         else
243         {
244             sb.append(".");
245         }
246         sb.append(eol);
247     }
248 }