package ch.akuhn.hapax.util;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import ch.akuhn.util.Throw;
public abstract class CharStream implements Closeable {
// TODO replace all assertions with real exception
public static final CharStream fromString(String string) {
return new StringCharStream(string);
}
public static final CharStream fromFile(File file) {
try {
return new InputStreamCharStream(new FileInputStream(file));
} catch (FileNotFoundException ex) {
throw Throw.exception(ex);
}
}
public static final char EOF = (char) -1;
protected StringBuffer buf = null;
public char curr;
public abstract char basicNext();
public abstract char basicBacktrack();
static class StringCharStream extends CharStream {
private final String string;
private int pos = 0;
public StringCharStream(String string) {
this.string = string;
}
@Override
public char basicBacktrack() {
assert pos > 0;
return string.charAt(--pos-1);
}
@Override
public char basicNext() {
if (pos >= string.length()) throw new BufferUnderflowException();
return string.charAt(pos++);
}
public void close() throws IOException {
// do nothing
}
}
static class InputStreamCharStream extends CharStream {
private InputStream input;
private char prev, next = EOF;
private boolean backtracked = false;
public InputStreamCharStream(InputStream input) {
this.input = input;
}
@Override
public char basicBacktrack() {
assert backtracked == false;
backtracked = true;
return prev;
}
@Override
public char basicNext() {
if (backtracked) {
backtracked = false;
return next;
}
try {
prev = next;
next = (char) input.read();
if (next == EOF) throw new BufferUnderflowException();
return next;
} catch (IOException ex) {
throw Throw.exception(ex);
}
}
public void close() throws IOException {
input.close();
}
}
public boolean hasMark() {
return buf != null;
}
public void mark() {
assert buf == null;
buf = new StringBuffer();
}
public String yank() {
String result = buf.toString();
buf = null;
return result;
}
public void backtrack() {
curr = this.basicBacktrack();
if (buf != null && buf.length() > 0) {
buf.setLength(buf.length() - 1);
}
}
public char next() {
if (buf != null) buf.append(curr);
return curr = basicNext();
}
public static CharStream fromInputStream(InputStream stream) {
return new InputStreamCharStream(stream);
}
}