From db60fd485297a360e886ad1d8f76ef16ea94c42e Mon Sep 17 00:00:00 2001 From: Jakub Skoczen Date: Fri, 16 Mar 2012 16:57:07 +0100 Subject: [PATCH] Record position in parse exception --- .../java/org/z3950/zing/cql/CQLParseException.java | 12 ++- src/main/java/org/z3950/zing/cql/CQLParser.java | 19 ++-- .../org/z3950/zing/cql/PositionAwareReader.java | 107 ++++++++++++++++++++ 3 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/z3950/zing/cql/PositionAwareReader.java diff --git a/src/main/java/org/z3950/zing/cql/CQLParseException.java b/src/main/java/org/z3950/zing/cql/CQLParseException.java index ee237f5..ceb97de 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParseException.java +++ b/src/main/java/org/z3950/zing/cql/CQLParseException.java @@ -9,14 +9,24 @@ package org.z3950.zing.cql; * @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 CQLParseException. * @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; } } diff --git a/src/main/java/org/z3950/zing/cql/CQLParser.java b/src/main/java/org/z3950/zing/cql/CQLParser.java index 795b2f1..62a51b6 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParser.java +++ b/src/main/java/org/z3950/zing/cql/CQLParser.java @@ -21,6 +21,7 @@ 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 public static final int V1POINT1 = 12368; public static final int V1POINT2 = 12369; @@ -96,14 +97,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 +133,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 +165,7 @@ public class CQLParser { new CQLProxNode(term, term2, ms)); } else { throw new CQLParseException("expected boolean, got " + - lexer.render()); + lexer.render(), par.getPosition()); } } @@ -179,7 +182,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()) { @@ -294,7 +298,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 + "'" + @@ -325,7 +330,7 @@ public class CQLParser { } throw new CQLParseException("expected " + expected + ", " + - "got " + lexer.render()); + "got " + lexer.render(), par.getPosition()); } diff --git a/src/main/java/org/z3950/zing/cql/PositionAwareReader.java b/src/main/java/org/z3950/zing/cql/PositionAwareReader.java new file mode 100644 index 0000000..b3294c0 --- /dev/null +++ b/src/main/java/org/z3950/zing/cql/PositionAwareReader.java @@ -0,0 +1,107 @@ +/* + * 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(); + } + +} -- 1.7.10.4