Till Westmann has submitted this change and it was merged. Change subject: Easier to read parser errors for SQL++ ......................................................................
Easier to read parser errors for SQL++ Change-Id: I13fd54fe2b1237b937a1706cf83fb47ce536b546 Reviewed-on: https://asterix-gerrit.ics.uci.edu/1182 Tested-by: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Reviewed-by: abdullah alamoudi <[email protected]> --- M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml 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 3 files changed, 135 insertions(+), 9 deletions(-) Approvals: abdullah alamoudi: Looks good to me, approved Jenkins: Verified; Verified Objections: Jenkins: Violations found diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index 54f06e6..c19593b 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -3163,7 +3163,7 @@ <test-case FilePath="open-index-enforced/error-checking"> <compilation-unit name="missing-optionality"> <output-dir compare="Text">missing-optionality</output-dir> - <expected-error>"?"</expected-error> + <expected-error>string) enforced</expected-error> </compilation-unit> </test-case> <test-case FilePath="open-index-enforced/error-checking"> 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..07aa473 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,10 @@ public class ScopeChecker { + protected static String quot = "\""; + + protected String eol = System.getProperty("line.separator", "\n"); + protected Counter varCounter = new Counter(-1); protected Stack<Scope> scopeStack = new Stack<Scope>(); @@ -57,7 +61,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 +73,6 @@ /** * Extend the current scope * - * @param scopeStack * @return */ public final Scope extendCurrentScope() { @@ -172,7 +174,88 @@ return false; } - public static final String removeQuotesAndEscapes(String s) { + 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 escaped = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + appendChar(escaped, str.charAt(i)); + } + return escaped.toString(); + } + + private static void appendChar(StringBuilder escaped, char c) { + char ch; + switch (c) { + case 0: + return; + case '\b': + escaped.append("\\b"); + return; + case '\t': + escaped.append("\\t"); + return; + case '\n': + escaped.append("\\n"); + return; + case '\f': + escaped.append("\\f"); + return; + case '\r': + escaped.append("\\r"); + return; + case '\"': + escaped.append("\\\""); + return; + case '\'': + escaped.append("\\\'"); + return; + case '\\': + escaped.append("\\\\"); + return; + default: + if ((ch = c) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + escaped.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + escaped.append(ch); + } + } + } + + public static String removeQuotesAndEscapes(String s) { char q = s.charAt(0); // simple or double quote String stripped = s.substring(1, s.length() - 1); int pos = stripped.indexOf('\\'); @@ -220,7 +303,11 @@ return res.toString(); } - public String extractFragment(int beginLine, int beginColumn, int endLine, int endColumn) { + protected String getLine(int line) { + return inputLines[line - 1]; + } + + protected String extractFragment(int beginLine, int beginColumn, int endLine, int endColumn) { StringBuilder extract = new StringBuilder(); if (beginLine == endLine) { // special case that we need to handle separately diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj index 9cabf84..dab178b 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 message = "In line " + line + " >>" + getLine(line) + "<<" + sep + "Encountered "; + for (int i = 0; i < maxSize; i++) { + if (i != 0) { + message += " "; + } + if (tok.kind == 0) { + message += fixQuotes(tokenImage[0]); + break; + } + message += fixQuotes(tokenImage[tok.kind]) + " "; + message += quot + addEscapes(tok.image) + quot; + tok = tok.next; + } + message += " at column " + currentToken.next.beginColumn + "." + sep; + if (REPORT_EXPECTED_TOKENS) { + if (expectedTokenSequences.length == 1) { + message += "Was expecting:" + sep + " "; + } else { + message += "Was expecting one of:" + sep + " "; + } + message += expected.toString(); + } + return message; + } + } 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: merged Gerrit-Change-Id: I13fd54fe2b1237b937a1706cf83fb47ce536b546 Gerrit-PatchSet: 4 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Till Westmann <[email protected]> Gerrit-Reviewer: Jenkins <[email protected]> Gerrit-Reviewer: Till Westmann <[email protected]> Gerrit-Reviewer: Yingyi Bu <[email protected]> Gerrit-Reviewer: abdullah alamoudi <[email protected]>
