/* * Created on Jun 12, 2007 Copyright (C) 2001-5, Anthony Harrison anh23@pitt.edu * (jactr.org) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. This library is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. You should have * received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.eclipse.ui.reconciler; import java.util.ArrayList; import java.util.List; import org.antlr.runtime.CharStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.jactr.io.parser.CanceledException; /** * Based on ANTLRStringStream * * @author developer */ public class ANTLRDocumentStream implements CharStream { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ANTLRDocumentStream.class); protected IDocument _document; /** 0..n-1 index into string of next char */ protected int _currentIndex = 0; protected int _currentLine = 1; protected int _positionInLine = 0; protected int _markerDepth = 0; protected List<StreamState> _markers; protected int _lastMarker; protected IProgressMonitor _monitor; private String _name; public ANTLRDocumentStream(IDocument document, String name) { this(document, name, new NullProgressMonitor()); } public ANTLRDocumentStream(IDocument document, String name, IProgressMonitor monitor) { _name = name; _document = document; setProgressMonitor(monitor); reset(); } public void setProgressMonitor(IProgressMonitor monitor) { _monitor = monitor; } /** * Reset the stream so that it's in the same state it was when the object was * created *except* the data array is not touched. */ public void reset() { _currentIndex = 0; _currentLine = 1; _positionInLine = 0; _markerDepth = 0; _markers = null; } public void consume() { if (_monitor.isCanceled()) throw new CanceledException(); if (_currentIndex < size()) { _positionInLine++; char c = 0; try { c = _document.getChar(_currentIndex); } catch (BadLocationException e) { throw new IllegalStateException( "Could not get next character in document next:" + _currentIndex + " size:" + size(), e); } if (c == '\n') { _currentLine++; _positionInLine = 0; } _currentIndex++; } } public int LA(int i) { if (_monitor.isCanceled()) throw new CanceledException(); if (i == 0) return 0; // undefined if (i < 0) { i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] if (_currentIndex + i - 1 < 0) return CharStream.EOF; // invalid; no char before first char } if (_currentIndex + i - 1 >= size()) return CharStream.EOF; // System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p); // System.out.println("LA("+i+"); p="+p+" n="+n+" // data.length="+data.length); try { return _document.getChar(_currentIndex + i - 1); } catch (BadLocationException e) { throw new IllegalStateException("Could not get character index:" + (_currentIndex + i - 1) + " size:" + size(), e); } } public int LT(int i) { return LA(i); } /** * Return the current input symbol index 0..n where n indicates the last * symbol has been read. The index is the index of char to be returned from * LA(1). */ public int index() { return _currentIndex; } public int size() { return _document.getLength(); } public int mark() { if (_markers == null) { _markers = new ArrayList<StreamState>(); _markers.add(null); // depth 0 means no backtracking, leave blank } _markerDepth++; StreamState state = null; if (_markerDepth >= _markers.size()) { state = new StreamState(); _markers.add(state); } else state = _markers.get(_markerDepth); state._p = _currentIndex; state._line = _currentLine; state._charPositionInLine = _positionInLine; _lastMarker = _markerDepth; return _markerDepth; } public void rewind(int m) { StreamState state = _markers.get(m); // restore stream state seek(state._p); _currentLine = state._line; _positionInLine = state._charPositionInLine; release(m); } public void rewind() { rewind(_lastMarker); } public void release(int marker) { // unwind any other markers made after m and release m _markerDepth = marker; // release this marker _markerDepth--; } /** * consume() ahead until p==index; can't just set p=index as we must update * line and charPositionInLine. */ public void seek(int index) { if (index <= _currentIndex) { _currentIndex = index; // just jump; don't update stream state (line, // ...) return; } // seek forward, consume until p hits index while (_currentIndex < index) consume(); } public String substring(int start, int stop) { try { String rtn = _document.get(start, stop - start + 1); if (LOGGER.isDebugEnabled()) LOGGER.debug("Returning " + rtn); return rtn; } catch (BadLocationException e) { throw new IllegalStateException("Could not get substring(" + start + "," + stop + "):" + size(), e); } } public int getLine() { return _currentLine; } public int getCharPositionInLine() { return _positionInLine; } public void setLine(int line) { this._currentLine = line; } public void setCharPositionInLine(int pos) { this._positionInLine = pos; } private class StreamState { /** Index into the char stream of next lookahead char */ int _p; /** What line number is the scanner at before processing buffer[p]? */ int _line; /** What char position 0..n-1 in line is scanner before processing buffer[p]? */ int _charPositionInLine; } public String getSourceName() { return _name; } }