Convert streams to kotlin
This commit is contained in:
parent
c5fbab6813
commit
0f34d25e12
|
@ -1,78 +0,0 @@
|
||||||
package scanner;
|
|
||||||
|
|
||||||
import stream.SafeInputStream;
|
|
||||||
import util.Characters;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes Lisp comments from an input stream.
|
|
||||||
*/
|
|
||||||
public class LispCommentRemovingInputStream implements LispInputStream {
|
|
||||||
|
|
||||||
private SafeInputStream underlyingInputStream;
|
|
||||||
private boolean isInQuotedString;
|
|
||||||
private boolean rereadLastCharacter;
|
|
||||||
private int previousCharacter;
|
|
||||||
private int currentCharacter;
|
|
||||||
|
|
||||||
public LispCommentRemovingInputStream(InputStream underlyingInputStream) {
|
|
||||||
this.underlyingInputStream = new SafeInputStream(underlyingInputStream);
|
|
||||||
this.isInQuotedString = false;
|
|
||||||
this.rereadLastCharacter = false;
|
|
||||||
this.previousCharacter = 0;
|
|
||||||
this.currentCharacter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() {
|
|
||||||
if (!rereadLastCharacter)
|
|
||||||
return readFromUnderlyingInputStream();
|
|
||||||
|
|
||||||
rereadLastCharacter = false;
|
|
||||||
|
|
||||||
return currentCharacter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readFromUnderlyingInputStream() {
|
|
||||||
readNextCharacter();
|
|
||||||
|
|
||||||
if (haveEnteredComment())
|
|
||||||
consumeAllBytesInComment();
|
|
||||||
|
|
||||||
return currentCharacter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readNextCharacter() {
|
|
||||||
previousCharacter = currentCharacter;
|
|
||||||
currentCharacter = underlyingInputStream.read();
|
|
||||||
|
|
||||||
if (haveEncounteredStringBoundary())
|
|
||||||
isInQuotedString = !isInQuotedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean haveEncounteredStringBoundary() {
|
|
||||||
return (previousCharacter != Characters.BACKSLASH) && (currentCharacter == Characters.DOUBLE_QUOTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean haveEnteredComment() {
|
|
||||||
return (currentCharacter == Characters.SEMICOLON) && (!isInQuotedString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void consumeAllBytesInComment() {
|
|
||||||
while (stillInComment())
|
|
||||||
currentCharacter = underlyingInputStream.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean stillInComment() {
|
|
||||||
return (currentCharacter != Characters.NEWLINE) && (currentCharacter != Characters.EOF);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unreadLastCharacter() {
|
|
||||||
if (rereadLastCharacter)
|
|
||||||
throw new MaximumUnreadsExceededException();
|
|
||||||
|
|
||||||
this.rereadLastCharacter = true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import stream.SafeInputStream
|
||||||
|
import util.Characters.BACKSLASH
|
||||||
|
import util.Characters.DOUBLE_QUOTE
|
||||||
|
import util.Characters.EOF
|
||||||
|
import util.Characters.NEWLINE
|
||||||
|
import util.Characters.SEMICOLON
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes Lisp comments from an input stream.
|
||||||
|
*/
|
||||||
|
class LispCommentRemovingInputStream(underlyingInputStream: InputStream) : LispInputStream {
|
||||||
|
|
||||||
|
private val underlyingInputStream = SafeInputStream(underlyingInputStream)
|
||||||
|
private var isInQuotedString = false
|
||||||
|
private var rereadLastCharacter = false
|
||||||
|
private var previousCharacter = 0
|
||||||
|
private var currentCharacter = 0
|
||||||
|
|
||||||
|
override fun read(): Int {
|
||||||
|
if (!rereadLastCharacter)
|
||||||
|
return readFromUnderlyingInputStream()
|
||||||
|
|
||||||
|
rereadLastCharacter = false
|
||||||
|
|
||||||
|
return currentCharacter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unreadLastCharacter() {
|
||||||
|
if (rereadLastCharacter)
|
||||||
|
throw LispInputStream.MaximumUnreadsExceededException()
|
||||||
|
|
||||||
|
this.rereadLastCharacter = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readFromUnderlyingInputStream(): Int {
|
||||||
|
readNextCharacter()
|
||||||
|
|
||||||
|
if (haveEnteredComment())
|
||||||
|
consumeAllBytesInComment()
|
||||||
|
|
||||||
|
return currentCharacter
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readNextCharacter() {
|
||||||
|
previousCharacter = currentCharacter
|
||||||
|
currentCharacter = underlyingInputStream.read()
|
||||||
|
|
||||||
|
if (haveEncounteredStringBoundary())
|
||||||
|
isInQuotedString = !isInQuotedString
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun haveEncounteredStringBoundary() =
|
||||||
|
previousCharacter != BACKSLASH.toInt() && currentCharacter == DOUBLE_QUOTE.toInt()
|
||||||
|
|
||||||
|
private fun haveEnteredComment() = currentCharacter == SEMICOLON.toInt() && !isInQuotedString
|
||||||
|
|
||||||
|
private fun consumeAllBytesInComment() {
|
||||||
|
while (stillInComment())
|
||||||
|
currentCharacter = underlyingInputStream.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stillInComment() = currentCharacter != NEWLINE.toInt() && currentCharacter != EOF
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
package scanner;
|
|
||||||
|
|
||||||
import error.CriticalLispException;
|
|
||||||
|
|
||||||
public interface LispInputStream {
|
|
||||||
|
|
||||||
int read();
|
|
||||||
|
|
||||||
void unreadLastCharacter();
|
|
||||||
|
|
||||||
public static class MaximumUnreadsExceededException extends CriticalLispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import error.CriticalLispException
|
||||||
|
|
||||||
|
interface LispInputStream {
|
||||||
|
|
||||||
|
fun read(): Int
|
||||||
|
fun unreadLastCharacter()
|
||||||
|
|
||||||
|
class MaximumUnreadsExceededException : CriticalLispException()
|
||||||
|
}
|
|
@ -1,181 +0,0 @@
|
||||||
package scanner;
|
|
||||||
|
|
||||||
import error.LineColumnException;
|
|
||||||
import file.FilePosition;
|
|
||||||
import file.FilePositionTracker;
|
|
||||||
import token.Token;
|
|
||||||
import token.TokenFactory;
|
|
||||||
import token.TokenFactoryImpl;
|
|
||||||
import util.Characters;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static java.lang.Character.isDigit;
|
|
||||||
import static java.lang.Character.isWhitespace;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a stream of bytes into a stream of Lisp tokens.
|
|
||||||
*/
|
|
||||||
public class LispScanner {
|
|
||||||
|
|
||||||
private LispInputStream inputStream;
|
|
||||||
private FilePositionTracker positionTracker;
|
|
||||||
private TokenFactory tokenFactory;
|
|
||||||
|
|
||||||
public LispScanner(InputStream inputStream, String fileName) {
|
|
||||||
this.inputStream = new LispCommentRemovingInputStream(inputStream);
|
|
||||||
this.positionTracker = new FilePositionTracker(fileName);
|
|
||||||
this.tokenFactory = new TokenFactoryImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Token getNextToken() {
|
|
||||||
for (int c = inputStream.read(); c != Characters.EOF; c = inputStream.read()) {
|
|
||||||
char currentCharacter = (char) c;
|
|
||||||
positionTracker.incrementColumn();
|
|
||||||
|
|
||||||
if (!isWhitespace(currentCharacter))
|
|
||||||
return createTokenFromCharacter(currentCharacter);
|
|
||||||
else if (currentCharacter == Characters.NEWLINE)
|
|
||||||
positionTracker.incrementLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenFactory.createEofToken(positionTracker.currentPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Token createTokenFromCharacter(char c) {
|
|
||||||
FilePosition currentPosition = positionTracker.currentPosition();
|
|
||||||
String tokenText = retrieveTokenText(c);
|
|
||||||
|
|
||||||
return tokenFactory.createToken(tokenText, currentPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String retrieveTokenText(char firstCharacter) {
|
|
||||||
String tokenText = "" + firstCharacter;
|
|
||||||
|
|
||||||
if (firstCharacter == Characters.DOUBLE_QUOTE)
|
|
||||||
tokenText = retrieveStringTokenText(firstCharacter);
|
|
||||||
else if (Characters.INSTANCE.isNumberPrefix(firstCharacter))
|
|
||||||
tokenText = retrieveNumberOrIdentifierTokenText(firstCharacter);
|
|
||||||
else if (isDigit(firstCharacter))
|
|
||||||
tokenText = retrieveNumberTokenText(firstCharacter);
|
|
||||||
else if (Characters.INSTANCE.isLegalIdentifierCharacter(firstCharacter))
|
|
||||||
tokenText = retrieveIdentifierTokenText(firstCharacter);
|
|
||||||
|
|
||||||
return tokenText;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String retrieveStringTokenText(char firstDoubleQuote) {
|
|
||||||
ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstDoubleQuote,
|
|
||||||
Characters.INSTANCE::isLegalStringCharacter);
|
|
||||||
|
|
||||||
return retriever.retrieveToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String retrieveNumberOrIdentifierTokenText(char firstCharacter) {
|
|
||||||
char nextCharacter = (char) inputStream.read();
|
|
||||||
inputStream.unreadLastCharacter();
|
|
||||||
|
|
||||||
if (isDigit(nextCharacter))
|
|
||||||
return retrieveNumberTokenText(firstCharacter);
|
|
||||||
|
|
||||||
return retrieveIdentifierTokenText(firstCharacter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String retrieveNumberTokenText(char firstCharacter) {
|
|
||||||
ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstCharacter, Character::isDigit);
|
|
||||||
|
|
||||||
return retriever.retrieveToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String retrieveIdentifierTokenText(char firstCharacter) {
|
|
||||||
ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstCharacter,
|
|
||||||
Characters.INSTANCE::isLegalIdentifierCharacter);
|
|
||||||
|
|
||||||
return retriever.retrieveToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ComplexTokenTextRetriever {
|
|
||||||
|
|
||||||
Function<Character, Boolean> isPartOfToken;
|
|
||||||
StringBuilder text;
|
|
||||||
FilePosition position;
|
|
||||||
char firstCharacter;
|
|
||||||
char currentCharacter;
|
|
||||||
char previousCharacter;
|
|
||||||
|
|
||||||
public ComplexTokenTextRetriever(char firstCharacter, Function<Character, Boolean> isPartOfToken) {
|
|
||||||
this.isPartOfToken = isPartOfToken;
|
|
||||||
this.text = new StringBuilder();
|
|
||||||
this.position = positionTracker.currentPosition();
|
|
||||||
this.firstCharacter = firstCharacter;
|
|
||||||
this.currentCharacter = firstCharacter;
|
|
||||||
this.previousCharacter = firstCharacter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String retrieveToken() {
|
|
||||||
text.append(firstCharacter);
|
|
||||||
|
|
||||||
for (int c = inputStream.read(); c != Characters.EOF; c = inputStream.read()) {
|
|
||||||
currentCharacter = (char) c;
|
|
||||||
|
|
||||||
if (!isPartOfToken.apply(currentCharacter)) {
|
|
||||||
inputStream.unreadLastCharacter();
|
|
||||||
|
|
||||||
return text.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
addCharacterToToken();
|
|
||||||
|
|
||||||
if (isTerminatingCharacter())
|
|
||||||
return text.toString();
|
|
||||||
|
|
||||||
previousCharacter = currentCharacter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return terminateTokenWithEof();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addCharacterToToken() {
|
|
||||||
text.append(currentCharacter);
|
|
||||||
positionTracker.incrementColumn();
|
|
||||||
|
|
||||||
if (currentCharacter == Characters.NEWLINE)
|
|
||||||
positionTracker.incrementLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTerminatingCharacter() {
|
|
||||||
return isStringToken() && isTerminatingDoubleQuote();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isStringToken() {
|
|
||||||
return firstCharacter == Characters.DOUBLE_QUOTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTerminatingDoubleQuote() {
|
|
||||||
return (currentCharacter == Characters.DOUBLE_QUOTE) &&
|
|
||||||
(previousCharacter != Characters.BACKSLASH);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String terminateTokenWithEof() {
|
|
||||||
if (isStringToken())
|
|
||||||
throw new UnterminatedStringException(position);
|
|
||||||
|
|
||||||
return text.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UnterminatedStringException extends LineColumnException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public UnterminatedStringException(FilePosition position) {
|
|
||||||
super(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessagePrefix() {
|
|
||||||
return "unterminated quoted string";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import error.LineColumnException
|
||||||
|
import file.FilePosition
|
||||||
|
import file.FilePositionTracker
|
||||||
|
import token.Token
|
||||||
|
import token.TokenFactoryImpl
|
||||||
|
import util.Characters
|
||||||
|
import util.Characters.BACKSLASH
|
||||||
|
import util.Characters.DOUBLE_QUOTE
|
||||||
|
import util.Characters.EOF
|
||||||
|
import util.Characters.NEWLINE
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.lang.Character.isDigit
|
||||||
|
import java.lang.Character.isWhitespace
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a stream of bytes into a stream of Lisp tokens.
|
||||||
|
*/
|
||||||
|
class LispScanner(inputStream: InputStream, fileName: String) {
|
||||||
|
|
||||||
|
private val inputStream = LispCommentRemovingInputStream(inputStream)
|
||||||
|
private val positionTracker = FilePositionTracker(fileName)
|
||||||
|
private val tokenFactory = TokenFactoryImpl()
|
||||||
|
|
||||||
|
val nextToken: Token
|
||||||
|
get() {
|
||||||
|
var c = inputStream.read()
|
||||||
|
while (c != EOF) {
|
||||||
|
val currentCharacter = c.toChar()
|
||||||
|
positionTracker.incrementColumn()
|
||||||
|
|
||||||
|
if (!isWhitespace(currentCharacter))
|
||||||
|
return createTokenFromCharacter(currentCharacter)
|
||||||
|
else if (currentCharacter == NEWLINE)
|
||||||
|
positionTracker.incrementLine()
|
||||||
|
|
||||||
|
c = inputStream.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenFactory.createEofToken(positionTracker.currentPosition())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTokenFromCharacter(c: Char): Token {
|
||||||
|
val currentPosition = positionTracker.currentPosition()
|
||||||
|
val tokenText = retrieveTokenText(c)
|
||||||
|
|
||||||
|
return tokenFactory.createToken(tokenText, currentPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retrieveTokenText(firstCharacter: Char): String {
|
||||||
|
var tokenText = "" + firstCharacter
|
||||||
|
|
||||||
|
if (firstCharacter == DOUBLE_QUOTE)
|
||||||
|
tokenText = retrieveStringTokenText(firstCharacter)
|
||||||
|
else if (Characters.isNumberPrefix(firstCharacter))
|
||||||
|
tokenText = retrieveNumberOrIdentifierTokenText(firstCharacter)
|
||||||
|
else if (isDigit(firstCharacter))
|
||||||
|
tokenText = retrieveNumberTokenText(firstCharacter)
|
||||||
|
else if (Characters.isLegalIdentifierCharacter(firstCharacter))
|
||||||
|
tokenText = retrieveIdentifierTokenText(firstCharacter)
|
||||||
|
|
||||||
|
return tokenText
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retrieveStringTokenText(firstDoubleQuote: Char) =
|
||||||
|
ComplexTokenTextRetriever(firstDoubleQuote, { Characters.isLegalStringCharacter(it) }).retrieveToken()
|
||||||
|
|
||||||
|
private fun retrieveNumberOrIdentifierTokenText(firstCharacter: Char): String {
|
||||||
|
val nextCharacter = inputStream.read().toChar()
|
||||||
|
inputStream.unreadLastCharacter()
|
||||||
|
|
||||||
|
return if (isDigit(nextCharacter))
|
||||||
|
retrieveNumberTokenText(firstCharacter)
|
||||||
|
else
|
||||||
|
retrieveIdentifierTokenText(firstCharacter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retrieveNumberTokenText(firstCharacter: Char) =
|
||||||
|
ComplexTokenTextRetriever(firstCharacter, { Character.isDigit(it) }).retrieveToken()
|
||||||
|
|
||||||
|
private fun retrieveIdentifierTokenText(firstCharacter: Char) =
|
||||||
|
ComplexTokenTextRetriever(firstCharacter, { Characters.isLegalIdentifierCharacter(it) }).retrieveToken()
|
||||||
|
|
||||||
|
private inner class ComplexTokenTextRetriever(internal var firstCharacter: Char,
|
||||||
|
internal var isPartOfToken: (Char) -> Boolean) {
|
||||||
|
internal var text = StringBuilder()
|
||||||
|
internal var position = positionTracker.currentPosition()
|
||||||
|
internal var currentCharacter = firstCharacter
|
||||||
|
internal var previousCharacter = firstCharacter
|
||||||
|
|
||||||
|
private fun isTerminatingCharacter() = isStringToken() && isTerminatingDoubleQuote()
|
||||||
|
private fun isStringToken() = firstCharacter == DOUBLE_QUOTE
|
||||||
|
private fun isTerminatingDoubleQuote() = currentCharacter == DOUBLE_QUOTE && previousCharacter != BACKSLASH
|
||||||
|
|
||||||
|
fun retrieveToken(): String {
|
||||||
|
text.append(firstCharacter)
|
||||||
|
|
||||||
|
var c = inputStream.read()
|
||||||
|
while (c != EOF) {
|
||||||
|
currentCharacter = c.toChar()
|
||||||
|
|
||||||
|
if (!isPartOfToken(currentCharacter)) {
|
||||||
|
inputStream.unreadLastCharacter()
|
||||||
|
|
||||||
|
return text.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
addCharacterToToken()
|
||||||
|
|
||||||
|
if (isTerminatingCharacter())
|
||||||
|
return text.toString()
|
||||||
|
|
||||||
|
previousCharacter = currentCharacter
|
||||||
|
c = inputStream.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
return terminateTokenWithEof()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addCharacterToToken() {
|
||||||
|
text.append(currentCharacter)
|
||||||
|
positionTracker.incrementColumn()
|
||||||
|
|
||||||
|
if (currentCharacter == NEWLINE)
|
||||||
|
positionTracker.incrementLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun terminateTokenWithEof(): String {
|
||||||
|
if (isStringToken())
|
||||||
|
throw UnterminatedStringException(position)
|
||||||
|
|
||||||
|
return text.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnterminatedStringException(position: FilePosition) : LineColumnException(position) {
|
||||||
|
override val messagePrefix: String
|
||||||
|
get() = "unterminated quoted string"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
package stream;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
||||||
|
|
||||||
public class SafeInputStream {
|
|
||||||
|
|
||||||
private InputStreamReader underlyingStream;
|
|
||||||
|
|
||||||
public SafeInputStream(InputStream underlyingStream) {
|
|
||||||
this.underlyingStream = new InputStreamReader(underlyingStream, UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read() {
|
|
||||||
try {
|
|
||||||
return underlyingStream.read();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
underlyingStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package stream
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
|
|
||||||
|
class SafeInputStream(underlyingStream: InputStream) {
|
||||||
|
|
||||||
|
private val underlyingStream: InputStreamReader = InputStreamReader(underlyingStream, UTF_8)
|
||||||
|
|
||||||
|
fun read(): Int {
|
||||||
|
try {
|
||||||
|
return underlyingStream.read()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
try {
|
||||||
|
underlyingStream.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
package stream;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class SafeOutputStream {
|
|
||||||
|
|
||||||
private OutputStream underlyingStream;
|
|
||||||
|
|
||||||
public SafeOutputStream(OutputStream underlyingStream) {
|
|
||||||
this.underlyingStream = underlyingStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) {
|
|
||||||
try {
|
|
||||||
underlyingStream.write(b);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
underlyingStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
underlyingStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package stream
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
class SafeOutputStream(private val underlyingStream: OutputStream) {
|
||||||
|
|
||||||
|
fun write(b: ByteArray) {
|
||||||
|
try {
|
||||||
|
underlyingStream.write(b)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun flush() {
|
||||||
|
try {
|
||||||
|
underlyingStream.flush()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
try {
|
||||||
|
underlyingStream.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
package stream;
|
|
||||||
|
|
||||||
import error.CriticalLispException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class UncheckedIOException extends CriticalLispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private IOException exception;
|
|
||||||
|
|
||||||
public UncheckedIOException(IOException exception) {
|
|
||||||
this.exception = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return exception.getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package stream
|
||||||
|
|
||||||
|
import error.CriticalLispException
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class UncheckedIOException(private val exception: IOException) : CriticalLispException() {
|
||||||
|
|
||||||
|
override val message: String
|
||||||
|
get() = exception.message ?: ""
|
||||||
|
}
|
Loading…
Reference in New Issue