/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.antlr.works.editor.antlr4.classification; import org.antlr.netbeans.editor.text.DocumentSnapshot; import org.antlr.netbeans.editor.text.DocumentSnapshotLine; import org.antlr.netbeans.editor.text.OffsetRegion; import org.antlr.netbeans.editor.text.SnapshotPositionRegion; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.misc.Interval; import org.openide.util.Parameters; /** * * @author Sam Harwell */ public class DocumentSnapshotCharStream implements CharStream { // input info private final DocumentSnapshot snapshot; private final int count; private String sourceName = "Snapshot"; // position info private int index; private int line; private int charPositionInLine; // cache info private boolean explicitCache; private int currentSnapshotLineStartIndex; private String currentSnapshotLine; public DocumentSnapshotCharStream(DocumentSnapshot snapshot) { Parameters.notNull("snapshot", snapshot); this.snapshot = snapshot; this.count = snapshot.length(); updateCachedLine(); } public DocumentSnapshotCharStream(DocumentSnapshot snapshot, OffsetRegion cachedSpan) { this(new SnapshotPositionRegion(snapshot, cachedSpan)); } public DocumentSnapshotCharStream(SnapshotPositionRegion cachedSpan) { this.snapshot = cachedSpan.getSnapshot(); this.count = getSnapshot().length(); this.explicitCache = true; this.currentSnapshotLineStartIndex = cachedSpan.getStart().getOffset(); this.currentSnapshotLine = cachedSpan.getText(); } public final DocumentSnapshot getSnapshot() { return snapshot; } public int getLine() { return line; } public void setLine(int line) { this.line = line; } public int getCharPositionInLine() { return charPositionInLine; } public void setCharPositionInLine(int charPositionInLine) { this.charPositionInLine = charPositionInLine; } @Override public final int size() { return count; } @Override public final int index() { return index; } private void setIndex(int index) { this.index = index; } @Override public String getSourceName() { return sourceName; } public void setSourceName(String sourceName) { Parameters.notNull("sourceName", sourceName); this.sourceName = sourceName; } public int LT(int i) { return LA(i); } @Override public String getText(Interval interval) { int start = interval.a; int stop = interval.b; if (currentSnapshotLine != null) { if (start >= currentSnapshotLineStartIndex && stop < currentSnapshotLineStartIndex + currentSnapshotLine.length()) { return currentSnapshotLine.substring(start - currentSnapshotLineStartIndex, stop + 1 - currentSnapshotLineStartIndex); } } // HACK: special handling due to Lexer passing invalid indexes. if (stop >= size()) { stop = size() - 1; } return getSnapshot().subSequence(start, stop + 1).toString(); } @Override public void consume() { int la = LA(1); if (la < 0) { return; } if (la == '\n') { setLine(getLine() + 1); setCharPositionInLine(0); } else { setCharPositionInLine(getCharPositionInLine() + 1); } setIndex(index() + 1); updateCachedLine(); } @Override public int LA(int i) { if (i == 0) { // undefined return 0; } int currentIndex = index(); int size = size(); if (i < 0) { // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] i++; if ((currentIndex + i - 1) < 0) { // invalid; no char before first char return CharStream.EOF; } } if ((currentIndex + i - 1) >= size) { return CharStream.EOF; } int actualIndex = currentIndex + i - 1; String currentLine = currentSnapshotLine; int currentLineStartIndex = currentSnapshotLineStartIndex; if (currentLine != null && actualIndex >= currentLineStartIndex && actualIndex < currentLineStartIndex + currentLine.length()) { return currentLine.charAt(actualIndex - currentLineStartIndex); } return getSnapshot().charAt(actualIndex); } @Override public int mark() { return 0; } @Override public void release(int marker) { } @Override public void seek(int index) { if (index <= index() && (index() - index) < getCharPositionInLine()) { // moved to a previous location on the same line setCharPositionInLine(getCharPositionInLine() - (index() - index)); setIndex(index); return; } setIndex(index); DocumentSnapshotLine currentLine = getSnapshot().findLineFromOffset(index()); setLine(currentLine.getLineNumber()); setCharPositionInLine(index() - currentLine.getStart().getOffset()); updateCachedLine(); } private void updateCachedLine() { if (explicitCache) { return; } if (currentSnapshotLine == null || index() < currentSnapshotLineStartIndex || index() >= currentSnapshotLineStartIndex + currentSnapshotLine.length()) { if (index() >= 0 && index() < size()) { DocumentSnapshotLine currentLine = getSnapshot().findLineFromOffset(index()); currentSnapshotLineStartIndex = currentLine.getStart().getOffset(); currentSnapshotLine = currentLine.getTextIncludingLineBreak(); } else { currentSnapshotLine = null; currentSnapshotLineStartIndex = 0; } } } }