Convert the interpreter to kotlin

This commit is contained in:
Mike Cifelli 2018-08-05 10:48:18 -04:00
parent d376c30d7a
commit eaf80390be
11 changed files with 115 additions and 162 deletions

View File

@ -1,7 +1,6 @@
package function
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy.RUNTIME
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE

View File

@ -1,28 +0,0 @@
package interpreter;
import sexpression.SExpression;
public class FileLispInterpreter extends LispInterpreter {
private SExpression lastSExpression;
public FileLispInterpreter() {
this.lastSExpression = null;
}
@Override
protected SExpression evaluateNextSExpression() {
return this.lastSExpression = super.evaluateNextSExpression();
}
@Override
protected void printSExpression(SExpression sExpression) {}
@Override
protected void applyFinishingTouches() {
if (lastSExpression != null)
super.printSExpression(lastSExpression);
super.applyFinishingTouches();
}
}

View File

@ -0,0 +1,19 @@
package interpreter
import sexpression.SExpression
class FileLispInterpreter : LispInterpreter() {
private var lastSExpression: SExpression? = null
override fun printSExpression(sExpression: SExpression) {
lastSExpression = sExpression
}
override fun applyFinishingTouches() {
if (lastSExpression != null)
super.printSExpression(lastSExpression!!)
super.applyFinishingTouches()
}
}

View File

@ -1,24 +0,0 @@
package interpreter;
public class InteractiveLispInterpreter extends LispInterpreter {
public static final String PROMPT = "~ ";
@Override
protected void prompt() {
environment.getOutput().print(environment.decoratePrompt(PROMPT));
environment.getOutput().flush();
}
@Override
protected void evaluateAndPrintNextSExpression() {
environment.getOutput().println();
super.evaluateAndPrintNextSExpression();
}
@Override
protected void applyFinishingTouches() {
environment.getOutput().println(environment.decoratePrompt(""));
environment.getOutput().flush();
}
}

View File

@ -0,0 +1,27 @@
package interpreter
import environment.RuntimeEnvironment.decoratePrompt
import environment.RuntimeEnvironment.output
import sexpression.SExpression
class InteractiveLispInterpreter : LispInterpreter() {
override fun prompt() = output?.run {
print(decoratePrompt(PROMPT))
flush()
}
override fun printSExpression(sExpression: SExpression) = output?.run {
println()
super.printSExpression(sExpression)
}
override fun applyFinishingTouches() = output?.run {
println(decoratePrompt(""))
flush()
}
companion object {
internal const val PROMPT = "~ "
}
}

View File

@ -1,93 +0,0 @@
package interpreter;
import environment.RuntimeEnvironment;
import error.LispException;
import parser.LispParser;
import sexpression.SExpression;
import java.io.InputStream;
import java.util.List;
import static function.builtin.EVAL.eval;
public class LispInterpreter {
protected RuntimeEnvironment environment;
private LispParser parser;
public LispInterpreter() {
this.environment = RuntimeEnvironment.INSTANCE;
}
public void interpretLanguageFiles(List<LanguageFile> languageFiles) {
for (LanguageFile file : languageFiles) {
LispParser languageParser = new LispParser(file.getInputStream(), file.getName());
while (!languageParser.isEof())
eval(languageParser.nextSExpression());
}
}
public void interpret() {
createParser();
for (prompt(); !parser.isEof(); prompt())
evaluateAndPrintNextSExpression();
applyFinishingTouches();
}
private void createParser() {
parser = new LispParser(environment.getInput(), environment.getInputName());
}
protected void prompt() {}
protected void evaluateAndPrintNextSExpression() {
try {
evaluateAndPrintNextSExpressionWithException();
} catch (LispException e) {
environment.getErrorManager().handle(e);
}
}
private void evaluateAndPrintNextSExpressionWithException() {
printSExpression(evaluateNextSExpression());
}
protected SExpression evaluateNextSExpression() {
SExpression sExpression = parser.nextSExpression();
return eval(sExpression);
}
protected void printSExpression(SExpression sExpression) {
String result = environment.decorateValueOutput(String.valueOf(sExpression));
environment.getOutput().println(result);
environment.getOutput().flush();
}
protected void applyFinishingTouches() {
environment.getOutput().println();
environment.getOutput().flush();
}
public static class LanguageFile {
private InputStream inputStream;
private String name;
public LanguageFile(InputStream inputStream, String name) {
this.inputStream = inputStream;
this.name = "lang:" + name;
}
public InputStream getInputStream() {
return inputStream;
}
public String getName() {
return name;
}
}
}

