* The resulting parse tree may be further processed by hand (see @@ -96,14 +133,16 @@ public class CQLParser { * tree representing the query. */ public CQLNode parse(Reader cql) throws CQLParseException, IOException { - lexer = new CQLLexer(cql, LEXDEBUG); + par = new PositionAwareReader(cql); + lexer = new CQLLexer(par, LEXDEBUG); lexer.nextToken(); debug("about to parseQuery()"); CQLNode root = parseTopLevelPrefixes("cql.serverChoice", new CQLRelation(compat == V1POINT2 ? "=" : "scr")); if (lexer.ttype != CQLLexer.TT_EOF) - throw new CQLParseException("junk after end: " + lexer.render()); + throw new CQLParseException("junk after end: " + lexer.render(), + par.getPosition()); return root; } @@ -130,7 +169,7 @@ public class CQLParser { } if (sortnode.keys.size() == 0) { - throw new CQLParseException("no sort keys"); + throw new CQLParseException("no sort keys", par.getPosition()); } node = sortnode; @@ -162,7 +201,7 @@ public class CQLParser { new CQLProxNode(term, term2, ms)); } else { throw new CQLParseException("expected boolean, got " + - lexer.render()); + lexer.render(), par.getPosition()); } } @@ -179,7 +218,8 @@ public class CQLParser { match('/'); if (lexer.ttype != CQLLexer.TT_WORD) throw new CQLParseException("expected modifier, " - + "got " + lexer.render()); + + "got " + lexer.render(), + par.getPosition()); String type = lexer.sval.toLowerCase(); match(lexer.ttype); if (!isSymbolicRelation()) { @@ -270,7 +310,8 @@ public class CQLParser { lexer.sval.equals("encloses") || (lexer.sval.equals("exact") && compat != V1POINT2) || (lexer.sval.equals("scr") && compat != V1POINT2) || - (lexer.sval.equals("adj") && compat == V1POINT2))) + (lexer.sval.equals("adj") && compat == V1POINT2) || + customRelations.contains(lexer.sval))) return true; return isSymbolicRelation(); @@ -294,7 +335,8 @@ public class CQLParser { if (lexer.ttype != token) throw new CQLParseException("expected " + lexer.render(token, true) + - ", " + "got " + lexer.render()); + ", " + "got " + lexer.render(), + par.getPosition()); int tmp = lexer.nextToken(); debug("match() got token=" + lexer.ttype + ", " + "nval=" + lexer.nval + ", sval='" + lexer.sval + "'" + @@ -313,11 +355,12 @@ public class CQLParser { // indexes, terms, prefix names and prefix identifiers. // ### Instead, we should ask the lexer whether what we // have is a keyword, and let the knowledge reside there. + (allowKeywordTerms && lexer.ttype == CQLLexer.TT_AND || lexer.ttype == CQLLexer.TT_OR || lexer.ttype == CQLLexer.TT_NOT || lexer.ttype == CQLLexer.TT_PROX || - lexer.ttype == CQLLexer.TT_SORTBY) { + lexer.ttype == CQLLexer.TT_SORTBY)) { String symbol = (lexer.ttype == CQLLexer.TT_NUMBER) ? lexer.render() : lexer.sval; match(lexer.ttype); @@ -325,7 +368,7 @@ public class CQLParser { } throw new CQLParseException("expected " + expected + ", " + - "got " + lexer.render()); + "got " + lexer.render(), par.getPosition()); }