aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java')
-rw-r--r--trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java225
1 files changed, 225 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
new file mode 100644
index 0000000..c73db34
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/InformativeParser.java
@@ -0,0 +1,225 @@
+package org.mozilla.javascript;
+
+import java.io.IOException;
+
+/**
+ * Subclass of Rhino's Parser that saves information about the token stream
+ * and error message to allow more helpful error messages.
+ *
+ * @author David Greenspan for AppJet
+ */
+
+/*
+ This class is written with speed in mind, to some extent. Rhino's tokenizer
+ is pretty efficient, and we wouldn't want to slow it down by, for example,
+ creating a TokenInfo object on the heap for every token seen.
+ */
+
+/*APPJET*/
+public class InformativeParser extends Parser {
+
+ public static class InformativeEvaluatorException extends EvaluatorException {
+ final ParseErrorInfo pei;
+
+ InformativeEvaluatorException(String errorMessage,
+ String sourceName, int lineNumber,
+ String lineSource, int columnNumber,
+ ParseErrorInfo peInfo) {
+ super(errorMessage, sourceName,
+ lineNumber, lineSource, columnNumber);
+ pei = peInfo;
+ }
+
+ public ParseErrorInfo getParseErrorInfo() {
+ return pei;
+ }
+ }
+
+ public static class ParseErrorInfo {
+ ParseErrorInfo() {}
+
+ String messageId = null;
+ String messageArg = null;
+
+ final int tokenMaxHistory = 10;
+ // ring buffers
+ final int[] tokenTypes = new int[tokenMaxHistory];
+ final String[] tokenStrings = new String[tokenMaxHistory];
+ final double[] tokenNumbers = new double[tokenMaxHistory];
+ final int[] tokenLineNumbers = new int[tokenMaxHistory];
+ final int[] tokenLineOffsets = new int[tokenMaxHistory];
+ int nextBufPos = 0;
+ int historyLength = 0;
+ boolean tokenPeeking = false;
+ int peekSlot;
+
+ void reportPeekToken(int type, String str, double num, int lineno,
+ int lineOffset) {
+ if (! tokenPeeking) {
+ peekSlot = nextBufPos;
+ tokenTypes[nextBufPos] = type;
+ tokenStrings[nextBufPos] = str;
+ tokenNumbers[nextBufPos] = num;
+ tokenLineNumbers[nextBufPos] = lineno;
+ tokenLineOffsets[nextBufPos] = lineOffset;
+
+ nextBufPos++;
+ if (nextBufPos == tokenMaxHistory) nextBufPos = 0;
+ if (historyLength < tokenMaxHistory) historyLength++;
+ tokenPeeking = true;
+ }
+ }
+
+ void reportConsumeToken() {
+ tokenPeeking = false;
+ }
+
+ private TokenInfo backToken(int n) {
+ // 0 is most recent token added to history
+ if (n >= historyLength) return null;
+ int i = (nextBufPos - 1 - n);
+ while (i < 0) i += tokenMaxHistory;
+ return new TokenInfo(tokenTypes[i], tokenStrings[i],
+ tokenNumbers[i], tokenLineNumbers[i],
+ tokenLineOffsets[i]);
+ }
+
+ public String getMessageId() { return messageId; }
+ public String getMessageArg() { return messageArg; }
+ public TokenInfo getPeekToken() {
+ if (tokenPeeking) return backToken(0);
+ return null;
+ }
+ public TokenInfo getPrevToken(int n) {
+ // 1 = last non-peek token seen, 2 = before that, etc.
+ if (! tokenPeeking) n--;
+ return backToken(n);
+ }
+ public TokenInfo getPrevToken() {
+ return getPrevToken(1);
+ }
+ }
+
+ public static class TokenInfo {
+ private int type, lineno, lineOffset;
+ private String str;
+ private double num;
+ TokenInfo(int type, String str, double num, int lineno,
+ int lineOffset) {
+ this.type = type; this.str = str; this.num = num;
+ this.lineno = lineno; this.lineOffset = lineOffset;
+ }
+ public int getType() { return type; }
+ public int getLineNumber() { return lineno; }
+ public int getLineOffset() { return lineOffset; }
+ public double getNumber() { return num; }
+ public String getString() { return str; }
+ }
+
+ ParseErrorInfo info = new ParseErrorInfo();
+
+ void doErrorReporterError(String message, String sourceURI, int line,
+ String lineText, int lineOffset) {
+
+ throw new InformativeEvaluatorException(message, sourceURI, line,
+ lineText, lineOffset, info);
+
+ }
+
+ public InformativeParser(CompilerEnvirons compilerEnv) {
+ // we override most calls to the parent's ErrorReporter anyway
+ super(compilerEnv, DefaultErrorReporter.instance);
+ }
+
+ @Override int peekToken() throws IOException {
+ int tt = super.peekToken();
+ info.reportPeekToken(tt, ts.getString(), ts.getNumber(),
+ ts.getLineno(), ts.getOffset());
+ return tt;
+ }
+ @Override void consumeToken() {
+ super.consumeToken();
+ info.reportConsumeToken();
+ }
+
+ @Override void addWarning(String messageId, String messageArg)
+ {
+ info.messageId = messageId;
+ info.messageArg = messageArg;
+
+ String message = ScriptRuntime.getMessage1(messageId, messageArg);
+ if (compilerEnv.reportWarningAsError()) {
+ ++syntaxErrorCount;
+ doErrorReporterError(message, sourceURI, ts.getLineno(),
+ ts.getLine(), ts.getOffset());
+ }
+ else { /* don't report */ }
+ }
+
+ @Override void addError(String messageId)
+ {
+ info.messageId = messageId;
+
+ ++syntaxErrorCount;
+ String message = ScriptRuntime.getMessage0(messageId);
+ doErrorReporterError(message, sourceURI, ts.getLineno(),
+ ts.getLine(), ts.getOffset());
+ }
+
+ @Override void addError(String messageId, String messageArg)
+ {
+ info.messageId = messageId;
+ info.messageArg = messageArg;
+
+ ++syntaxErrorCount;
+ String message = ScriptRuntime.getMessage1(messageId, messageArg);
+ doErrorReporterError(message, sourceURI, ts.getLineno(),
+ ts.getLine(), ts.getOffset());
+ }
+
+ @Override protected Decompiler createDecompiler(CompilerEnvirons env) {
+ return new MyDecompiler();
+ }
+
+ public static final ErrorReporter THROW_INFORMATIVE_ERRORS
+ = new ErrorReporter() {
+ public void warning(String message, String sourceURI, int line,
+ String lineText, int lineOffset) {
+ DefaultErrorReporter.instance.warning
+ (message, sourceURI, line, lineText, lineOffset);
+ }
+ public void error(String message, String sourceURI, int line,
+ String lineText, int lineOffset) {
+ DefaultErrorReporter.instance.error
+ (message, sourceURI, line, lineText, lineOffset);
+ }
+ public EvaluatorException runtimeError(String message,
+ String sourceURI,
+ int line, String lineText,
+ int lineOffset) {
+ return DefaultErrorReporter.instance.runtimeError
+ (message, sourceURI, line, lineText, lineOffset);
+ }
+
+ };
+
+ public static Parser makeParser(CompilerEnvirons compilerEnv,
+ ErrorReporter errorReporter) {
+ if (errorReporter == THROW_INFORMATIVE_ERRORS) {
+ return new InformativeParser(compilerEnv);
+ }
+ else {
+ return new Parser(compilerEnv, errorReporter);
+ }
+ }
+
+ private class MyDecompiler extends Decompiler {
+ @Override void addRegexp(String regexp, String flags) {
+ super.addRegexp(regexp, flags);
+ String str = '/'+regexp+'/'+flags;
+ info.reportPeekToken(Token.REGEXP, str, ts.getNumber(),
+ ts.getLineno(), ts.getOffset());
+ info.reportConsumeToken();
+ }
+ }
+} \ No newline at end of file