001: package org.apache.velocity.runtime.parser;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import org.apache.velocity.exception.ExtendedParseException;
023:
024: /**
025: * This is an extension of the ParseException, which also takes a
026: * template name.
027: *
028: * @see org.apache.velocity.runtime.parser.ParseException
029: *
030: * @author <a href="hps@intermeta.de">Henning P. Schmiedehausen</a>
031: * @version $Id: TemplateParseException.java 463298 2006-10-12 16:10:32Z henning $
032: */
033: public class TemplateParseException extends ParseException implements
034: ExtendedParseException {
035: private static final long serialVersionUID = -3146323135623083918L;
036:
037: /**
038: * This is the name of the template which contains the parsing error, or
039: * null if not defined.
040: */
041: private final String templateName;
042:
043: /**
044: * This constructor is used to add a template name
045: * to info cribbed from a ParseException generated in the parser.
046: * @param currentTokenVal
047: * @param expectedTokenSequencesVal
048: * @param tokenImageVal
049: * @param templateNameVal
050: */
051: public TemplateParseException(Token currentTokenVal,
052: int[][] expectedTokenSequencesVal, String[] tokenImageVal,
053: String templateNameVal) {
054: super (currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
055: this .templateName = templateNameVal;
056: }
057:
058: /**
059: * This constructor is used by the method "generateParseException"
060: * in the generated parser. Calling this constructor generates
061: * a new object of this type with the fields "currentToken",
062: * "expectedTokenSequences", and "tokenImage" set. The boolean
063: * flag "specialConstructor" is also set to true to indicate that
064: * this constructor was used to create this object.
065: * This constructor calls its super class with the empty string
066: * to force the "toString" method of parent class "Throwable" to
067: * print the error message in the form:
068: * ParseException: <result of getMessage>
069: * @param currentTokenVal
070: * @param expectedTokenSequencesVal
071: * @param tokenImageVal
072: */
073: public TemplateParseException(Token currentTokenVal,
074: int[][] expectedTokenSequencesVal, String[] tokenImageVal) {
075: super (currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
076: templateName = "*unset*";
077: }
078:
079: /**
080: * The following constructors are for use by you for whatever
081: * purpose you can think of. Constructing the exception in this
082: * manner makes the exception behave in the normal way - i.e., as
083: * documented in the class "Throwable". The fields "errorToken",
084: * "expectedTokenSequences", and "tokenImage" do not contain
085: * relevant information. The JavaCC generated code does not use
086: * these constructors.
087: */
088: public TemplateParseException() {
089: super ();
090: templateName = "*unset*";
091: }
092:
093: /**
094: * Creates a new TemplateParseException object.
095: *
096: * @param message TODO: DOCUMENT ME!
097: */
098: public TemplateParseException(String message) {
099: super (message);
100: templateName = "*unset*";
101: }
102:
103: /**
104: * returns the Template name where this exception occured.
105: * @return The Template name where this exception occured.
106: */
107: public String getTemplateName() {
108: return templateName;
109: }
110:
111: /**
112: * returns the line number where this exception occured.
113: * @return The line number where this exception occured.
114: */
115: public int getLineNumber() {
116: if ((currentToken != null) && (currentToken.next != null)) {
117: return currentToken.next.beginLine;
118: } else {
119: return -1;
120: }
121: }
122:
123: /**
124: * returns the column number where this exception occured.
125: * @return The column number where this exception occured.
126: */
127: public int getColumnNumber() {
128: if ((currentToken != null) && (currentToken.next != null)) {
129: return currentToken.next.beginColumn;
130: } else {
131: return -1;
132: }
133: }
134:
135: /**
136: * This method has the standard behavior when this object has been
137: * created using the standard constructors. Otherwise, it uses
138: * "currentToken" and "expectedTokenSequences" to generate a parse
139: * error message and returns it. If this object has been created
140: * due to a parse error, and you do not catch it (it gets thrown
141: * from the parser), then this method is called during the printing
142: * of the final stack trace, and hence the correct error message
143: * gets displayed.
144: * @return The error message.
145: */
146: public String getMessage() {
147: if (!specialConstructor) {
148: StringBuffer sb = new StringBuffer(super .getMessage());
149: appendTemplateInfo(sb);
150: return sb.toString();
151: }
152:
153: int maxSize = 0;
154:
155: StringBuffer expected = new StringBuffer();
156:
157: for (int i = 0; i < expectedTokenSequences.length; i++) {
158: if (maxSize < expectedTokenSequences[i].length) {
159: maxSize = expectedTokenSequences[i].length;
160: }
161:
162: for (int j = 0; j < expectedTokenSequences[i].length; j++) {
163: expected.append(
164: tokenImage[expectedTokenSequences[i][j]])
165: .append(" ");
166: }
167:
168: if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
169: expected.append("...");
170: }
171:
172: expected.append(eol).append(" ");
173: }
174:
175: StringBuffer retval = new StringBuffer("Encountered \"");
176: Token tok = currentToken.next;
177:
178: for (int i = 0; i < maxSize; i++) {
179: if (i != 0) {
180: retval.append(" ");
181: }
182:
183: if (tok.kind == 0) {
184: retval.append(tokenImage[0]);
185: break;
186: }
187:
188: retval.append(add_escapes(tok.image));
189: tok = tok.next;
190: }
191:
192: retval.append("\"");
193: appendTemplateInfo(retval);
194:
195: if (expectedTokenSequences.length == 1) {
196: retval.append("Was expecting:").append(eol).append(" ");
197: } else {
198: retval.append("Was expecting one of:").append(eol).append(
199: " ");
200: }
201:
202: // avoid JDK 1.3 StringBuffer.append(Object o) vs 1.4 StringBuffer.append(StringBuffer sb) gotcha.
203: retval.append(expected.toString());
204: return retval.toString();
205: }
206:
207: /**
208: * @param sb
209: */
210: protected void appendTemplateInfo(final StringBuffer sb) {
211: sb.append(" at line ").append(getLineNumber()).append(
212: ", column ").append(getColumnNumber());
213:
214: if (getTemplateName() != null) {
215: sb.append(" of ").append(getTemplateName());
216: } else {
217: sb.append(".");
218: }
219: sb.append(eol);
220: }
221: }
|