forked from jasder/antlr
oops; don't need these afterall
This commit is contained in:
parent
3900606024
commit
44355d6ff6
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
[The "BSD license"]
|
|
||||||
Copyright (c) 2011 Terence Parr
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.antlr.v4.runtime;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.misc.Interval;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
|
|
||||||
/** Buffer up all char from stream, but pull chars from input on-demand,
|
|
||||||
* in a lazy fashion. This allows us build interactive programs using
|
|
||||||
* ANTLR like shells and REPLs. This is a kind of ANTLRInputStream
|
|
||||||
* that does not load() everything up front.
|
|
||||||
*/
|
|
||||||
public class LazyCharStream implements CharStream {
|
|
||||||
/** A buffer of the data being scanned */
|
|
||||||
protected char[] data;
|
|
||||||
|
|
||||||
/** This is where we will read next char. It's also how many characters
|
|
||||||
* we've actually read into the buffer. It's less than or equal
|
|
||||||
* to data.length.
|
|
||||||
*/
|
|
||||||
protected int next;
|
|
||||||
|
|
||||||
/** 0..n-1 index into string of next lookahead char. LA(1) is data[p] */
|
|
||||||
protected int p=0;
|
|
||||||
|
|
||||||
protected Reader input;
|
|
||||||
|
|
||||||
/** What is name or source of this char stream? */
|
|
||||||
public String name;
|
|
||||||
|
|
||||||
public LazyCharStream(InputStream input) {
|
|
||||||
this(input, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyCharStream(Reader input) {
|
|
||||||
this(input, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyCharStream(InputStream input, int initialSize) {
|
|
||||||
this.input = new InputStreamReader(input);
|
|
||||||
data = new char[initialSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyCharStream(Reader input, int initialSize) {
|
|
||||||
this.input = input;
|
|
||||||
data = new char[initialSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
p = 0;
|
|
||||||
next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void consume() {
|
|
||||||
sync(1); // make sure we have read current char
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int LA(int i) {
|
|
||||||
sync(i);
|
|
||||||
int index = p + i - 1;
|
|
||||||
if ( index < 0 ) throw new IndexOutOfBoundsException();
|
|
||||||
if ( index > next) return CharStream.EOF;
|
|
||||||
int c = data[index];
|
|
||||||
if ( c==(char)CharStream.EOF ) return CharStream.EOF;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return a marker that we can release later. Marker happens to be
|
|
||||||
* index into buffer (not index()).
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int mark() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release(int marker) { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int index() {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seek(int index) {
|
|
||||||
if ( index<=p ) {
|
|
||||||
p = index; // just jump; don't update stream state (line, ...)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// seek forward, consume until p hits index
|
|
||||||
while ( p<index && index< next) {
|
|
||||||
consume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return num char we've read so far */
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSourceName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getText(Interval interval) {
|
|
||||||
int start = interval.a;
|
|
||||||
int stop = interval.b;
|
|
||||||
if ( stop < start ) {
|
|
||||||
throw new IllegalArgumentException("inverted interval");
|
|
||||||
}
|
|
||||||
if ( stop >= next) {
|
|
||||||
int need = stop - next + 1;
|
|
||||||
fill(need);
|
|
||||||
}
|
|
||||||
int count = stop - start + 1;
|
|
||||||
return new String(data, start, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Make sure we have 'want' elements from current position p. Last valid
|
|
||||||
* p index is data.size()-1. p+want-1 is the data index 'want' elements
|
|
||||||
* ahead. If we want 1 element, (p+1-1)==p must be < n.
|
|
||||||
*/
|
|
||||||
protected void sync(int want) {
|
|
||||||
// E.g., sync(1) means current p must have a char. If p>=next, we
|
|
||||||
// need a char
|
|
||||||
int need = (p+want-1) - next + 1; // how many more elements we need?
|
|
||||||
if ( need > 0 ) fill(need); // out of elements?
|
|
||||||
}
|
|
||||||
|
|
||||||
/** add n elements to buffer */
|
|
||||||
public void fill(int n) {
|
|
||||||
for (int i=1; i<=n; i++) {
|
|
||||||
try {
|
|
||||||
int c = input.read();
|
|
||||||
add(c);
|
|
||||||
if ( c==EOF ) break;
|
|
||||||
}
|
|
||||||
catch (IOException ioe) {
|
|
||||||
throw new RuntimeException(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void add(int c) {
|
|
||||||
if ( next >=data.length ) {
|
|
||||||
char[] newdata = new char[data.length*2]; // resize
|
|
||||||
System.arraycopy(data, 0, newdata, 0, data.length);
|
|
||||||
data = newdata;
|
|
||||||
}
|
|
||||||
data[next++] = (char)c;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
package org.antlr.v4.test;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.LazyCharStream;
|
|
||||||
import org.antlr.v4.runtime.misc.Interval;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.StringReader;
|
|
||||||
|
|
||||||
public class TestLazyCharStream extends BaseTest {
|
|
||||||
@Test public void testNoChar() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("")
|
|
||||||
);
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void test1Char() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("x")
|
|
||||||
);
|
|
||||||
assertEquals('x', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void test2Char() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("xy")
|
|
||||||
);
|
|
||||||
assertEquals('x', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('y', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void test2CharAhead() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("xy")
|
|
||||||
);
|
|
||||||
assertEquals('x', input.LA(1));
|
|
||||||
assertEquals('y', input.LA(2));
|
|
||||||
assertEquals(CharStream.EOF, input.LA(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testBufferExpand() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("01234"),
|
|
||||||
2 // buff size 2
|
|
||||||
);
|
|
||||||
assertEquals('0', input.LA(1));
|
|
||||||
assertEquals('1', input.LA(2));
|
|
||||||
assertEquals('2', input.LA(3));
|
|
||||||
assertEquals('3', input.LA(4));
|
|
||||||
assertEquals('4', input.LA(5));
|
|
||||||
assertEquals(CharStream.EOF, input.LA(6));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testBufferWrapSize1() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("01234"),
|
|
||||||
1 // buff size 1
|
|
||||||
);
|
|
||||||
assertEquals('0', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('1', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('2', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('3', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('4', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testBufferWrapSize2() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("01234"),
|
|
||||||
2 // buff size 2
|
|
||||||
);
|
|
||||||
assertEquals('0', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('1', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('2', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('3', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals('4', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void test1Mark() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("xyz")
|
|
||||||
);
|
|
||||||
int m = input.mark();
|
|
||||||
assertEquals('x', input.LA(1));
|
|
||||||
assertEquals('y', input.LA(2));
|
|
||||||
assertEquals('z', input.LA(3));
|
|
||||||
input.release(m);
|
|
||||||
assertEquals(CharStream.EOF, input.LA(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void test2Mark() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("xyz"),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
assertEquals('x', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
int m1 = input.mark();
|
|
||||||
assertEquals('y', input.LA(1));
|
|
||||||
input.consume();
|
|
||||||
int m2 = input.mark();
|
|
||||||
assertEquals('z', input.LA(1));
|
|
||||||
input.release(m2); // noop since not earliest in buf
|
|
||||||
input.consume();
|
|
||||||
input.release(m1);
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testLazy1CharAtTime() throws Exception {
|
|
||||||
CharStream input = new LazyCharStream(
|
|
||||||
new StringReader("x")
|
|
||||||
);
|
|
||||||
assertEquals(0, input.size());
|
|
||||||
assertEquals("x", input.getText(Interval.of(0,0)));
|
|
||||||
assertEquals(1, input.size());
|
|
||||||
input.consume(); // x already loaded so size is still 1 after this
|
|
||||||
input.consume(); // now we have x EOF
|
|
||||||
assertEquals(2, input.size());
|
|
||||||
assertEquals(CharStream.EOF, input.LA(1));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue