* @version $Id: CQLParseException.java,v 1.2 2002-11-06 20:13:45 mike Exp $
*/
public class CQLParseException extends Exception {
+ private int pos;
/**
* Creates a new <TT>CQLParseException</TT>.
* @param s
* An error message describing the problem with the query,
* usually a syntax error of some kind.
*/
- public CQLParseException(String s) {
+ public CQLParseException(String s, int pos) {
super(s);
+ this.pos = pos;
+ }
+
+ /**
+ * Character position of the parsing error.
+ * @return
+ */
+ public int getPosition() {
+ return pos;
}
}
*/
public class CQLParser {
private CQLLexer lexer;
+ private PositionAwareReader par; //active reader with position
private int compat; // When false, implement CQL 1.2
public static final int V1POINT1 = 12368;
public static final int V1POINT2 = 12369;
* 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;
}
}
if (sortnode.keys.size() == 0) {
- throw new CQLParseException("no sort keys");
+ throw new CQLParseException("no sort keys", par.getPosition());
}
node = sortnode;
new CQLProxNode(term, term2, ms));
} else {
throw new CQLParseException("expected boolean, got " +
- lexer.render());
+ lexer.render(), par.getPosition());
}
}
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()) {
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 + "'" +
}
throw new CQLParseException("expected " + expected + ", " +
- "got " + lexer.render());
+ "got " + lexer.render(), par.getPosition());
}
--- /dev/null
+/*
+ * Copyright (c) 1995-2012, Index Data
+ * All rights reserved.
+ * See the file LICENSE for details.
+ */
+package org.z3950.zing.cql;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.CharBuffer;
+
+/**
+ * Reader proxy to count how many characters has been read so far.
+ * @author jakub
+ */
+public class PositionAwareReader extends Reader {
+ protected Reader reader;
+ protected int pos = -1;
+
+ public PositionAwareReader(Reader reader) {
+ this.reader = reader;
+ }
+
+ /*
+ * Position of the last read character or -1 if either reading from an empty
+ * stream or no 'read' has been invoked for this reader.
+ */
+ public int getPosition() {
+ return pos;
+ }
+
+ @Override
+ public void mark(int readAheadLimit) throws IOException {
+ reader.mark(readAheadLimit);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return reader.markSupported();
+ }
+
+ @Override
+ public int read() throws IOException {
+ int c = reader.read();
+ if (c != -1) pos++;
+ return c;
+ }
+
+ @Override
+ public int read(char[] cbuf) throws IOException {
+ int c = reader.read(cbuf);
+ if (c != -1) pos+=c;
+ return c;
+ }
+
+ @Override
+ public int read(CharBuffer target) throws IOException {
+ int c = reader.read(target);
+ if (c != -1) pos+=c;
+ return c;
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ int c = reader.read(cbuf, off, len);
+ if (c != -1) pos+=c;
+ return c;
+ }
+
+ @Override
+ public boolean ready() throws IOException {
+ return reader.ready();
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return reader.skip(n);
+ }
+
+ @Override
+ public void close() throws IOException {
+ reader.close();
+ }
+
+ @Override
+ public void reset() throws IOException {
+ reader.reset();
+ }
+
+ //override object methods, to be on the safe-side
+
+ @Override
+ public boolean equals(Object obj) {
+ return reader.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return reader.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return reader.hashCode();
+ }
+
+}