Repository: cayenne Updated Branches: refs/heads/master 666c96de1 -> c44ccfde3
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c44ccfde/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JavaCharStream.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JavaCharStream.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JavaCharStream.java index 7394b28..4065980 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JavaCharStream.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/JavaCharStream.java @@ -29,8 +29,7 @@ import java.io.IOException; * contain only ASCII characters (with java-like unicode escape processing). */ -public class JavaCharStream -{ +public class JavaCharStream { // optimizing internal Exception by reusing the exception per CAY-1667. This exception // never reaches the end user, so we can suppress stack trace creation and make it @@ -40,547 +39,603 @@ public class JavaCharStream @Override public synchronized Throwable fillInStackTrace() { return this; - }; + } }; - -/** Whether parser is static. */ - public static final boolean staticFlag = false; - static final int hexval(char c) throws java.io.IOException { - switch(c) - { - case '0' : - return 0; - case '1' : - return 1; - case '2' : - return 2; - case '3' : - return 3; - case '4' : - return 4; - case '5' : - return 5; - case '6' : - return 6; - case '7' : - return 7; - case '8' : - return 8; - case '9' : - return 9; - - case 'a' : - case 'A' : - return 10; - case 'b' : - case 'B' : - return 11; - case 'c' : - case 'C' : - return 12; - case 'd' : - case 'D' : - return 13; - case 'e' : - case 'E' : - return 14; - case 'f' : - case 'F' : - return 15; - } - - throw new java.io.IOException(); // Should never come here - } - -/** Position in buffer. */ - public int bufpos = -1; - int bufsize; - int available; - int tokenBegin; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] nextCharBuf; - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int nextCharInd = -1; - protected int inBuf = 0; - protected int tabSize = 8; - private boolean closed; - - protected void setTabSize(int i) { tabSize = i; } - protected int getTabSize(int i) { return tabSize; } - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - bufpos += (bufsize - tokenBegin); + + /** + * Whether parser is static. + */ + public static final boolean staticFlag = false; + + static final int hexval(char c) throws java.io.IOException { + switch (c) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + + case 'a': + case 'A': + return 10; + case 'b': + case 'B': + return 11; + case 'c': + case 'C': + return 12; + case 'd': + case 'D': + return 13; + case 'e': + case 'E': + return 14; + case 'f': + case 'F': + return 15; } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; + throw new java.io.IOException(); // Should never come here + } + + /** + * Position in buffer. + */ + public int bufpos = -1; + int bufsize; + int available; + int tokenBegin; + protected int bufline[]; + protected int bufcolumn[]; + + protected int column = 0; + protected int line = 1; + + protected boolean prevCharIsCR = false; + protected boolean prevCharIsLF = false; + + protected java.io.Reader inputStream; + + protected char[] nextCharBuf; + protected char[] buffer; + protected int maxNextCharInd = 0; + protected int nextCharInd = -1; + protected int inBuf = 0; + protected int tabSize = 8; + private boolean closed; + + protected void setTabSize(int i) { + tabSize = i; + } + + protected int getTabSize(int i) { + return tabSize; + } + + protected void ExpandBuff(boolean wrapAround) { + char[] newbuffer = new char[bufsize + 2048]; + int newbufline[] = new int[bufsize + 2048]; + int newbufcolumn[] = new int[bufsize + 2048]; + + try { + if (wrapAround) { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); + bufcolumn = newbufcolumn; + + bufpos += (bufsize - tokenBegin); + } else { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + buffer = newbuffer; - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + bufline = newbufline; - bufpos -= tokenBegin; + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + bufcolumn = newbufcolumn; + + bufpos -= tokenBegin; + } + } catch (Throwable t) { + throw new Error(t.getMessage()); } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - available = (bufsize += 2048); - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - int i; - if (maxNextCharInd == nextCharBuf.length) - maxNextCharInd = nextCharInd = 0; - - try { - // check for closed status to prevent the underlying Reader from - // throwing IOException that causes performance degradation - if (closed || (i = inputStream.read(nextCharBuf, maxNextCharInd, - nextCharBuf.length - maxNextCharInd)) == -1) - { - inputStream.close(); - closed = true; - throw END_OF_STREAM_EXCEPTION; + + available = (bufsize += 2048); + tokenBegin = 0; + } + + protected void FillBuff() throws java.io.IOException { + int i; + if (maxNextCharInd == nextCharBuf.length) + maxNextCharInd = nextCharInd = 0; + + try { + // check for closed status to prevent the underlying Reader from + // throwing IOException that causes performance degradation + if (closed || (i = inputStream.read(nextCharBuf, maxNextCharInd, + nextCharBuf.length - maxNextCharInd)) == -1) { + inputStream.close(); + closed = true; + throw END_OF_STREAM_EXCEPTION; + } else + maxNextCharInd += i; + return; + } catch (java.io.IOException e) { + if (bufpos != 0) { + --bufpos; + backup(0); + } else { + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + throw e; } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - if (bufpos != 0) - { - --bufpos; - backup(0); + } + + protected char ReadByte() throws java.io.IOException { + if (++nextCharInd >= maxNextCharInd) + FillBuff(); + + return nextCharBuf[nextCharInd]; + } + + /** + * @return starting character for token. + */ + public char BeginToken() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + tokenBegin = bufpos; + return buffer[bufpos]; } + + tokenBegin = 0; + bufpos = -1; + + return readChar(); + } + + protected void AdjustBuffSize() { + if (available == bufsize) { + if (tokenBegin > 2048) { + bufpos = 0; + available = tokenBegin; + } else + ExpandBuff(false); + } else if (available > tokenBegin) + available = bufsize; + else if ((tokenBegin - available) < 2048) + ExpandBuff(true); else - { - bufline[bufpos] = line; - bufcolumn[bufpos] = column; + available = tokenBegin; + } + + protected void UpdateLineColumn(char c) { + column++; + + if (prevCharIsLF) { + prevCharIsLF = false; + line += (column = 1); + } else if (prevCharIsCR) { + prevCharIsCR = false; + if (c == '\n') { + prevCharIsLF = true; + } else + line += (column = 1); } - throw e; - } - } - - protected char ReadByte() throws java.io.IOException - { - if (++nextCharInd >= maxNextCharInd) - FillBuff(); - - return nextCharBuf[nextCharInd]; - } - -/** @return starting character for token. */ - public char BeginToken() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - tokenBegin = bufpos; - return buffer[bufpos]; - } - - tokenBegin = 0; - bufpos = -1; - - return readChar(); - } - - protected void AdjustBuffSize() - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = 0; - available = tokenBegin; + + switch (c) { + case '\r': + prevCharIsCR = true; + break; + case '\n': + prevCharIsLF = true; + break; + case '\t': + column--; + column += (tabSize - (column % tabSize)); + break; + default: + break; } - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; + + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + + /** + * Read a character. + */ + public char readChar() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + return buffer[bufpos]; } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - -/** Read a character. */ - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - char c; - - if (++bufpos == available) - AdjustBuffSize(); - - if ((buffer[bufpos] = c = ReadByte()) == '\\') - { - UpdateLineColumn(c); - - int backSlashCnt = 1; - - for (;;) // Read all the backslashes - { - if (++bufpos == available) - AdjustBuffSize(); - - try - { - if ((buffer[bufpos] = c = ReadByte()) != '\\') - { - UpdateLineColumn(c); - // found a non-backslash char. - if ((c == 'u') && ((backSlashCnt & 1) == 1)) - { - if (--bufpos < 0) - bufpos = bufsize - 1; - - break; - } - - backup(backSlashCnt); - return '\\'; - } - } - catch(java.io.IOException e) - { - if (backSlashCnt > 1) - backup(backSlashCnt-1); - - return '\\'; - } - - UpdateLineColumn(c); - backSlashCnt++; + + char c; + + if (++bufpos == available) + AdjustBuffSize(); + + if ((buffer[bufpos] = c = ReadByte()) == '\\') { + UpdateLineColumn(c); + + int backSlashCnt = 1; + + for (; ; ) // Read all the backslashes + { + if (++bufpos == available) + AdjustBuffSize(); + + try { + if ((buffer[bufpos] = c = ReadByte()) != '\\') { + UpdateLineColumn(c); + // found a non-backslash char. + if ((c == 'u') && ((backSlashCnt & 1) == 1)) { + if (--bufpos < 0) + bufpos = bufsize - 1; + + break; + } + + backup(backSlashCnt); + return '\\'; + } + } catch (java.io.IOException e) { + // We are returning one backslash so we should only backup (count-1) + if (backSlashCnt > 1) + backup(backSlashCnt - 1); + + return '\\'; + } + + UpdateLineColumn(c); + backSlashCnt++; + } + + // Here, we have seen an odd number of backslash's followed by a 'u' + try { + while ((c = ReadByte()) == 'u') + ++column; + + buffer[bufpos] = c = (char) (hexval(c) << 12 | + hexval(ReadByte()) << 8 | + hexval(ReadByte()) << 4 | + hexval(ReadByte())); + + column += 4; + } catch (java.io.IOException e) { + throw new Error("Invalid escape character at line " + line + + " column " + column + "."); + } + + if (backSlashCnt == 1) + return c; + else { + backup(backSlashCnt - 1); + return '\\'; + } + } else { + UpdateLineColumn(c); + return c; } + } - // Here, we have seen an odd number of backslash's followed by a 'u' - try - { - while ((c = ReadByte()) == 'u') - ++column; + @Deprecated + /** + * @deprecated + * @see #getEndColumn + */ + public int getColumn() { + return bufcolumn[bufpos]; + } - buffer[bufpos] = c = (char)(hexval(c) << 12 | - hexval(ReadByte()) << 8 | - hexval(ReadByte()) << 4 | - hexval(ReadByte())); + @Deprecated + /** + * @deprecated + * @see #getEndLine + */ + public int getLine() { + return bufline[bufpos]; + } - column += 4; - } - catch(java.io.IOException e) - { - throw new Error("Invalid escape character at line " + line + - " column " + column + "."); + /** + * Get end column. + */ + public int getEndColumn() { + return bufcolumn[bufpos]; + } + + /** + * Get end line. + */ + public int getEndLine() { + return bufline[bufpos]; + } + + /** + * @return column of token start + */ + public int getBeginColumn() { + return bufcolumn[tokenBegin]; + } + + /** + * @return line number of token start + */ + public int getBeginLine() { + return bufline[tokenBegin]; + } + + /** + * Retreat. + */ + public void backup(int amount) { + + inBuf += amount; + if ((bufpos -= amount) < 0) + bufpos += bufsize; + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + nextCharBuf = new char[buffersize]; + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.Reader dstream) { + this(dstream, 1, 1, 4096); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.Reader dstream) { + ReInit(dstream, 1, 1, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) { + this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, startline, startcolumn, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream, int startline, + int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, 1, 1, 4096); + } + + /** + * Constructor. + */ + public JavaCharStream(java.io.InputStream dstream) { + this(dstream, 1, 1, 4096); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + if (buffer == null || buffersize != buffer.length) { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + nextCharBuf = new char[buffersize]; } + prevCharIsLF = prevCharIsCR = false; + tokenBegin = inBuf = maxNextCharInd = 0; + nextCharInd = bufpos = -1; + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } - if (backSlashCnt == 1) - return c; + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, startline, startcolumn, 4096); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, 1, 1, 4096); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream dstream) { + ReInit(dstream, 1, 1, 4096); + } + + /** + * @return token image as String + */ + public String GetImage() { + if (bufpos >= tokenBegin) + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); else - { - backup(backSlashCnt - 1); - return '\\'; + return new String(buffer, tokenBegin, bufsize - tokenBegin) + + new String(buffer, 0, bufpos + 1); + } + + /** + * @return suffix + */ + public char[] GetSuffix(int len) { + char[] ret = new char[len]; + + if ((bufpos + 1) >= len) + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + else { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, + len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } - } - else - { - UpdateLineColumn(c); - return c; - } - } - - /** - * @deprecated - * @see #getEndColumn - */ - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - public int getLine() { - return bufline[bufpos]; - } - -/** Get end column. */ - public int getEndColumn() { - return bufcolumn[bufpos]; - } - -/** Get end line. */ - public int getEndLine() { - return bufline[bufpos]; - } - -/** @return column of token start */ - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - -/** @return line number of token start */ - public int getBeginLine() { - return bufline[tokenBegin]; - } - -/** Retreat. */ - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - -/** Constructor. */ - public JavaCharStream(java.io.Reader dstream, - int startline, int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - nextCharBuf = new char[buffersize]; - } - -/** Constructor. */ - public JavaCharStream(java.io.Reader dstream, - int startline, int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException - { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, - int startcolumn) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, startline, startcolumn, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException - { - this(dstream, encoding, 1, 1, 4096); - } - -/** Constructor. */ - public JavaCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - - - - /** @return token image as String */ - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - /** @return suffix */ - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - /** Set buffers back to null when finished. */ - public void Done() - { - nextCharBuf = null; - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; + + return ret; + } + + /** + * Set buffers back to null when finished. + */ + public void Done() { + nextCharBuf = null; + buffer = null; + bufline = null; + bufcolumn = null; + } + + /** + * Method to adjust line and column numbers for the start of a token. + */ + public void adjustBeginLineColumn(int newLine, int newCol) { + int start = tokenBegin; + int len; + + if (bufpos >= tokenBegin) { + len = bufpos - tokenBegin + inBuf + 1; + } else { + len = bufsize - tokenBegin + bufpos + 1 + inBuf; } - } - line = bufline[j]; - column = bufcolumn[j]; - } + int i = 0, j = 0, k = 0; + int nextColDiff = 0, columnDiff = 0; + + while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { + bufline[j] = newLine; + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; + bufcolumn[j] = newCol + columnDiff; + columnDiff = nextColDiff; + i++; + } + + if (i < len) { + bufline[j] = newLine++; + bufcolumn[j] = newCol + columnDiff; + + while (i++ < len) { + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) + bufline[j] = newLine++; + else + bufline[j] = newLine; + } + } + + line = bufline[j]; + column = bufcolumn[j]; + } } -/* JavaCC - OriginalChecksum=de7dff2a3eda69c495bc3a754d6314ab (do not edit this line) */ +/* JavaCC - OriginalChecksum=42728d5d6de379c28d8e61854c22fc66 (do not edit this line) */ http://git-wip-us.apache.org/repos/asf/cayenne/blob/c44ccfde/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt index 370a223..16e443b 100644 --- a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt +++ b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt @@ -77,82 +77,91 @@ void notCondition() : {} void simpleCondition() : {} { - <TRUE> #True - | - <FALSE> #False - | - scalarConditionExpression() - ( - simpleNotCondition() - | - ("=" | "==") scalarExpression() #Equal(2) - | - ("!=" | "<>") scalarExpression() #NotEqual(2) + <TRUE> #True | - "<=" scalarExpression() #LessOrEqual(2) - | - "<" scalarExpression() #Less(2) - | - ">" scalarExpression() #Greater(2) - | - ">=" scalarExpression() #GreaterOrEqual(2) - | - "like" scalarExpression() #Like(2) + <FALSE> #False | - "likeIgnoreCase" scalarExpression() #LikeIgnoreCase(2) - | - "in" - ( namedParameter() | "(" scalarCommaList() ")" ) - #In(2) - | - "between" scalarExpression() "and" scalarExpression() #Between(3) + conditionExpression() + ( + ("=" | "==") scalarExpression() #Equal(2) + | + ("!=" | "<>") scalarExpression() #NotEqual(2) + | + "<=" scalarExpression() #LessOrEqual(2) + | + "<" scalarExpression() #Less(2) + | + ">" scalarExpression() #Greater(2) + | + ">=" scalarExpression() #GreaterOrEqual(2) + | + "like" scalarExpression() #Like(2) + | + "likeIgnoreCase" scalarExpression() #LikeIgnoreCase(2) + | + "in" ( namedParameter() | "(" scalarCommaList() ")" ) #In(2) + | + "between" scalarExpression() "and" scalarExpression() #Between(3) + | + simpleNotCondition() )? } void simpleNotCondition() : {} { ("not" | "!" ) - ( "like" scalarExpression() #NotLike(2) | "likeIgnoreCase" scalarExpression() #NotLikeIgnoreCase(2) - | - "in" - ( namedParameter() | "(" scalarCommaList() ")" ) - #NotIn(2) - | + | + "in" ( namedParameter() | "(" scalarCommaList() ")" ) #NotIn(2) + | "between" scalarExpression() "and" scalarExpression() #NotBetween(3) ) } void scalarCommaList() : {} { - ( - scalarConstExpression() - ( "," scalarConstExpression() )* - ) #List + ( scalarConstExpression() ( "," scalarConstExpression() )* ) #List } -void scalarConditionExpression() : {} +void conditionExpression() : {} { // TODO: once we switch expression package to use AST* from parser package, // we might need implement special subclasses for numeric and character constant // nodes for the purpose of expression evaluation, instead . For now keep them as // generic ASTScalar and purge from the parent node to keep compatible with QualifierTranslator. - - scalarNumericExpression() + + // Path without any operator will go to numeric expression. + // This done intentionally to remove lookahead that leads + // to dramatically perfomance degradation (parser can become 3 times slower) + numericExpression() + | + stringExpression() | - <SINGLE_QUOTED_STRING> { jjtThis.setValue(token_source.literalValue); } #Scalar(0) - | - <DOUBLE_QUOTED_STRING> { jjtThis.setValue(token_source.literalValue); } #Scalar(0) - | - <NULL> #Scalar(0) + <NULL> #Scalar(0) +} + +void stringParameter() : {} +{ + pathExpression() + | + stringExpression() +} + +void stringExpression() : {} +{ + <SINGLE_QUOTED_STRING> { jjtThis.setValue(token_source.literalValue); } #Scalar(0) + | + <DOUBLE_QUOTED_STRING> { jjtThis.setValue(token_source.literalValue); } #Scalar(0) + | + functionsReturningStrings() } void scalarExpression() : {} { - scalarConditionExpression() + conditionExpression() | <TRUE> { jjtThis.setValue(true); } #Scalar(0) | @@ -176,7 +185,7 @@ void scalarConstExpression() : {} <FALSE> { jjtThis.setValue(false); } #Scalar(0) } -void scalarNumericExpression() : {} +void numericExpression() : {} { bitwiseOr() } @@ -259,40 +268,75 @@ void numericPrimary() : {} "(" orCondition() ")" | - pathExpression() - | - namedParameter() - | <INT_LITERAL> { jjtThis.setValue(token_source.literalValue); } #Scalar(0) | <FLOAT_LITERAL>{ jjtThis.setValue(token_source.literalValue); } #Scalar(0) + | + namedParameter() + | + functionsReturningNumerics() + | + pathExpression() } -void namedParameter() : +void functionsReturningStrings() : { } { - Token t; + concat() | substring() | trim() | lower() | upper() } + +void concat() #Concat : { } { - "$" t = <PROPERTY_PATH> { jjtThis.setValue(t.image); } #NamedParameter(0) + <CONCAT> "(" stringParameter() "," stringParameter() ")" +} + +void substring() #Substring : { } +{ + <SUBSTRING> "(" stringParameter() "," numericExpression() ["," numericExpression()] ")" } +void trim() #Trim : { } +{ + <TRIM> "(" stringParameter() ")" +} -void pathExpression() : { - Token t; +void lower() #Lower : { } +{ + <LOWER> "(" stringParameter() ")" } + +void upper() #Upper : { } { - ( - t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0) - | - "obj:" - t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0) - | - "db:" - t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #DbPath(0) - | - "enum:" - t = <PROPERTY_PATH> { jjtThis.setValue(ParserUtil.makeEnum(t.image)); } #Scalar(0) - ) + <UPPER> "(" stringParameter() ")" +} + +void functionsReturningNumerics() : { } +{ + length() | locate() | abs() | sqrt() | mod() +} + +void length() #Length : { } +{ + <LENGTH> "(" stringParameter() ")" +} + +void locate() #Locate : { } +{ + <LOCATE> "(" stringParameter() "," stringParameter() ["," numericExpression()] ")" +} + +void abs() #Abs : { } +{ + <ABS> "(" numericExpression() ")" +} + +void sqrt() #Sqrt : { } +{ + <SQRT> "(" numericExpression() ")" +} + +void mod() #Mod : { } +{ + <MOD> "(" numericExpression() "," numericExpression() ")" } @@ -381,10 +425,65 @@ SKIP : TOKEN : { <NULL: "null" | "NULL" > -| - <TRUE: "true" | "TRUE" > -| - <FALSE: "false" | "FALSE" > + | <TRUE: "true" | "TRUE" > + | <FALSE: "false" | "FALSE" > +} + +TOKEN [ IGNORE_CASE ]: /* aggregates */ +{ + <AVG: "AVG" > + | <MIN: "MIN" > + | <MAX: "MAX" > + | <SUM: "SUM" > + | <COUNT: "COUNT" > +} + +TOKEN [ IGNORE_CASE ]: /* functions returning strings */ +{ + <CONCAT: "CONCAT" > + | <SUBSTRING: "SUBSTRING" > + | <TRIM: "TRIM" > + | <LOWER: "LOWER" > + | <UPPER: "UPPER" > +} + +TOKEN [ IGNORE_CASE ]: /* functions returning numerics */ +{ + <LENGTH: "LENGTH" > + | <LOCATE: "LOCATE" > + | <ABS: "ABS" > + | <SQRT: "SQRT" > + | <MOD: "MOD" > +} + +TOKEN [ IGNORE_CASE ]: /* functions returning datetime */ +{ + <CURRENT_DATE: "CURRENT_DATE" > + | <CURRENT_TIME: "CURRENT_TIME" > + | <CURRENT_TIMESTAMP: "CURRENT_TIMESTAMP" > +} + +void namedParameter() : +{ + Token t; +} +{ + "$" t = <PROPERTY_PATH> { jjtThis.setValue(t.image); } #NamedParameter(0) +} + +void pathExpression() : { + Token t; +} +{ + ( + t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0) + | + "obj:" t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #ObjPath(0) + | + "db:" t = <PROPERTY_PATH> { jjtThis.setPath(t.image); } #DbPath(0) + | + "enum:" t = <PROPERTY_PATH> { jjtThis.setValue(ParserUtil.makeEnum(t.image)); } #Scalar(0) + ) } TOKEN : { @@ -400,8 +499,7 @@ TOKEN : < #DIGIT: ["0"-"9"] > } - -/** +/** * Quoted Strings, whose object value is stored in the token manager's * "literalValue" field. Both single and double qoutes are allowed */ http://git-wip-us.apache.org/repos/asf/cayenne/blob/c44ccfde/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java index 3cf4a46..9fc6ac2 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryTest.java @@ -33,6 +33,7 @@ import java.util.Map; import org.apache.cayenne.exp.parser.ASTLike; import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase; +import org.apache.cayenne.exp.parser.ASTTrim; import org.junit.Before; import org.junit.Test; @@ -471,4 +472,16 @@ public class ExpressionFactoryTest { public void testDbPathExp() { assertEquals("db:abc.xyz", ExpressionFactory.dbPathExp("abc.xyz").toString()); } + + @Test + public void testFuncExp() { + Expression e = ExpressionFactory.exp("TRIM(abc.xyz)"); + assertEquals(ASTTrim.class, e.getClass()); + } + + // CAY-2081 + @Test(expected = ExpressionException.class) + public void testExceptionInParse() { + ExpressionFactory.exp("name like %32_65415'"); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/c44ccfde/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallMathIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallMathIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallMathIT.java index 192a1ad..9033ab9 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallMathIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallMathIT.java @@ -19,8 +19,12 @@ package org.apache.cayenne.exp.parser; +import java.math.BigDecimal; + import org.apache.cayenne.ObjectContext; import org.apache.cayenne.di.Inject; +import org.apache.cayenne.exp.Expression; +import org.apache.cayenne.exp.ExpressionFactory; import org.apache.cayenne.exp.Property; import org.apache.cayenne.query.ObjectSelect; import org.apache.cayenne.testdo.table_primitives.TablePrimitives; @@ -80,4 +84,27 @@ public class ASTFunctionCallMathIT extends ServerCase { assertEquals(p1, p2); } + @Test + public void testASTAbsParse() { + Expression exp = ExpressionFactory.exp("ABS(-3)"); + assertEquals(3.0, exp.evaluate(new Object())); + } + + @Test + public void testASTSqrtParse() { + Expression exp = ExpressionFactory.exp("SQRT(16)"); + assertEquals(4.0, exp.evaluate(new Object())); + } + + @Test + public void testASTModParse() { + Expression exp = ExpressionFactory.exp("MOD(11,2)"); + assertEquals(1.0, exp.evaluate(new Object())); + } + + @Test + public void testComplexParse() { + Expression exp = ExpressionFactory.exp("10 - MOD(SQRT(ABS(-9)), 2)"); + assertEquals(BigDecimal.valueOf(9L), exp.evaluate(new Object())); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/c44ccfde/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java index cbb7514..58a69dd 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTFunctionCallStringIT.java @@ -23,6 +23,8 @@ import java.util.Date; import org.apache.cayenne.ObjectContext; import org.apache.cayenne.di.Inject; +import org.apache.cayenne.exp.Expression; +import org.apache.cayenne.exp.ExpressionFactory; import org.apache.cayenne.exp.Property; import org.apache.cayenne.query.ObjectSelect; import org.apache.cayenne.testdo.testmap.Artist; @@ -152,4 +154,45 @@ public class ASTFunctionCallStringIT extends ServerCase { assertEquals(a1, a2); } + @Test + public void testASTConcatParse() { + Expression exp = ExpressionFactory.exp("CONCAT('abc', 'def')"); + assertEquals("abcdef", exp.evaluate(new Object())); + } + + @Test + public void testASTSubstringParse() { + Expression exp = ExpressionFactory.exp("SUBSTRING('123456789', 3, 2)"); + assertEquals("45", exp.evaluate(new Object())); + } + + @Test + public void testASTTrimParse() { + Expression exp = ExpressionFactory.exp("TRIM(' abc ')"); + assertEquals("abc", exp.evaluate(new Object())); + } + + @Test + public void testASTLowerParse() { + Expression exp = ExpressionFactory.exp("LOWER('AbC')"); + assertEquals("abc", exp.evaluate(new Object())); + } + + @Test + public void testASTUpperParse() { + Expression exp = ExpressionFactory.exp("UPPER('aBc')"); + assertEquals("ABC", exp.evaluate(new Object())); + } + + @Test + public void testASTLocateParse() { + Expression exp = ExpressionFactory.exp("LOCATE('Bc', 'aBc')"); + assertEquals(2, exp.evaluate(new Object())); + } + + @Test + public void testComplexParse() { + Expression exp = ExpressionFactory.exp("LOCATE(UPPER('Bc'), UPPER('aBc')) = LENGTH(SUBSTRING(TRIM(LOWER(CONCAT(' abc', 'def '))), 3, 2))"); + assertEquals(true, exp.evaluate(new Object())); + } }
