/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.parser.jython; import java.io.IOException; import org.python.pydev.core.ObjectsInternPool.ObjectsPoolMap; import org.python.pydev.core.log.Log; import org.python.pydev.shared_core.string.FastStringBuffer; /** * An implementation of interface CharStream, where the data is read from a Reader. Completely recreated so that we can read data directly from a String, as the * initial implementation was highly inefficient when working only with a string (actually, if it was small, there would be no noticeable * delays, but if it became big, then the improvement would be HUGE). * * It keeps the same semantics for line and column stuff (and shares the previous approach of keeping a buffer for this info). * If we wanted we could optimize it for also taking less memory, but as there is usually not so many concurrent parses, this * is probably not worth it -- and it would probably be a little slower) */ public final class FastCharStream { public final char[] buffer; public final int bufline[]; public final int bufcolumn[]; private boolean prevCharIsCR = false; private boolean prevCharIsLF = false; private int column = 0; private int line = 1; public int bufpos = -1; private int updatePos; public int tokenBegin; private static IOException ioException; private static final boolean DEBUG = false; public FastCharStream(char cs[]) { this.buffer = cs; this.bufline = new int[cs.length]; this.bufcolumn = new int[cs.length]; } public int getCurrentPos() { return bufpos; } public void restorePos(int pos) { bufpos = pos; } /** * Restores a previous position. * Don't forget to restore the level if eof was already found! */ public void restoreLineColPos(final int endLine, final int endColumn) { final int initialBufPos = bufpos; final int currLine = getEndLine(); if (currLine < endLine) { //note: we could do it, but it's not what we want! Log.log("Cannot backtrack to a later position -- current line: " + getEndLine() + " requested line:" + endLine); return; } else if (currLine == endLine && getEndColumn() < endColumn) { Log.log("Cannot backtrack to a later position -- current col: " + getEndColumn() + " requested col:" + endColumn); return; } while ((getEndLine() != endLine || getEndColumn() != endColumn) && bufpos >= 0) { bufpos--; } if (bufpos < 0 || getEndLine() != endLine) { //we couldn't find it. Let's restore the position when we started it. bufpos = initialBufPos; Log.log("Couldn't backtrack to position: line" + endLine + " -- col:" + endColumn); } } public final char readChar() throws IOException { try { bufpos++; char r = this.buffer[bufpos]; if (bufpos >= updatePos) { updatePos++; //start UpdateLineCol column++; if (prevCharIsLF) { prevCharIsLF = false; line += (column = 1); } else if (prevCharIsCR) { prevCharIsCR = false; if (r == '\n') { prevCharIsLF = true; } else { line += (column = 1); } } if (r == '\r') { prevCharIsCR = true; } else if (r == '\n') { prevCharIsLF = true; } bufline[bufpos] = line; bufcolumn[bufpos] = column; //end UpdateLineCol } return r; } catch (ArrayIndexOutOfBoundsException e) { bufpos--; if (ioException == null) { ioException = new IOException(); } throw ioException; } } public final int getEndColumn() { return bufcolumn[bufpos]; } public final int getEndLine() { return bufline[bufpos]; } public final int getBeginColumn() { return bufcolumn[tokenBegin]; } public final int getBeginLine() { return bufline[tokenBegin]; } public final void backup(int amount) { if (DEBUG) { System.out.println("FastCharStream: backup >>" + amount + "<<"); } bufpos -= amount; } public final char BeginToken() throws IOException { char c = readChar(); tokenBegin = bufpos; if (DEBUG) { System.out.println("FastCharStream: BeginToken >>" + (int) c + "<<"); } return c; } private final ObjectsPoolMap interned = new ObjectsPoolMap(); public final String GetImage() { String string; if (bufpos >= tokenBegin) { string = new String(buffer, tokenBegin, bufpos - tokenBegin + 1); } else { string = new String(buffer, tokenBegin, buffer.length - tokenBegin + 1); } String existing = interned.get(string); if (existing != null) { return existing; } interned.put(string, string); return string; } public final void AppendSuffix(FastStringBuffer buf, int len) { if (len > 0) { try { int initial = bufpos - len + 1; if (initial < 0) { int initial0 = initial; len += initial; initial = 0; buf.appendN('\u0000', -initial0); buf.append(buffer, initial, len); } else { buf.append(buffer, initial, len); } } catch (Exception e) { Log.log(e); } } } public static boolean ACCEPT_GET_SUFFIX = false; public final char[] GetSuffix(int len) { if (!ACCEPT_GET_SUFFIX) { throw new RuntimeException("This method should not be used (AppendSuffix should be used instead)."); } char[] ret = new char[len]; if (len > 0) { try { int initial = bufpos - len + 1; if (initial < 0) { int initial0 = initial; len += initial; initial = 0; System.arraycopy(buffer, initial, ret, -initial0, len); } else { System.arraycopy(buffer, initial, ret, 0, len); } } catch (Exception e) { Log.log(e); } } if (DEBUG) { System.out.println("FastCharStream: GetSuffix:" + len + " >>" + new String(ret) + "<<"); } return ret; } public void setBeginEndCharsEqual(Token t) { t.beginLine = t.endLine = bufline[tokenBegin]; t.beginColumn = t.endColumn = bufcolumn[tokenBegin]; } public void setBeginEndChars(Token t) { t.beginLine = bufline[tokenBegin]; t.beginColumn = bufcolumn[tokenBegin]; t.endLine = bufline[bufpos]; t.endColumn = bufcolumn[bufpos]; } }