Convert to function types

This commit is contained in:
Mike Cifelli 2018-03-27 20:52:57 -04:00
parent 2177d13397
commit d7a751ad39
12 changed files with 468 additions and 478 deletions

View File

@ -1,153 +0,0 @@
package application;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.IOSafeTerminal;
import com.googlecode.lanterna.terminal.Terminal;
import interpreter.LispInterpreter;
import interpreter.LispInterpreterBuilder;
import stream.UncheckedIOException;
import terminal.LispTerminal;
import terminal.TerminalConfiguration;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.function.Function;
import static com.googlecode.lanterna.terminal.IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter;
import static java.text.MessageFormat.format;
import static terminal.LispTerminal.END_OF_SEGMENT;
public class LispMain {
public static final String GREETING = "Transcendental Lisp - Version {0}";
public static final String ANSI_RESET = "\u001B[0m";
public static final String ANSI_RED = "\u001B[31m";
public static final String ANSI_GREEN = "\u001B[32m";
public static final String ANSI_YELLOW = "\u001B[33m";
public static final String ANSI_PURPLE = "\u001B[35m";
public static final String[] LANGUAGE_FILE_NAMES = new String[] { "functions.lisp", "dlambda.lisp" };
public static void main(String[] arguments) {
LispMain lispMain = new LispMain();
if (arguments.length == 0)
lispMain.runInteractive();
else
lispMain.runWithFile(arguments[0]);
}
private LispInterpreterBuilder builder;
private PipedInputStream inputReader;
private PrintStream output;
private LispTerminal lispTerminal;
private TerminalConfiguration configuration;
public LispMain() {
this.builder = LispInterpreterBuilder.INSTANCE;
}
public LispMain(TerminalConfiguration configuration) {
this.builder = LispInterpreterBuilder.INSTANCE;
this.configuration = configuration;
}
public void runInteractive() {
initializeTerminal();
printGreeting();
lispTerminal.start();
buildInteractiveInterpreter().interpret();
shutdownTerminal();
}
private void initializeTerminal() {
createTerminalConfiguration();
inputReader = configuration.getInputReader();
output = new PrintStream(configuration.getOutputWriter());
lispTerminal = new LispTerminal(configuration);
}
private void createTerminalConfiguration() {
if (configuration == null) {
configuration = new TerminalConfiguration();
configuration.setInputPair(new PipedOutputStream(), new PipedInputStream());
configuration.setOutputPair(new PipedOutputStream(), new PipedInputStream());
configuration.setTerminal(createIOSafeTerminal());
}
}
private IOSafeTerminal createIOSafeTerminal() {
return createRuntimeExceptionConvertingAdapter(createDefaultTerminal());
}
private Terminal createDefaultTerminal() {
try {
return new DefaultTerminalFactory().createTerminal();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void printGreeting() {
output.println(format(GREETING, getVersion()));
output.println();
}
private String getVersion() {
return getClass().getPackage().getImplementationVersion();
}
private LispInterpreter buildInteractiveInterpreter() {
builder.setInput(inputReader, "terminal");
builder.setOutput(output);
builder.setErrorOutput(output);
builder.setTerminationFunction(this::shutdownTerminal);
builder.setErrorTerminationFunction(this::shutdownTerminal);
builder.setLanguageFileNames(LANGUAGE_FILE_NAMES);
builder.setPromptDecorator(s -> s + END_OF_SEGMENT);
builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN));
builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW));
builder.setErrorOutputDecorator(makeColorDecorator(ANSI_RED));
builder.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE));
return builder.build();
}
private void shutdownTerminal() {
output.print(END_OF_SEGMENT);
lispTerminal.stop();
output.close();
}
private Function<String, String> makeColorDecorator(String color) {
return new Function<String, String>() {
@Override
public String apply(String s) {
return color + s + ANSI_RESET;
}
};
}
public void runWithFile(String fileName) {
buildFileInterpreter(fileName).interpret();
}
private LispInterpreter buildFileInterpreter(String fileName) {
builder.useFile(fileName);
builder.setOutput(System.out);
builder.setErrorOutput(System.err);
builder.setTerminationFunction(() -> System.exit(0));
builder.setErrorTerminationFunction(() -> System.exit(1));
builder.setLanguageFileNames(LANGUAGE_FILE_NAMES);
builder.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN));
builder.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW));
builder.setErrorOutputDecorator(makeColorDecorator(ANSI_RED));
builder.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE));
return builder.build();
}
}

View File

