Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 39 additions & 39 deletions src/main/java/org/z3950/zing/cql/CQLParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CQLParser {
private CQLTokenizer lexer;
private final int compat; // When false, implement CQL 1.2
private final Set<String> customRelations = new HashSet<String>();

public static final int V1POINT1 = 12368;
public static final int V1POINT2 = 12369;
public static final int V1POINT1SORT = 12370;
Expand All @@ -47,10 +47,10 @@ public CQLParser(int compat) {
this.compat = compat;
this.allowKeywordTerms = true;
}

/**
* Official CQL grammar allows registered keywords like 'and/or/not/sortby/prox'
* to be used unquoted in terms. This constructor allows to create an instance
* Official CQL grammar allows registered keywords like 'and/or/not/sortby/prox'
* to be used unquoted in terms. This constructor allows to create an instance
* of a parser that prohibits this behavior while sacrificing compatibility.
* @param compat CQL version compatibility
* @param allowKeywordTerms when false registered keywords are disallowed in unquoted terms
Expand All @@ -59,7 +59,7 @@ public CQLParser(int compat, boolean allowKeywordTerms) {
this.compat = compat;
this.allowKeywordTerms = allowKeywordTerms;
}

/**
* The new parser implements CQL 1.2
*/
Expand All @@ -72,24 +72,25 @@ private static void debug(String str) {
if (DEBUG)
System.err.println("PARSEDEBUG: " + str);
}

/**
* Registers custom relation in this parser. Note that when a custom relation
* is registered the parser is no longer strictly compliant with the chosen spec.
* Custom relations are case-insensitive.
* @param relation
* @return true if custom relation has not been registered already
*/
public boolean registerCustomRelation(String relation) {
return customRelations.add(relation);
return customRelations.add(relation.toLowerCase());
}

/**
* Unregisters previously registered custom relation in this instance of the parser.
* @param relation
* @return true is relation has been previously registered
*/
public boolean unregisterCustomRelation(String relation) {
return customRelations.remove(relation);
return customRelations.remove(relation.toLowerCase());
}

/**
Expand Down Expand Up @@ -117,7 +118,7 @@ public CQLNode parse(String cql)
CQLNode root = parseTopLevelPrefixes("cql.serverChoice",
new CQLRelation(compat == V1POINT2 ? "=" : "scr"));
if (lexer.what() != CQLTokenizer.TT_EOF)
throw new CQLParseException("junk after end: " + lexer.render(),
throw new CQLParseException("junk after end: " + lexer.render(),
lexer.pos());

return root;
Expand Down Expand Up @@ -194,7 +195,7 @@ private ModifierSet gatherModifiers(String base)
match('/');
if (lexer.what() != CQLTokenizer.TT_WORD)
throw new CQLParseException("expected modifier, "
+ "got " + lexer.render(),
+ "got " + lexer.render(),
lexer.pos());
String type = lexer.value().toLowerCase();
match(lexer.what());
Expand Down Expand Up @@ -241,7 +242,7 @@ private CQLNode parseTerm(String index, CQLRelation relation)

if (!isRelation())
break; //we're done if no relation

//render relation
String relstr = (lexer.what() == CQLTokenizer.TT_WORD ?
lexer.value() : lexer.render(lexer.what(), false));
Expand Down Expand Up @@ -282,40 +283,39 @@ private CQLNode parsePrefix(String index, CQLRelation relation,

return new CQLPrefixNode(name, identifier, node);
}

private boolean isWordOrString() {
return CQLTokenizer.TT_WORD == lexer.what()
return CQLTokenizer.TT_WORD == lexer.what()
|| CQLTokenizer.TT_STRING == lexer.what();
}

private boolean isRelation() {
debug("isRelation: checking what()=" + lexer.what() +
" (" + lexer.render() + ")");
if (lexer.what() == CQLTokenizer.TT_WORD &&
(lexer.value().indexOf('.') >= 0 ||
lexer.value().equals("any") ||
lexer.value().equals("all") ||
lexer.value().equals("within") ||
lexer.value().equals("encloses") ||
(lexer.value().equals("exact") && compat != V1POINT2) ||
(lexer.value().equals("scr") && compat != V1POINT2) ||
(lexer.value().equals("adj") && compat == V1POINT2) ||
customRelations.contains(lexer.value())))
return true;

debug("isRelation: checking what()=" + lexer.what() +
" (" + lexer.render() + ")");
if (lexer.what() == CQLTokenizer.TT_WORD) {
return lexer.value().indexOf('.') >= 0 ||
lexer.value().equalsIgnoreCase("any") ||
lexer.value().equalsIgnoreCase("all") ||
lexer.value().equalsIgnoreCase("within") ||
lexer.value().equalsIgnoreCase("encloses") ||
(lexer.value().equalsIgnoreCase("exact") && compat != V1POINT2) ||
(lexer.value().equalsIgnoreCase("scr") && compat != V1POINT2) ||
(lexer.value().equalsIgnoreCase("adj") && compat == V1POINT2) ||
customRelations.stream().anyMatch(r -> r.equalsIgnoreCase(lexer.value()));
}
return isSymbolicRelation();
}

private boolean isSymbolicRelation() {
debug("isSymbolicRelation: checking what()=" + lexer.what() +
" (" + lexer.render() + ")");
return (lexer.what() == '<' ||
lexer.what() == '>' ||
lexer.what() == '=' ||
lexer.what() == CQLTokenizer.TT_LE ||
lexer.what() == CQLTokenizer.TT_GE ||
lexer.what() == CQLTokenizer.TT_NE ||
lexer.what() == CQLTokenizer.TT_EQEQ);
debug("isSymbolicRelation: checking what()=" + lexer.what() +
" (" + lexer.render() + ")");
return (lexer.what() == '<' ||
lexer.what() == '>' ||
lexer.what() == '=' ||
lexer.what() == CQLTokenizer.TT_LE ||
lexer.what() == CQLTokenizer.TT_GE ||
lexer.what() == CQLTokenizer.TT_NE ||
lexer.what() == CQLTokenizer.TT_EQEQ);
}

private void match(int token)
Expand All @@ -324,7 +324,7 @@ private void match(int token)
if (lexer.what() != token)
throw new CQLParseException("expected " +
lexer.render(token, true) +
", " + "got " + lexer.render(),
", " + "got " + lexer.render(),
lexer.pos());
lexer.move();
debug("match() got token=" + lexer.what() + ", value()='" + lexer.value() + "'");
Expand Down Expand Up @@ -500,7 +500,7 @@ public static void main (String[] args) {
f.close();
System.out.println(root.toPQF(config));
} catch (IOException ex) {
System.err.println("Can't load PQF properties:" +
System.err.println("Can't load PQF properties:" +
ex.getMessage());
System.exit(5);
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/regression/02/03.cql
Original file line number Diff line number Diff line change
@@ -1 +1 @@
title any fish
title Any fish
2 changes: 1 addition & 1 deletion src/test/resources/regression/02/03.xcql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<searchClause>
<index>title</index>
<relation>
<value>any</value>
<value>Any</value>
</relation>
<term>fish</term>
</searchClause>
2 changes: 1 addition & 1 deletion src/test/resources/regression/09/06.cql
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sortby sortby sortby sortby sortby
Sortby Sortby Sortby Sortby Sortby
8 changes: 4 additions & 4 deletions src/test/resources/regression/09/06.xcql
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
<relation>
<value>=</value>
</relation>
<term>sortby</term>
<term>Sortby</term>
<sortKeys>
<key>
<index>sortby</index>
<index>Sortby</index>
</key>
<key>
<index>sortby</index>
<index>Sortby</index>
</key>
<key>
<index>sortby</index>
<index>Sortby</index>
</key>
</sortKeys>
</searchClause>