package repl import interpreter.Preprocessor import io.Logger import io.Terminal import parser.ReplParser import prolog.Answer import prolog.Answers import prolog.flags.AppliedCut class Repl { private val io = Terminal() private val parser = ReplParser() private val preprocessor = Preprocessor() init { welcome() while (true) { try { printAnswers(query()) } catch (e: Exception) { Logger.error("Error parsing REPL: ${e.message}") } } } private fun welcome() { io.checkNewLine() io.say("Prolog REPL. Type '^D' to quit.\n") } private fun query(): Answers { val queryString = io.prompt("?-", { "| " }, { it.endsWith(".") }) val simpleQuery = parser.parse(queryString) val query = preprocessor.preprocess(simpleQuery) return query.satisfy(emptyMap()) } private fun printAnswers(answers: Answers) { val iterator = answers.iterator() if (!iterator.hasNext()) { io.say("false.\n") return } io.say(prettyPrint(iterator.next())) while (true) { when (io.prompt("")) { ";" -> { try { io.say(prettyPrint(iterator.next())) } catch (_: NoSuchElementException) { break } } "" -> { io.checkNewLine() return } "a" -> { io.checkNewLine() return } "." -> { io.checkNewLine() return } "h" -> { help() io.say("Action?") } else -> { io.say("Unknown action: (h for help)\n") io.say("Action?") } } } io.say("\n") } private fun help(): String { io.say("Commands:\n") io.say(" ; find next solution\n") io.say(" a abort\n") io.say(" . end query\n") io.say(" h help\n") return "" } private fun prettyPrint(result: Answer): String { result.fold( onSuccess = { val subs = result.getOrNull()!! if (subs.isEmpty()) { io.checkNewLine() return "true." } return subs.entries.joinToString(",\n") { "${it.key} = ${it.value}" } }, onFailure = { failure -> if (failure is AppliedCut) { if (failure.subs != null) { return prettyPrint(Result.success(failure.subs)) } return "false." } return "ERROR: ${failure.message}" } ) } }