+ private void gatherProxRelation(CQLProxNode node)
+ throws CQLParseException, IOException {
+ if (!isProxRelation())
+ throw new CQLParseException("expected proximity relation, got " +
+ lexer.render());
+ node.addModifier("relation", lexer.render(lexer.ttype, false));
+ match(lexer.ttype);
+ debug("gPR matched " + lexer.render(lexer.ttype, false));
+ }
+
+ private void gatherProxDistance(CQLProxNode node)
+ throws CQLParseException, IOException {
+ if (lexer.ttype != lexer.TT_NUMBER)
+ throw new CQLParseException("expected proximity distance, got " +
+ lexer.render());
+ node.addModifier("distance", lexer.render(lexer.ttype, false));
+ match(lexer.ttype);
+ debug("gPD matched " + lexer.render(lexer.ttype, false));
+ }
+
+ private void gatherProxUnit(CQLProxNode node)
+ throws CQLParseException, IOException {
+ if (lexer.ttype != lexer.TT_pWORD &&
+ lexer.ttype != lexer.TT_SENTENCE &&
+ lexer.ttype != lexer.TT_PARAGRAPH &&
+ lexer.ttype != lexer.TT_ELEMENT)
+ throw new CQLParseException("expected proximity unit, got " +
+ lexer.render());
+ node.addModifier("unit", lexer.render());
+ match(lexer.ttype);
+ }
+
+ private void gatherProxOrdering(CQLProxNode node)
+ throws CQLParseException, IOException {
+ if (lexer.ttype != lexer.TT_ORDERED &&
+ lexer.ttype != lexer.TT_UNORDERED)
+ throw new CQLParseException("expected proximity ordering, got " +
+ lexer.render());
+ node.addModifier("ordering", lexer.render());
+ match(lexer.ttype);
+ }
+
+ private boolean isBaseRelation() {
+ debug("isBaseRelation: checking ttype=" + lexer.ttype +
+ " (" + lexer.render() + ")");
+ return (isProxRelation() ||
+ lexer.ttype == lexer.TT_ANY ||
+ lexer.ttype == lexer.TT_ALL ||
+ lexer.ttype == lexer.TT_EXACT ||
+ lexer.ttype == lexer.TT_SCR);
+ }
+
+ // Checks for a relation that may be used inside a prox operator
+ private boolean isProxRelation() {
+ debug("isProxRelation: checking ttype=" + lexer.ttype +
+ " (" + lexer.render() + ")");
+ return (lexer.ttype == '<' ||
+ lexer.ttype == '>' ||
+ lexer.ttype == '=' ||
+ lexer.ttype == lexer.TT_LE ||
+ lexer.ttype == lexer.TT_GE ||
+ lexer.ttype == lexer.TT_NE);
+ }
+
+ private void match(int token)
+ throws CQLParseException, IOException {
+ debug("in match(" + lexer.render(token, true) + ")");
+ if (lexer.ttype != token)
+ throw new CQLParseException("expected " +
+ lexer.render(token, true) +
+ ", " + "got " + lexer.render());
+ int tmp = lexer.nextToken();
+ debug("match() got token=" + lexer.ttype + ", " +
+ "nval=" + lexer.nval + ", sval='" + lexer.sval + "'" +
+ " (tmp=" + tmp + ")");
+ }
+
+ private String matchSymbol(String expected)
+ throws CQLParseException, IOException {
+
+ debug("in matchSymbol()");
+ if (lexer.ttype == lexer.TT_WORD ||
+ lexer.ttype == lexer.TT_NUMBER ||
+ lexer.ttype == '"' ||
+ // The following is a complete list of keywords. Because
+ // they're listed here, they can be used unquoted as
+ // qualifiers, 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.
+ lexer.ttype == lexer.TT_AND ||
+ lexer.ttype == lexer.TT_OR ||
+ lexer.ttype == lexer.TT_NOT ||
+ lexer.ttype == lexer.TT_PROX ||
+ lexer.ttype == lexer.TT_ANY ||
+ lexer.ttype == lexer.TT_ALL ||
+ lexer.ttype == lexer.TT_EXACT ||
+ lexer.ttype == lexer.TT_pWORD ||
+ lexer.ttype == lexer.TT_SENTENCE ||
+ lexer.ttype == lexer.TT_PARAGRAPH ||
+ lexer.ttype == lexer.TT_ELEMENT ||
+ lexer.ttype == lexer.TT_ORDERED ||
+ lexer.ttype == lexer.TT_UNORDERED ||
+ lexer.ttype == lexer.TT_RELEVANT ||
+ lexer.ttype == lexer.TT_FUZZY ||
+ lexer.ttype == lexer.TT_STEM ||
+ lexer.ttype == lexer.TT_SCR ||
+ lexer.ttype == lexer.TT_PHONETIC) {
+ String symbol = (lexer.ttype == lexer.TT_NUMBER) ?
+ lexer.render() : lexer.sval;
+ match(lexer.ttype);
+ return symbol;