1 52 53 package freemarker.core; 54 55 import freemarker.template.utility.SecurityUtilities; 56 57 66 public class ParseException extends java.io.IOException implements FMParserConstants { 67 68 80 public ParseException(Token currentTokenVal, 81 int[][] expectedTokenSequencesVal, 82 String [] tokenImageVal 83 ) 84 { 85 super(""); 86 specialConstructor = true; 87 currentToken = currentTokenVal; 88 expectedTokenSequences = expectedTokenSequencesVal; 89 tokenImage = tokenImageVal; 90 } 91 92 101 102 protected ParseException() { 103 super(); 104 specialConstructor = false; 105 } 106 107 113 114 public ParseException(String 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 message, TemplateObject tobj) { 122 super(message); 123 specialConstructor = false; 124 this.lineNumber = tobj.beginLine; 125 this.columnNumber = tobj.beginColumn; 126 } 127 128 133 protected boolean specialConstructor; 134 135 140 public Token currentToken; 141 142 public int columnNumber, lineNumber; 143 144 149 public int[][] expectedTokenSequences; 150 151 156 public String [] tokenImage; 157 158 168 public String getMessage() { 169 if (!specialConstructor) { 170 return super.getMessage(); 171 } 172 String retval = customGetMessage(); 173 if (retval != null) { 174 return retval; 175 } 176 String 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 227 private String customGetMessage() { 228 Token nextToken = currentToken.next; 229 int kind = nextToken.kind; 230 if (kind == EOF) { 231 StringBuffer buf = new StringBuffer ("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 282 protected String eol = SecurityUtilities.getSystemProperty("line.separator", "\n"); 283 284 289 protected String add_escapes(String str) { 290 StringBuffer retval = new StringBuffer (); 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 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 |