@ -0,0 +1,146 @@
package application
import com.googlecode.lanterna.terminal.DefaultTerminalFactory
import com.googlecode.lanterna.terminal.IOSafeTerminal
import com.googlecode.lanterna.terminal.IOSafeTerminalAdapter.createRuntimeExceptionConvertingAdapter
import com.googlecode.lanterna.terminal.Terminal
import interpreter.LispInterpreter
import interpreter.LispInterpreterBuilder
import stream.UncheckedIOException
import terminal.LispTerminal
import terminal.LispTerminal.END_OF_SEGMENT
import terminal.TerminalConfiguration
import java.io.IOException
import java.io.PipedInputStream
import java.io.PipedOutputStream
import java.io.PrintStream
import java.text.MessageFormat.format
class LispMain {
private var builder: LispInterpreterBuilder? = null
private var inputReader: PipedInputStream? = null
private var output: PrintStream? = null
private var lispTerminal: LispTerminal? = null
private var configuration: TerminalConfiguration? = null
private val version = LispMain::class.java.`package`.implementationVersion
constructor() {
this.builder = LispInterpreterBuilder
}
constructor(configuration: TerminalConfiguration) {
this.builder = LispInterpreterBuilder
this.configuration = configuration
}
fun runInteractive() {
initializeTerminal()
printGreeting()
lispTerminal!!.start()
buildInteractiveInterpreter().interpret()
shutdownTerminal()
}
private fun initializeTerminal() {
createTerminalConfiguration()
inputReader = configuration!!.inputReader
output = PrintStream(configuration!!.outputWriter)
lispTerminal = LispTerminal(configuration!!)
}
private fun createTerminalConfiguration() {
if (configuration == null) {
configuration = TerminalConfiguration()
configuration!!.setInputPair(PipedOutputStream(), PipedInputStream())
configuration!!.setOutputPair(PipedOutputStream(), PipedInputStream())
configuration!!.terminal = createIOSafeTerminal()
}
}
private fun createIOSafeTerminal(): IOSafeTerminal {
return createRuntimeExceptionConvertingAdapter(createDefaultTerminal())
}
private fun createDefaultTerminal(): Terminal {
try {
return DefaultTerminalFactory().createTerminal()
} catch (e: IOException) {
throw UncheckedIOException(e)
}
}
private fun printGreeting() {
output!!.println(format(GREETING, (version ?: "null")))
output!!.println()
}
private fun buildInteractiveInterpreter(): LispInterpreter {
builder!!.setInput(inputReader!!, "terminal")
builder!!.setOutput(output!!)
builder!!.setErrorOutput(output!!)
builder!!.setTerminationFunction { this.shutdownTerminal() }
builder!!.setErrorTerminationFunction { this.shutdownTerminal() }
builder!!.setLanguageFileNames(*LANGUAGE_FILE_NAMES)
builder!!.setPromptDecorator { s -> s + END_OF_SEGMENT }
builder!!.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN))
builder!!.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW))
builder!!.setErrorOutputDecorator(makeColorDecorator(ANSI_RED))
builder!!.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE))
return builder!!.build()
}
private fun shutdownTerminal() {
output!!.print(END_OF_SEGMENT)
lispTerminal!!.stop()
output!!.close()
}
private fun makeColorDecorator(color: String): (String) -> String {
return { color + it + ANSI_RESET }
}
fun runWithFile(fileName: String) {
buildFileInterpreter(fileName).interpret()
}
private fun buildFileInterpreter(fileName: String): LispInterpreter {
builder!!.useFile(fileName)
builder!!.setOutput(System.out)
builder!!.setErrorOutput(System.err)
builder!!.setTerminationFunction { System.exit(0) }
builder!!.setErrorTerminationFunction { System.exit(1) }
builder!!.setLanguageFileNames(*LANGUAGE_FILE_NAMES)
builder!!.setValueOutputDecorator(makeColorDecorator(ANSI_GREEN))
builder!!.setWarningOutputDecorator(makeColorDecorator(ANSI_YELLOW))
builder!!.setErrorOutputDecorator(makeColorDecorator(ANSI_RED))
builder!!.setCriticalOutputDecorator(makeColorDecorator(ANSI_PURPLE))
return builder!!.build()
}
companion object {
val GREETING = "Transcendental Lisp - Version {0}"
val ANSI_RESET = "\u001B[0m"
val ANSI_RED = "\u001B[31m"
val ANSI_GREEN = "\u001B[32m"
val ANSI_YELLOW = "\u001B[33m"
val ANSI_PURPLE = "\u001B[35m"
val LANGUAGE_FILE_NAMES = arrayOf("functions.lisp", "dlambda.lisp")
@JvmStatic
fun main(arguments: Array<String>) {
val lispMain = LispMain()
if (arguments.size == 0)
lispMain.runInteractive()
else
lispMain.runWithFile(arguments[0])
}
}
}

