001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.expression.ast;
005:
006: /**
007: * This exception is thrown when parse errors are encountered. You can explicitly create objects of this exception type
008: * by calling the method generateParseException in the generated parser. You can modify this class to customize your
009: * error reporting mechanisms so long as you retain the public fields.
010: */
011: public class ParseException extends Exception {
012:
013: /**
014: * This constructor is used by the method "generateParseException" in the generated parser. Calling this constructor
015: * generates a new object of this type with the fields "currentToken", "expectedTokenSequences", and "tokenImage"
016: * set. The boolean flag "specialConstructor" is also set to true to indicate that this constructor was used to
017: * create this object. This constructor calls its super class with the empty string to force the "toString" method
018: * of parent class "Throwable" to print the error message in the form: ParseException: <result of getMessage>
019: */
020: public ParseException(Token currentTokenVal,
021: int[][] expectedTokenSequencesVal, String[] tokenImageVal) {
022: super ("");
023: specialConstructor = true;
024: currentToken = currentTokenVal;
025: expectedTokenSequences = expectedTokenSequencesVal;
026: tokenImage = tokenImageVal;
027: }
028:
029: /**
030: * The following constructors are for use by you for whatever purpose you can think of. Constructing the exception
031: * in this manner makes the exception behave in the normal way - i.e., as documented in the class "Throwable". The
032: * fields "errorToken", "expectedTokenSequences", and "tokenImage" do not contain relevant information. The JavaCC
033: * generated code does not use these constructors.
034: */
035:
036: public ParseException() {
037: super ();
038: specialConstructor = false;
039: }
040:
041: public ParseException(String message) {
042: super (message);
043: specialConstructor = false;
044: }
045:
046: /**
047: * This variable determines which constructor was used to create this object and thereby affects the semantics of
048: * the "getMessage" method (see below).
049: */
050: protected boolean specialConstructor;
051:
052: /**
053: * This is the last token that has been consumed successfully. If this object has been created due to a parse error,
054: * the token followng this token will (therefore) be the first error token.
055: */
056: public Token currentToken;
057:
058: /**
059: * Each entry in this array is an array of integers. Each array of integers represents a sequence of tokens (by
060: * their ordinal values) that is expected at this point of the parse.
061: */
062: public int[][] expectedTokenSequences;
063:
064: /**
065: * This is a reference to the "tokenImage" array of the generated parser within which the parse error occurred. This
066: * array is defined in the generated ...Constants interface.
067: */
068: public String[] tokenImage;
069:
070: /**
071: * This method has the standard behavior when this object has been created using the standard constructors.
072: * Otherwise, it uses "currentToken" and "expectedTokenSequences" to generate a parse error message and returns it.
073: * If this object has been created due to a parse error, and you do not catch it (it gets thrown from the parser),
074: * then this method is called during the printing of the final stack trace, and hence the correct error message gets
075: * displayed.
076: */
077: public String getMessage() {
078: if (!specialConstructor) {
079: return super .getMessage();
080: }
081: String expected = "";
082: int maxSize = 0;
083: for (int i = 0; i < expectedTokenSequences.length; i++) {
084: if (maxSize < expectedTokenSequences[i].length) {
085: maxSize = expectedTokenSequences[i].length;
086: }
087: for (int j = 0; j < expectedTokenSequences[i].length; j++) {
088: expected += tokenImage[expectedTokenSequences[i][j]]
089: + " ";
090: }
091: if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
092: expected += "...";
093: }
094: expected += eol + " ";
095: }
096: String retval = "Encountered \"";
097: Token tok = currentToken.next;
098: for (int i = 0; i < maxSize; i++) {
099: if (i != 0) {
100: retval += " ";
101: }
102: if (tok.kind == 0) {
103: retval += tokenImage[0];
104: break;
105: }
106: retval += add_escapes(tok.image);
107: tok = tok.next;
108: }
109: retval += "\" at line " + currentToken.next.beginLine
110: + ", column " + currentToken.next.beginColumn;
111: retval += "." + eol;
112: if (expectedTokenSequences.length == 1) {
113: retval += "Was expecting:" + eol + " ";
114: } else {
115: retval += "Was expecting one of:" + eol + " ";
116: }
117: retval += expected;
118: return retval;
119: }
120:
121: /**
122: * The end of line string for this machine.
123: */
124: protected String eol = System.getProperty("line.separator", "\n");
125:
126: /**
127: * Used to convert raw characters to their escaped version when these raw version cannot be used as part of an ASCII
128: * string literal.
129: */
130: protected String add_escapes(String str) {
131: StringBuffer retval = new StringBuffer();
132: char ch;
133: for (int i = 0; i < str.length(); i++) {
134: switch (str.charAt(i)) {
135: case 0:
136: continue;
137: case '\b':
138: retval.append("\\b");
139: continue;
140: case '\t':
141: retval.append("\\t");
142: continue;
143: case '\n':
144: retval.append("\\n");
145: continue;
146: case '\f':
147: retval.append("\\f");
148: continue;
149: case '\r':
150: retval.append("\\r");
151: continue;
152: case '\"':
153: retval.append("\\\"");
154: continue;
155: case '\'':
156: retval.append("\\\'");
157: continue;
158: case '\\':
159: retval.append("\\\\");
160: continue;
161: default:
162: if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
163: String s = "0000" + Integer.toString(ch, 16);
164: retval.append("\\u"
165: + s.substring(s.length() - 4, s.length()));
166: } else {
167: retval.append(ch);
168: }
169: continue;
170: }
171: }
172: return retval.toString();
173: }
174:
175: }
|