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

View File

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

View File

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

View File

@ -3,8 +3,6 @@ package application;
import com.googlecode.lanterna.terminal.virtual.DefaultVirtualTerminal; import com.googlecode.lanterna.terminal.virtual.DefaultVirtualTerminal;
import environment.RuntimeEnvironment; import environment.RuntimeEnvironment;
import interpreter.LispInterpreterBuilder; import interpreter.LispInterpreterBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.contrib.java.lang.system.ExpectedSystemExit; import org.junit.contrib.java.lang.system.ExpectedSystemExit;
@ -18,10 +16,6 @@ import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.util.concurrent.CountDownLatch; 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 com.googlecode.lanterna.input.KeyType.Enter;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -79,7 +73,7 @@ public class MainTest extends SymbolAndFunctionCleaner {
} }
private String getExpectedGreeting() { private String getExpectedGreeting() {
return format(GREETING, getClass().getPackage().getImplementationVersion()); return format(LispMain.Companion.getGREETING(), getClass().getPackage().getImplementationVersion());
} }
@Rule @Rule
@ -109,7 +103,10 @@ public class MainTest extends SymbolAndFunctionCleaner {
exit.expectSystemExitWithStatus(1); exit.expectSystemExitWithStatus(1);
exit.checkAssertionAfterwards(() -> { 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()); assertEquals("", getSystemOutLog());
}); });
@ -121,7 +118,10 @@ public class MainTest extends SymbolAndFunctionCleaner {
runInterpreterWithFile(FILE); runInterpreterWithFile(FILE);
assertEquals("", getSystemErrLog()); 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 @Test
@ -142,9 +142,12 @@ public class MainTest extends SymbolAndFunctionCleaner {
@Test @Test
public void runMain() { public void runMain() {
LispMain.main(new String[] { FILE }); LispMain.Companion.main(new String[] { FILE });
assertEquals("", getSystemErrLog()); 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 error.ErrorManager
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import java.util.HashSet import java.util.HashSet
import java.util.function.Function
@TestInstance(PER_CLASS) @TestInstance(PER_CLASS)
class RuntimeEnvironmentTest { class RuntimeEnvironmentTest {
@ -77,7 +75,7 @@ class RuntimeEnvironmentTest {
@Test @Test
fun `assign a termination function`() { fun `assign a termination function`() {
RuntimeEnvironment.terminationFunction = Runnable { indicatorSet.add(TERMINATED_SUCCESSFULLY) } RuntimeEnvironment.terminationFunction = { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.terminateSuccessfully() RuntimeEnvironment.terminateSuccessfully()
assertThat(indicatorSet.contains(TERMINATED_SUCCESSFULLY)).isTrue() assertThat(indicatorSet.contains(TERMINATED_SUCCESSFULLY)).isTrue()
@ -85,7 +83,7 @@ class RuntimeEnvironmentTest {
@Test @Test
fun `assign an error termination function`() { fun `assign an error termination function`() {
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED_EXCEPTIONALLY) } RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.terminateExceptionally() RuntimeEnvironment.terminateExceptionally()
assertThat(indicatorSet.contains(TERMINATED_EXCEPTIONALLY)).isTrue() assertThat(indicatorSet.contains(TERMINATED_EXCEPTIONALLY)).isTrue()
@ -93,35 +91,35 @@ class RuntimeEnvironmentTest {
@Test @Test
fun `assing a prompt decorator`() { fun `assing a prompt decorator`() {
RuntimeEnvironment.promptDecorator = Function { s -> "[$s]" } RuntimeEnvironment.promptDecorator = { "[$it]" }
assertThat(RuntimeEnvironment.decoratePrompt("test")).isEqualTo("[test]") assertThat(RuntimeEnvironment.decoratePrompt("test")).isEqualTo("[test]")
} }
@Test @Test
fun `assign a value output decorator`() { fun `assign a value output decorator`() {
RuntimeEnvironment.valueOutputDecorator = Function { s -> "($s)" } RuntimeEnvironment.valueOutputDecorator = { "($it)" }
assertThat(RuntimeEnvironment.decorateValueOutput("test")).isEqualTo("(test)") assertThat(RuntimeEnvironment.decorateValueOutput("test")).isEqualTo("(test)")
} }
@Test @Test
fun `assign a warning output decorator`() { fun `assign a warning output decorator`() {
RuntimeEnvironment.warningOutputDecorator = Function { s -> "|$s|" } RuntimeEnvironment.warningOutputDecorator = { "|$it|" }
assertThat(RuntimeEnvironment.decorateWarningOutput("test")).isEqualTo("|test|") assertThat(RuntimeEnvironment.decorateWarningOutput("test")).isEqualTo("|test|")
} }
@Test @Test
fun `assign an error output decorator`() { fun `assign an error output decorator`() {
RuntimeEnvironment.errorOutputDecorator = Function { s -> "{$s}" } RuntimeEnvironment.errorOutputDecorator = { "{$it}" }
assertThat(RuntimeEnvironment.decorateErrorOutput("test")).isEqualTo("{test}") assertThat(RuntimeEnvironment.decorateErrorOutput("test")).isEqualTo("{test}")
} }
@Test @Test
fun `assign a critical output decorator`() { fun `assign a critical output decorator`() {
RuntimeEnvironment.criticalOutputDecorator = Function { s -> "/$s/" } RuntimeEnvironment.criticalOutputDecorator = { "/$it/" }
assertThat(RuntimeEnvironment.decorateCriticalOutput("test")).isEqualTo("/test/") assertThat(RuntimeEnvironment.decorateCriticalOutput("test")).isEqualTo("/test/")
} }
@ -134,13 +132,13 @@ class RuntimeEnvironmentTest {
RuntimeEnvironment.errorOutput = System.err RuntimeEnvironment.errorOutput = System.err
RuntimeEnvironment.errorManager = ErrorManager() RuntimeEnvironment.errorManager = ErrorManager()
RuntimeEnvironment.path = "testpath/" RuntimeEnvironment.path = "testpath/"
RuntimeEnvironment.terminationFunction = Runnable { indicatorSet.add(TERMINATED_SUCCESSFULLY) } RuntimeEnvironment.terminationFunction = { indicatorSet.add(TERMINATED_SUCCESSFULLY) }
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED_EXCEPTIONALLY) } RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED_EXCEPTIONALLY) }
RuntimeEnvironment.promptDecorator = Function { s -> "[$s]" } RuntimeEnvironment.promptDecorator = { "[$it]" }
RuntimeEnvironment.valueOutputDecorator = Function { s -> "($s)" } RuntimeEnvironment.valueOutputDecorator = { "($it)" }
RuntimeEnvironment.warningOutputDecorator = Function { s -> "|$s|" } RuntimeEnvironment.warningOutputDecorator = { "|$it|" }
RuntimeEnvironment.errorOutputDecorator = Function { s -> "{$s}" } RuntimeEnvironment.errorOutputDecorator = { "{$it}" }
RuntimeEnvironment.criticalOutputDecorator = Function { s -> "/$s/" } RuntimeEnvironment.criticalOutputDecorator = { "/$it/" }
RuntimeEnvironment.reset() RuntimeEnvironment.reset()
assertThat(RuntimeEnvironment.inputName).isNull() assertThat(RuntimeEnvironment.inputName).isNull()
@ -150,12 +148,12 @@ class RuntimeEnvironmentTest {
assertThat(RuntimeEnvironment.errorManager).isNull() assertThat(RuntimeEnvironment.errorManager).isNull()
assertThat(RuntimeEnvironment.path).isNull() assertThat(RuntimeEnvironment.path).isNull()
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateSuccessfully() } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateSuccessfully() }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateExceptionally() } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.terminateExceptionally() }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decoratePrompt("") } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decoratePrompt("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateValueOutput("") } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateValueOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateWarningOutput("") } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateWarningOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateErrorOutput("") } // assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateErrorOutput("") }
assertThrows(NullPointerException::class.java) { RuntimeEnvironment.decorateCriticalOutput("") } // 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.ByteArrayOutputStream
import java.io.PrintStream import java.io.PrintStream
import java.util.HashSet import java.util.HashSet
import java.util.function.Function
class ErrorManagerTest { class ErrorManagerTest {
@ -25,12 +24,12 @@ class ErrorManagerTest {
private val outputStream: ByteArrayOutputStream = ByteArrayOutputStream() private val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
private fun createErrorManagerWithIndicators(): ErrorManager { private fun createErrorManagerWithIndicators(): ErrorManager {
RuntimeEnvironment.errorTerminationFunction = Runnable { indicatorSet.add(TERMINATED) } RuntimeEnvironment.errorTerminationFunction = { indicatorSet.add(TERMINATED) }
RuntimeEnvironment.errorOutput = PrintStream(errorOutputStream) RuntimeEnvironment.errorOutput = PrintStream(errorOutputStream)
RuntimeEnvironment.output = PrintStream(outputStream) RuntimeEnvironment.output = PrintStream(outputStream)
RuntimeEnvironment.warningOutputDecorator = Function { s -> s } RuntimeEnvironment.warningOutputDecorator = { it }
RuntimeEnvironment.errorOutputDecorator = Function { s -> s } RuntimeEnvironment.errorOutputDecorator = { it }
RuntimeEnvironment.criticalOutputDecorator = Function { s -> s } RuntimeEnvironment.criticalOutputDecorator = { it }
return ErrorManager() 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
}
}