View File

@ -1,10 +1,8 @@
package environment
import error.ErrorManager
import java.io.InputStream
import java.io.PrintStream
import java.util.function.Function
object RuntimeEnvironment {
@ -15,14 +13,13 @@ object RuntimeEnvironment {
var errorManager: ErrorManager? = null
var path: String? = null
// TODO - convert to function types ()-> Unit etc... once calling code is kotlin
var terminationFunction: Runnable? = null
var errorTerminationFunction: Runnable? = null
var promptDecorator: Function<String, String>? = null
var valueOutputDecorator: Function<String, String>? = null
var warningOutputDecorator: Function<String, String>? = null
var errorOutputDecorator: Function<String, String>? = null
var criticalOutputDecorator: Function<String, String>? = null
var terminationFunction: (() -> Unit) = {}
var errorTerminationFunction: (() -> Unit) = {}
var promptDecorator: ((String) -> String) = { it }
var valueOutputDecorator: ((String) -> String) = { it }
var warningOutputDecorator: ((String) -> String) = { it }
var errorOutputDecorator: ((String) -> String) = { it }
var criticalOutputDecorator: ((String) -> String) = { it }
fun reset() {
inputName = null
@ -31,26 +28,26 @@ object RuntimeEnvironment {
errorOutput = null
errorManager = null
path = null
terminationFunction = null
errorTerminationFunction = null
promptDecorator = null
valueOutputDecorator = null
warningOutputDecorator = null
errorOutputDecorator = null
criticalOutputDecorator = null
terminationFunction = {}
errorTerminationFunction = {}
promptDecorator = { it }
valueOutputDecorator = { it }
warningOutputDecorator = { it }
errorOutputDecorator = { it }
criticalOutputDecorator = { it }
}
fun terminateSuccessfully() {
terminationFunction!!.run()
terminationFunction()
}
fun terminateExceptionally() {
errorTerminationFunction!!.run()
errorTerminationFunction()
}
fun decoratePrompt(prompt: String) = promptDecorator!!.apply(prompt)
fun decorateValueOutput(valueOutput: String) = valueOutputDecorator!!.apply(valueOutput)
fun decorateWarningOutput(warningOutput: String) = warningOutputDecorator!!.apply(warningOutput)
fun decorateErrorOutput(errorOutput: String) = errorOutputDecorator!!.apply(errorOutput)
fun decorateCriticalOutput(criticalOutput: String) = criticalOutputDecorator!!.apply(criticalOutput)
fun decoratePrompt(prompt: String) = promptDecorator(prompt)
fun decorateValueOutput(valueOutput: String) = valueOutputDecorator(valueOutput)
fun decorateWarningOutput(warningOutput: String) = warningOutputDecorator(warningOutput)
fun decorateErrorOutput(errorOutput: String) = errorOutputDecorator(errorOutput)
fun decorateCriticalOutput(criticalOutput: String) = criticalOutputDecorator(criticalOutput)
}

View File

@ -5,13 +5,11 @@ import error.CriticalLispException
import error.ErrorManager
import interpreter.LispInterpreter.LanguageFile
import util.Path
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.InputStream
import java.io.PrintStream
import java.util.ArrayList
import java.util.function.Function
object LispInterpreterBuilder {
@ -19,31 +17,40 @@ object LispInterpreterBuilder {
private var isInteractive = true
private var isFileBased = false
private var languageFiles = ArrayList<LanguageFile>()
private var promptDecorator = Function<String, String> { s -> s }
private var valueOutputDecorator = Function<String, String> { s -> s }
private var warningOutputDecorator = Function<String, String> { s -> s }
private var errorOutputDecorator = Function<String, String> { s -> s }
private var criticalOutputDecorator = Function<String, String> { s -> s }
private var inputStream: InputStream? = null
private var outputStream: PrintStream? = null
private var errorOutputStream: PrintStream? = null
private var terminationFunction: Runnable? = null
private var errorTerminationFunction: Runnable? = null
private var terminationFunction: () -> Unit = {}
private var errorTerminationFunction: () -> Unit = {}
private var promptDecorator: (String) -> String = { it }
private var valueOutputDecorator: (String) -> String = { it }
private var warningOutputDecorator: (String) -> String = { it }
private var errorOutputDecorator: (String) -> String = { it }
private var criticalOutputDecorator: (String) -> String = { it }
init {
reset()
}
fun reset() {
this.inputName = ""
this.isInteractive = true
this.isFileBased = false
this.languageFiles = ArrayList()
this.promptDecorator = Function { s -> s }
this.valueOutputDecorator = Function { s -> s }
this.warningOutputDecorator = Function { s -> s }
this.errorOutputDecorator = Function { s -> s }
this.criticalOutputDecorator = Function { s -> s }
inputName = ""
isInteractive = true
isFileBased = false
languageFiles = ArrayList()
inputStream = null
outputStream = null
errorOutputStream = null
terminationFunction = {}
errorTerminationFunction = {}
promptDecorator = { it }
valueOutputDecorator = { it }
warningOutputDecorator = { it }
errorOutputDecorator = { it }
criticalOutputDecorator = { it }
}
fun setNotInteractive() {
this.isInteractive = false
}
fun setInput(inputStream: InputStream, inputName: String) {
@ -59,18 +66,6 @@ object LispInterpreterBuilder {
this.errorOutputStream = errorOutputStream
}
fun setTerminationFunction(terminationFunction: Runnable) {
this.terminationFunction = terminationFunction
}
fun setErrorTerminationFunction(errorTerminationFunction: Runnable) {
this.errorTerminationFunction = errorTerminationFunction
}
fun setNotInteractive() {
this.isInteractive = false
}
fun useFile(fileName: String) {
this.isFileBased = true
this.inputName = fileName
@ -85,23 +80,31 @@ object LispInterpreterBuilder {
this.languageFiles!!.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName))
}
fun setPromptDecorator(decorator: Function<String, String>) {
fun setTerminationFunction(terminationFunction: () -> Unit) {
this.terminationFunction = terminationFunction
}
fun setErrorTerminationFunction(errorTerminationFunction: () -> Unit) {
this.errorTerminationFunction = errorTerminationFunction
}
fun setPromptDecorator(decorator: (String) -> String) {
this.promptDecorator = decorator
}
fun setValueOutputDecorator(decorator: Function<String, String>) {
fun setValueOutputDecorator(decorator: (String) -> String) {
this.valueOutputDecorator = decorator
}
fun setWarningOutputDecorator(decorator: Function<String, String>) {
fun setWarningOutputDecorator(decorator: (String) -> String) {
this.warningOutputDecorator = decorator
}
fun setErrorOutputDecorator(decorator: Function<String, String>) {
fun setErrorOutputDecorator(decorator: (String) -> String) {
this.errorOutputDecorator = decorator
}
fun setCriticalOutputDecorator(decorator: Function<String, String>) {
fun setCriticalOutputDecorator(decorator: (String) -> String) {
this.criticalOutputDecorator = decorator
}

View File

@ -1,5 +1,6 @@
package acceptance.fixture;
import application.LispMain;
import environment.RuntimeEnvironment;
import interpreter.LispInterpreter;
import interpreter.LispInterpreterBuilder;
@ -13,8 +14,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import static application.LispMain.LANGUAGE_FILE_NAMES;
public class LispInterpreterFixture {
private static ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@ -38,9 +37,9 @@ public class LispInterpreterFixture {
LispInterpreterBuilder.INSTANCE.setOutput(new PrintStream(outputStream));
LispInterpreterBuilder.INSTANCE.setErrorOutput(new PrintStream(outputStream));
LispInterpreterBuilder.INSTANCE.setNotInteractive();
LispInterpreterBuilder.INSTANCE.setLanguageFileNames(LANGUAGE_FILE_NAMES);
LispInterpreterBuilder.INSTANCE.setTerminationFunction(LispInterpreterFixture::terminate);
LispInterpreterBuilder.INSTANCE.setErrorTerminationFunction(LispInterpreterFixture::terminateFromError);
LispInterpreterBuilder.INSTANCE.setLanguageFileNames(LispMain.Companion.getLANGUAGE_FILE_NAMES());
// LispInterpreterBuilder.INSTANCE.setTerminationFunction(LispInterpreterFixture::terminate);
// LispInterpreterBuilder.INSTANCE.setErrorTerminationFunction(LispInterpreterFixture::terminateFromError);
interpreter = LispInterpreterBuilder.INSTANCE.build();
}

View File

@ -3,8 +3,6 @@ package application;
import com.googlecode.lanterna.terminal.virtual.DefaultVirtualTerminal;
import environment.RuntimeEnvironment;
import interpreter.LispInterpreterBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
@ -18,10 +16,6 @@ import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.CountDownLatch;
import static application.LispMain.ANSI_GREEN;
import static application.LispMain.ANSI_PURPLE;
import static application.LispMain.ANSI_RESET;
import static application.LispMain.GREETING;
import static com.googlecode.lanterna.input.KeyType.Enter;
import static java.text.MessageFormat.format;
import static org.junit.Assert.assertEquals;
@ -79,7 +73,7 @@ public class MainTest extends SymbolAndFunctionCleaner {
}
private String getExpectedGreeting() {
return format(GREETING, getClass().getPackage().getImplementationVersion());
return format(LispMain.Companion.getGREETING(), getClass().getPackage().getImplementationVersion());
}
@Rule
@ -109,7 +103,10 @@ public class MainTest extends SymbolAndFunctionCleaner {
exit.expectSystemExitWithStatus(1);
exit.checkAssertionAfterwards(() -> {
assertEquals(format("{0}{1}{2}\n", ANSI_PURPLE, expectedMessage, ANSI_RESET), getSystemErrLog());
assertEquals(format("{0}{1}{2}\n",
LispMain.Companion.getANSI_PURPLE(),
expectedMessage,
LispMain.Companion.getANSI_RESET()), getSystemErrLog());
assertEquals("", getSystemOutLog());
});
@ -121,7 +118,10 @@ public class MainTest extends SymbolAndFunctionCleaner {
runInterpreterWithFile(FILE);
assertEquals("", getSystemErrLog());
assertEquals(format("{0}{1}{2}\n\n", ANSI_GREEN, "RADISH", ANSI_RESET), getSystemOutLog());
assertEquals(format("{0}{1}{2}\n\n",
LispMain.Companion.getANSI_GREEN(),
"RADISH",
LispMain.Companion.getANSI_RESET()), getSystemOutLog());
}
@Test
@ -142,9 +142,12 @@ public class MainTest extends SymbolAndFunctionCleaner {
@Test
public void runMain() {
LispMain.main(new String[] { FILE });
LispMain.Companion.main(new String[] { FILE });
assertEquals("", getSystemErrLog());
assertEquals(format("{0}{1}{2}\n\n", ANSI_GREEN, "RADISH", ANSI_RESET), getSystemOutLog());
assertEquals(format("{0}{1}{2}\n\n",
LispMain.Companion.getANSI_GREEN(),
"RADISH",
LispMain.Companion.getANSI_RESET()), getSystemOutLog());
}
}

View File

@ -3,13 +3,11 @@ package environment
import error.ErrorManager
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import java.util.HashSet
import java.util.function.Function
@TestInstance(PER_CLASS)
class RuntimeEnvironmentTest {
@ -77,7 +75,7 @@ class RuntimeEnvironmentTest {
@Test
fun `assign a termination function`() {
RuntimeEnvironment.terminationFunction = Runnable { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.terminationFunction = { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.terminateSuccessfully()
assertThat(indicatorSet.contains(TERMINATED_SUCCESSFULLY)).isTrue()
@ -85,7 +83,7 @@ class RuntimeEnvironmentTest {
@Test
fun `assign an error termination function`() {
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.terminateExceptionally()
assertThat(indicatorSet.contains(TERMINATED_EXCEPTIONALLY)).isTrue()
@ -93,35 +91,35 @@ class RuntimeEnvironmentTest {
@Test
fun `assing a prompt decorator`() {
RuntimeEnvironment.promptDecorator = Function { s -> "[$s]" }
RuntimeEnvironment.promptDecorator = { "[$it]" }
assertThat(RuntimeEnvironment.decoratePrompt("test")).isEqualTo("[test]")
}
@Test
fun `assign a value output decorator`() {
RuntimeEnvironment.valueOutputDecorator = Function { s -> "($s)" }
RuntimeEnvironment.valueOutputDecorator = { "($it)" }
assertThat(RuntimeEnvironment.decorateValueOutput("test")).isEqualTo("(test)")
}
@Test
fun `assign a warning output decorator`() {
RuntimeEnvironment.warningOutputDecorator = Function { s -> "|$s|" }
RuntimeEnvironment.warningOutputDecorator = { "|$it|" }
assertThat(RuntimeEnvironment.decorateWarningOutput("test")).isEqualTo("|test|")
}
@Test
fun `assign an error output decorator`() {
RuntimeEnvironment.errorOutputDecorator = Function { s -> "{$s}" }
RuntimeEnvironment.errorOutputDecorator = { "{$it}" }
assertThat(RuntimeEnvironment.decorateErrorOutput("test")).isEqualTo("{test}")
}
@Test
fun `assign a critical output decorator`() {
RuntimeEnvironment.criticalOutputDecorator = Function { s -> "/$s/" }
RuntimeEnvironment.criticalOutputDecorator = { "/$it/" }
assertThat(RuntimeEnvironment.decorateCriticalOutput("test")).isEqualTo("/test/")
}
@ -134,13 +132,13 @@ class RuntimeEnvironmentTest {
RuntimeEnvironment.errorOutput = System.err
RuntimeEnvironment.errorManager = ErrorManager()
RuntimeEnvironment.path = "testpath/"
RuntimeEnvironment.terminationFunction = Runnable { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.promptDecorator = Function { s -> "[$s]" }
RuntimeEnvironment.valueOutputDecorator = Function { s -> "($s)" }
RuntimeEnvironment.warningOutputDecorator = Function { s -> "|$s|" }
RuntimeEnvironment.errorOutputDecorator = Function { s -> "{$s}" }
RuntimeEnvironment.criticalOutputDecorator = Function { s -> "/$s/" }
RuntimeEnvironment.terminationFunction = { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.promptDecorator = { "[$it]" }
RuntimeEnvironment.valueOutputDecorator = { "($it)" }
RuntimeEnvironment.warningOutputDecorator = { "|$it|" }
RuntimeEnvironment.errorOutputDecorator = { "{$it}" }
RuntimeEnvironment.criticalOutputDecorator = { "/$it/" }
RuntimeEnvironment.reset()
assertThat(RuntimeEnvironment.inputName).isNull()
@ -150,12 +148,12 @@ class RuntimeEnvironmentTest {
assertThat(RuntimeEnvironment.errorManager).isNull()
assertThat(RuntimeEnvironment.path).isNull()
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateSuccessfully() }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateExceptionally() }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decoratePrompt("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateValueOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateWarningOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateErrorOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateCriticalOutput("") }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateSuccessfully() }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateExceptionally() }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decoratePrompt("") }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateValueOutput("") }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateWarningOutput("") }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateErrorOutput("") }
// assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateCriticalOutput("") }
}
}

View File

@ -11,7 +11,6 @@ import org.junit.jupiter.api.Test
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.util.HashSet
import java.util.function.Function
class ErrorManagerTest {
@ -25,12 +24,12 @@ class ErrorManagerTest {
private val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
private fun createErrorManagerWithIndicators(): ErrorManager {
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED) }
RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED) }
RuntimeEnvironment.errorOutput = PrintStream(errorOutputStream)
RuntimeEnvironment.output = PrintStream(outputStream)
RuntimeEnvironment.warningOutputDecorator = Function { s -> s }
RuntimeEnvironment.errorOutputDecorator = Function { s -> s }
RuntimeEnvironment.criticalOutputDecorator = Function { s -> s }
RuntimeEnvironment.warningOutputDecorator = { it }
RuntimeEnvironment.errorOutputDecorator = { it }
RuntimeEnvironment.criticalOutputDecorator = { it }
return ErrorManager()
}

View File

@ -1,60 +0,0 @@
package function.builtin;
import environment.RuntimeEnvironment;
import function.ArgumentValidator.TooManyArgumentsException;
import org.junit.Test;
import testutil.SymbolAndFunctionCleaner;
import java.util.HashSet;
import java.util.Set;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static testutil.TestUtilities.evaluateString;
public class EXITTest extends SymbolAndFunctionCleaner {
private static final String TERMINATED = "terminated";
private RuntimeEnvironment environment;
private Set<String> indicatorSet;
public EXITTest() {
this.environment = RuntimeEnvironment.INSTANCE;
}
private void assertTerminated() {
assertTrue(indicatorSet.contains(TERMINATED));
}
private void assertNotTerminated() {
assertFalse(indicatorSet.contains(TERMINATED));
}
@Override
public void additionalSetUp() {
indicatorSet = new HashSet<>();
environment.reset();
environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED));
}
@Override
public void additionalTearDown() {
environment.reset();
}
@Test
public void exitWorks() {
evaluateString("(exit)");
assertTerminated();
}
@Test
public void exitNotCalled_IndicatorSetIsClean() {
assertNotTerminated();
}
@Test(expected = TooManyArgumentsException.class)
public void exitWithTooManyArguments() {
evaluateString("(exit 1)");
}
}

View File

@ -0,0 +1,58 @@
package function.builtin
import environment.RuntimeEnvironment
import function.ArgumentValidator.TooManyArgumentsException
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import testutil.SymbolAndFunctionCleaner
import testutil.TestUtilities.evaluateString
import java.util.HashSet
class EXITTest : SymbolAndFunctionCleaner() {
private val environment: RuntimeEnvironment
private var indicatorSet: MutableSet<String>? = null
init {
this.environment = RuntimeEnvironment
}
private fun assertTerminated() {
assertTrue(indicatorSet!!.contains(TERMINATED))
}
private fun assertNotTerminated() {
assertFalse(indicatorSet!!.contains(TERMINATED))
}
override fun additionalSetUp() {
indicatorSet = HashSet()
environment.reset()
environment.terminationFunction = { indicatorSet!!.add(TERMINATED) }
}
override fun additionalTearDown() {
environment.reset()
}
@Test
fun exitWorks() {
evaluateString("(exit)")
assertTerminated()
}
@Test
fun exitNotCalled_IndicatorSetIsClean() {
assertNotTerminated()
}
@Test(expected = TooManyArgumentsException::class)
fun exitWithTooManyArguments() {
evaluateString("(exit 1)")
}
companion object {
private val TERMINATED = "terminated"
}
}

View File

@ -1,162 +0,0 @@
package interpreter;
import environment.RuntimeEnvironment;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;
import static interpreter.InteractiveLispInterpreter.PROMPT;
import static java.text.MessageFormat.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static testutil.TestUtilities.createInputStreamFromString;
public class LispInterpreterTest {
private static final String TERMINATED = "terminated";
private static final String FILE = LispInterpreterTest.class.getResource("file.lisp").getFile();
private Set<String> indicatorSet;
private ByteArrayOutputStream outputStream;
private ByteArrayOutputStream errorOutputStream;
private RuntimeEnvironment environment;
private LispInterpreterBuilder builder;
public LispInterpreterTest() {
this.environment = RuntimeEnvironment.INSTANCE;
this.builder = LispInterpreterBuilder.INSTANCE;
}
private void setCommonFeatures() {
builder.setOutput(new PrintStream(outputStream));
builder.setErrorOutput(new PrintStream(errorOutputStream));
builder.setTerminationFunction(() -> {});
builder.setErrorTerminationFunction(() -> indicatorSet.add(TERMINATED));
}
private void assertTerminated() {
assertTrue(indicatorSet.contains(TERMINATED));
}
private void assertErrorMessageWritten() {
assertTrue(errorOutputStream.toByteArray().length > 0);
}
@Before
public void setUp() {
indicatorSet = new HashSet<>();
outputStream = new ByteArrayOutputStream();
errorOutputStream = new ByteArrayOutputStream();
environment.reset();
builder.reset();
}
@After
public void tearDown() {
environment.reset();
builder.reset();
}
@Test
public void buildInteractiveInterpreter() {
setCommonFeatures();
builder.setInput(System.in, "stdin");
LispInterpreter interpreter = builder.build();
assertTrue(interpreter instanceof InteractiveLispInterpreter);
}
@Test
public void buildNonInteractiveInterpreter() {
setCommonFeatures();
builder.setInput(System.in, "stdin");
builder.setNotInteractive();
LispInterpreter interpreter = builder.build();
assertFalse(interpreter instanceof InteractiveLispInterpreter);
assertFalse(interpreter instanceof FileLispInterpreter);
}
@Test
public void buildFileBasedInterpreter() {
setCommonFeatures();
builder.useFile(FILE);
LispInterpreter interpreter = builder.build();
assertTrue(interpreter instanceof FileLispInterpreter);
}
@Test
public void attemptToBuildInterpreterOnBadFile() {
setCommonFeatures();
builder.useFile("does-not-exist.lisp");
builder.build();
assertErrorMessageWritten();
assertTerminated();
}
@Test
public void makeSureDecoratorsAreInitializedWithDefaults() {
builder.build();
assertEquals("", environment.decoratePrompt(""));
assertEquals("", environment.decorateValueOutput(""));
assertEquals("", environment.decorateWarningOutput(""));
assertEquals("", environment.decorateErrorOutput(""));
assertEquals("", environment.decorateCriticalOutput(""));
}
@Test
public void makeSureDecoratorsAreSetCorrectly() {
builder.setPromptDecorator(s -> "#" + s + "#");
builder.setValueOutputDecorator(s -> "@" + s + "@");
builder.setWarningOutputDecorator(s -> "%" + s + "%");
builder.setErrorOutputDecorator(s -> "*" + s + "*");
builder.setCriticalOutputDecorator(s -> "$" + s + "$");
builder.build();
assertEquals("#x#", environment.decoratePrompt("x"));
assertEquals("@x@", environment.decorateValueOutput("x"));
assertEquals("%x%", environment.decorateWarningOutput("x"));
assertEquals("*x*", environment.decorateErrorOutput("x"));
assertEquals("$x$", environment.decorateCriticalOutput("x"));
}
@Test
public void fileBasedInterpreterWorks_PrintsLastValueOnly() {
setCommonFeatures();
builder.useFile(FILE);
builder.build().interpret();
assertEquals("PICKLE\n\n", outputStream.toString());
assertEquals("", errorOutputStream.toString());
}
@Test
public void interactiveInterpreterWorks() {
setCommonFeatures();
builder.setInput(createInputStreamFromString("'pickle"), "input");
builder.build().interpret();
assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream.toString());
assertEquals("", errorOutputStream.toString());
}
@Test
public void interpreterHandlesError() {
setCommonFeatures();
builder.setNotInteractive();
builder.setInput(createInputStreamFromString("pickle"), "input");
builder.build().interpret();
assertEquals("\n", outputStream.toString());
assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream.toString());
}
}

View File

@ -0,0 +1,162 @@
package interpreter
import environment.RuntimeEnvironment
import interpreter.InteractiveLispInterpreter.PROMPT
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import testutil.TestUtilities.createInputStreamFromString
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.text.MessageFormat.format
import java.util.HashSet
class LispInterpreterTest {
private var indicatorSet: MutableSet<String>? = null
private var outputStream: ByteArrayOutputStream? = null
private var errorOutputStream: ByteArrayOutputStream? = null
private val environment: RuntimeEnvironment
private val builder: LispInterpreterBuilder
init {
this.environment = RuntimeEnvironment
this.builder = LispInterpreterBuilder
}
private fun setCommonFeatures() {
builder.setOutput(PrintStream(outputStream!!))
builder.setErrorOutput(PrintStream(errorOutputStream!!))
builder.setTerminationFunction { }
builder.setErrorTerminationFunction { indicatorSet!!.add(TERMINATED) }
}
private fun assertTerminated() {
assertTrue(indicatorSet!!.contains(TERMINATED))
}
private fun assertErrorMessageWritten() {
assertTrue(errorOutputStream!!.toByteArray().size > 0)
}
@Before
fun setUp() {
indicatorSet = HashSet()
outputStream = ByteArrayOutputStream()
errorOutputStream = ByteArrayOutputStream()
environment.reset()
builder.reset()
}
@After
fun tearDown() {
environment.reset()
builder.reset()
}
@Test
fun buildInteractiveInterpreter() {
setCommonFeatures()
builder.setInput(System.`in`, "stdin")
val interpreter = builder.build()
assertTrue(interpreter is InteractiveLispInterpreter)
}
@Test
fun buildNonInteractiveInterpreter() {
setCommonFeatures()
builder.setInput(System.`in`, "stdin")
builder.setNotInteractive()
val interpreter = builder.build()
assertFalse(interpreter is InteractiveLispInterpreter)
assertFalse(interpreter is FileLispInterpreter)
}
@Test
fun buildFileBasedInterpreter() {
setCommonFeatures()
builder.useFile(FILE)
val interpreter = builder.build()
assertTrue(interpreter is FileLispInterpreter)
}
@Test
fun attemptToBuildInterpreterOnBadFile() {
setCommonFeatures()
builder.useFile("does-not-exist.lisp")
builder.build()
assertErrorMessageWritten()
assertTerminated()
}
@Test
fun makeSureDecoratorsAreInitializedWithDefaults() {
builder.build()
assertEquals("", environment.decoratePrompt(""))
assertEquals("", environment.decorateValueOutput(""))
assertEquals("", environment.decorateWarningOutput(""))
assertEquals("", environment.decorateErrorOutput(""))
assertEquals("", environment.decorateCriticalOutput(""))
}
@Test
fun makeSureDecoratorsAreSetCorrectly() {
builder.setPromptDecorator { s -> "#$s#" }
builder.setValueOutputDecorator { s -> "@$s@" }
builder.setWarningOutputDecorator { s -> "%$s%" }
builder.setErrorOutputDecorator { s -> "*$s*" }
builder.setCriticalOutputDecorator { s -> "$$s$" }
builder.build()
assertEquals("#x#", environment.decoratePrompt("x"))
assertEquals("@x@", environment.decorateValueOutput("x"))
assertEquals("%x%", environment.decorateWarningOutput("x"))
assertEquals("*x*", environment.decorateErrorOutput("x"))
assertEquals("\$x$", environment.decorateCriticalOutput("x"))
}
@Test
fun fileBasedInterpreterWorks_PrintsLastValueOnly() {
setCommonFeatures()
builder.useFile(FILE)
builder.build().interpret()
assertEquals("PICKLE\n\n", outputStream!!.toString())
assertEquals("", errorOutputStream!!.toString())
}
@Test
fun interactiveInterpreterWorks() {
setCommonFeatures()
builder.setInput(createInputStreamFromString("'pickle"), "input")
builder.build().interpret()
assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream!!.toString())
assertEquals("", errorOutputStream!!.toString())
}
@Test
fun interpreterHandlesError() {
setCommonFeatures()
builder.setNotInteractive()
builder.setInput(createInputStreamFromString("pickle"), "input")
builder.build().interpret()
assertEquals("\n", outputStream!!.toString())
assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream!!.toString())
}
companion object {
private val TERMINATED = "terminated"
private val FILE = LispInterpreterTest::class.java.getResource("file.lisp").file
}
}