View File

@ -0,0 +1,56 @@
package interpreter
import environment.RuntimeEnvironment.decorateValueOutput
import environment.RuntimeEnvironment.errorManager
import environment.RuntimeEnvironment.input
import environment.RuntimeEnvironment.inputName
import environment.RuntimeEnvironment.output
import error.LispException
import function.builtin.EVAL.eval
import parser.LispParser
import sexpression.SExpression
import java.io.InputStream
open class LispInterpreter {
private lateinit var parser: LispParser
fun interpretLanguageFiles(languageFiles: List<LanguageFile>) {
for (file in languageFiles)
LispParser(file.inputStream, file.name).forEach { eval(it) }
}
fun interpret() {
parser = LispParser(input!!, inputName!!)
prompt()
while (!parser.isEof()) {
evaluateAndPrintNextSExpression()
prompt()
}
applyFinishingTouches()
}
protected open fun prompt(): Unit? = null
protected open fun evaluateAndPrintNextSExpression() = try {
printSExpression(eval(parser.nextSExpression()))
} catch (e: LispException) {
errorManager?.run { handle(e) }
}
protected open fun printSExpression(sExpression: SExpression) = output?.run {
println(decorateValueOutput(sExpression.toString()))
flush()
}
protected open fun applyFinishingTouches() = output?.run {
println()
flush()
}
class LanguageFile(val inputStream: InputStream, name: String) {
val name: String = "lang:$name"
}
}

View File

@ -151,13 +151,10 @@ object LispInterpreterBuilder {
private fun getInputStream() = if (isFileBased) FileInputStream(inputName) else inputStream
private fun createInterpreter(): LispInterpreter {
if (isFileBased)
return FileLispInterpreter()
else if (isInteractive)
return InteractiveLispInterpreter()
return LispInterpreter()
private fun createInterpreter() = when {
isFileBased -> FileLispInterpreter()
isInteractive -> InteractiveLispInterpreter()
else -> LispInterpreter()
}
class LispFileNotFoundException(val e: FileNotFoundException) : CriticalLispException() {

View File

@ -10,13 +10,15 @@ import java.io.InputStream
/**
* Converts a stream of bytes into internal representations of Lisp s-expressions.
*/
class LispParser(inputStream: InputStream, fileName: String) {
class LispParser(inputStream: InputStream, fileName: String) : AbstractIterator<SExpression>() {
private val scanner: LispScanner = LispScanner(inputStream, fileName)
private var nextToken: Token? = null
private var delayedException: LispException? = null
private var isNextTokenStored: Boolean = false
override fun computeNext() = if (isEof()) done() else setNext(nextSExpression())
fun isEof(): Boolean {
if (!isNextTokenStored)
storeNextToken()
@ -32,7 +34,7 @@ class LispParser(inputStream: InputStream, fileName: String) {
isNextTokenStored = false
return nextToken!!.parseSExpression({ scanner.nextToken })
return nextToken!!.parseSExpression { scanner.nextToken }
}
private fun storeNextToken() {

View File

@ -1,7 +1,7 @@
package interpreter
import environment.RuntimeEnvironment
import interpreter.InteractiveLispInterpreter.PROMPT
import interpreter.InteractiveLispInterpreter.Companion.PROMPT
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse

View File

@ -17,12 +17,10 @@ class LispCommentRemovingInputStreamTest {
private fun createLispInputStream(inputString: String) =
LispCommentRemovingInputStream(createInputStreamFromString(inputString))
private fun readInputStreamIntoString(inputStream: LispInputStream) = StringBuilder().let {
private fun readInputStreamIntoString(inputStream: LispInputStream) = StringBuilder().apply {
for (c in inputStream)
it.append(c.toChar())
it.toString()
}
append(c.toChar())
}.toString()
@Test
fun `no bytes in gives no bytes out`() {