package interpreter import environment.RuntimeEnvironment 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 { private var inputName = "" private var isInteractive = true private var isFileBased = false private var languageFiles = ArrayList() private var promptDecorator = Function { s -> s } private var valueOutputDecorator = Function { s -> s } private var warningOutputDecorator = Function { s -> s } private var errorOutputDecorator = Function { s -> s } private var criticalOutputDecorator = Function { 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 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 } } fun setInput(inputStream: InputStream, inputName: String) { this.inputStream = inputStream this.inputName = inputName } fun setOutput(outputStream: PrintStream) { this.outputStream = outputStream } fun setErrorOutput(errorOutputStream: PrintStream) { 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 this.setNotInteractive() } fun setLanguageFileNames(vararg languageFiles: String) { val classLoader = javaClass.classLoader this.languageFiles = ArrayList() for (fileName in languageFiles) this.languageFiles!!.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName)) } fun setPromptDecorator(decorator: Function) { this.promptDecorator = decorator } fun setValueOutputDecorator(decorator: Function) { this.valueOutputDecorator = decorator } fun setWarningOutputDecorator(decorator: Function) { this.warningOutputDecorator = decorator } fun setErrorOutputDecorator(decorator: Function) { this.errorOutputDecorator = decorator } fun setCriticalOutputDecorator(decorator: Function) { this.criticalOutputDecorator = decorator } fun build(): LispInterpreter { configureRuntimeEnvironment() val lispInterpreter = createInterpreter() lispInterpreter.interpretLanguageFiles(languageFiles) return lispInterpreter } private fun configureRuntimeEnvironment() { val errorManager = ErrorManager() RuntimeEnvironment.output = outputStream RuntimeEnvironment.errorOutput = errorOutputStream RuntimeEnvironment.errorManager = errorManager RuntimeEnvironment.terminationFunction = terminationFunction RuntimeEnvironment.errorTerminationFunction = errorTerminationFunction RuntimeEnvironment.promptDecorator = promptDecorator RuntimeEnvironment.valueOutputDecorator = valueOutputDecorator RuntimeEnvironment.warningOutputDecorator = warningOutputDecorator RuntimeEnvironment.errorOutputDecorator = errorOutputDecorator RuntimeEnvironment.criticalOutputDecorator = criticalOutputDecorator configurePath() configureInput(errorManager) } private fun configurePath() { if (isFileBased) RuntimeEnvironment.path = Path.getPathPrefix(inputName!!) else RuntimeEnvironment.path = "" } private fun configureInput(errorManager: ErrorManager) { RuntimeEnvironment.inputName = inputName try { RuntimeEnvironment.input = getInputStream() } catch (e: FileNotFoundException) { errorManager.handle(LispFileNotFoundException(e)) } } private fun getInputStream() = if (isFileBased) FileInputStream(inputName) else inputStream private fun createInterpreter(): LispInterpreter { if (isFileBased) return FileLispInterpreter() else if (isInteractive) return InteractiveLispInterpreter() return LispInterpreter() } class LispFileNotFoundException(val e: FileNotFoundException) : CriticalLispException() { override val message: String get() = e.message ?: "" } }