117 lines
3 KiB
Kotlin
117 lines
3 KiB
Kotlin
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}"
|
|
}
|
|
)
|
|
}
|
|
}
|