X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Forg%2Fz3950%2Fzing%2Fcql%2FCQLParser.java;h=d577cd9435a9c153530eda78cea35e53029f2258;hb=1d03472f13d7cf463707da0027b9c796cde27812;hp=25095631a6cb4a4446227425c9aa4eb48c4dc3ba;hpb=2ef8d2fc0e5a32518b1a5750e6f68cdb91e64de2;p=cql-java-moved-to-github.git diff --git a/src/main/java/org/z3950/zing/cql/CQLParser.java b/src/main/java/org/z3950/zing/cql/CQLParser.java index 2509563..d577cd9 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParser.java +++ b/src/main/java/org/z3950/zing/cql/CQLParser.java @@ -8,7 +8,9 @@ import java.io.FileNotFoundException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** @@ -20,10 +22,13 @@ import java.util.List; public class CQLParser { private CQLLexer lexer; private PositionAwareReader par; //active reader with position - private int compat; // When false, implement CQL 1.2 + private final int compat; // When false, implement CQL 1.2 + private final Set customRelations = new HashSet(); + public static final int V1POINT1 = 12368; public static final int V1POINT2 = 12369; public static final int V1POINT1SORT = 12370; + public final boolean allowKeywordTerms; static private boolean DEBUG = false; static private boolean LEXDEBUG = false; @@ -43,13 +48,27 @@ public class CQLParser { */ 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 + * 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 + */ + public CQLParser(int compat, boolean allowKeywordTerms) { + this.compat = V1POINT2; + this.allowKeywordTerms = allowKeywordTerms; + } + /** * The new parser implements CQL 1.2 */ public CQLParser() { this.compat = V1POINT2; + this.allowKeywordTerms = true; } private static void debug(String str) { @@ -58,6 +77,25 @@ public class CQLParser { } /** + * 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. + * @param relation + * @return true if custom relation has not been registered already + */ + public boolean registerCustomRelation(String relation) { + return customRelations.add(relation); + } + + /** + * 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); + } + + /** * Compiles a CQL query. *

* The resulting parse tree may be further processed by hand (see @@ -272,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(); @@ -316,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);