Till Westmann has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/1182

Change subject: Easier to read parser errors for SQL++
......................................................................

Easier to read parser errors for SQL++

Change-Id: I13fd54fe2b1237b937a1706cf83fb47ce536b546
---
M 
asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
2 files changed, 130 insertions(+), 6 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/82/1182/1

diff --git 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
index dc0fa93..4c4766a 100644
--- 
a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
+++ 
b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/ScopeChecker.java
@@ -29,6 +29,9 @@
 
 public class ScopeChecker {
 
+    protected static String QUOT = "\"";
+    protected static String NL = "\n";
+
     protected Counter varCounter = new Counter(-1);
 
     protected Stack<Scope> scopeStack = new Stack<Scope>();
@@ -57,7 +60,6 @@
     /**
      * Create a new scope, using the top scope in scopeStack as parent scope
      *
-     * @param scopeStack
      * @return new scope
      */
     public final Scope createNewScope() {
@@ -70,7 +72,6 @@
     /**
      * Extend the current scope
      *
-     * @param scopeStack
      * @return
      */
     public final Scope extendCurrentScope() {
@@ -172,6 +173,86 @@
         return false;
     }
 
+    protected String eol = System.getProperty("line.separator", NL);
+
+    protected int appendExpected(StringBuilder expected, int[][] 
expectedTokenSequences, String[] tokenImage) {
+        int maxSize = 0;
+        for (int i = 0; i < expectedTokenSequences.length; i++) {
+            if (maxSize < expectedTokenSequences[i].length) {
+                maxSize = expectedTokenSequences[i].length;
+            }
+            for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+                append(expected, 
fixQuotes(tokenImage[expectedTokenSequences[i][j]]));
+                append(expected, " ");
+            }
+            if (expectedTokenSequences[i][expectedTokenSequences[i].length - 
1] != 0) {
+                append(expected, "...");
+            }
+            append(expected, eol);
+            append(expected, "    ");
+        }
+        return maxSize;
+    }
+
+    private void append(StringBuilder expected, String str) {
+        if (expected != null) {
+            expected.append(str);
+        }
+    }
+
+    protected String fixQuotes(String token) {
+        final int last = token.length() - 1;
+        if (token.charAt(0) == '"' && token.charAt(last) == '"') {
+            return "'" + token.substring(1, last) + "'";
+        } else {
+            return token;
+        }
+    }
+
+    protected static String addEscapes(String str) {
+        StringBuilder retval = new StringBuilder();
+        char ch;
+        for (int i = 0; i < str.length(); i++) {
+            switch (str.charAt(i)) {
+                case 0:
+                    continue;
+                case '\b':
+                    retval.append("\\b");
+                    continue;
+                case '\t':
+                    retval.append("\\t");
+                    continue;
+                case '\n':
+                    retval.append("\\n");
+                    continue;
+                case '\f':
+                    retval.append("\\f");
+                    continue;
+                case '\r':
+                    retval.append("\\r");
+                    continue;
+                case '\"':
+                    retval.append("\\\"");
+                    continue;
+                case '\'':
+                    retval.append("\\\'");
+                    continue;
+                case '\\':
+                    retval.append("\\\\");
+                    continue;
+                default:
+                    if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                        String s = "0000" + Integer.toString(ch, 16);
+                        retval.append("\\u" + s.substring(s.length() - 4, 
s.length()));
+                    } else {
+                        retval.append(ch);
+                    }
+                    continue;
+            }
+        }
+        return retval.toString();
+    }
+
     public static final String removeQuotesAndEscapes(String s) {
         char q = s.charAt(0); // simple or double quote
         String stripped = s.substring(1, s.length() - 1);
@@ -220,6 +301,10 @@
         return res.toString();
     }
 
+    public String getLine(int line) {
+        return inputLines[line - 1];
+    }
+
     public String extractFragment(int beginLine, int beginColumn, int endLine, 
int endColumn) {
         StringBuilder extract = new StringBuilder();
         if (beginLine == endLine) {
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj 
b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 9cabf84..d7463f9 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -151,8 +151,6 @@
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 
-
-
 class SQLPPParser extends ScopeChecker implements IParser {
 
     // optimizer hints
@@ -178,6 +176,9 @@
 
     // data generator hints
     private static final String DGEN_HINT = "dgen";
+
+    // error configuration
+    protected static final boolean REPORT_EXPECTED_TOKENS = false;
 
     private static class IndexParams {
       public IndexType type;
@@ -251,7 +252,7 @@
       return rfdg;
     }
 
-    public SQLPPParser(String s){
+    public SQLPPParser(String s) {
         this(new StringReader(s));
         super.setInput(s);
     }
@@ -272,9 +273,47 @@
             // by the ANTLR-generated lexer or parser (e.g it does this for 
invalid backslash u + 4 hex digits escapes)
             throw new AsterixException(new ParseException(e.getMessage()));
         } catch (ParseException e) {
-            throw new AsterixException(e.getMessage());
+            throw new AsterixException("Syntax error: " + getMessage(e));
         }
     }
+
+    protected String getMessage(ParseException pe) {
+        Token currentToken = pe.currentToken;
+        if (currentToken == null) {
+            return pe.getMessage();
+        }
+        int[][] expectedTokenSequences = pe.expectedTokenSequences;
+        String[] tokenImage = pe.tokenImage;
+        String sep = REPORT_EXPECTED_TOKENS ? eol : " ";
+        StringBuilder expected = REPORT_EXPECTED_TOKENS ? new StringBuilder() 
: null;
+        int maxSize = appendExpected(expected, expectedTokenSequences, 
tokenImage);
+        Token tok = currentToken.next;
+        int line = tok.beginLine;
+        String retval = "In line " + line + " >>" + getLine(line) + "<<" + sep 
+ "Encountered ";
+        for (int i = 0; i < maxSize; i++) {
+            if (i != 0) {
+                retval += " ";
+            }
+            if (tok.kind == 0) {
+                retval += fixQuotes(tokenImage[0]);
+                break;
+            }
+            retval += fixQuotes(tokenImage[tok.kind]) + " ";
+            retval += QUOT + addEscapes(tok.image) + QUOT;
+            tok = tok.next;
+        }
+        retval += " at column " + currentToken.next.beginColumn + "." + sep;
+        if (REPORT_EXPECTED_TOKENS) {
+            if (expectedTokenSequences.length == 1) {
+                retval += "Was expecting:" + sep + "    ";
+            } else {
+                retval += "Was expecting one of:" + sep + "    ";
+            }
+            retval += expected.toString();
+        }
+        return retval;
+    }
+
 }
 
 PARSER_END(SQLPPParser)

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/1182
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I13fd54fe2b1237b937a1706cf83fb47ce536b546
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Till Westmann <ti...@apache.org>

Reply via email to