package prolog.builtins import io.Logger import io.Terminal import parser.ReplParser import prolog.Answers import prolog.ast.Database.Program import prolog.Substitutions import prolog.ast.logic.Satisfiable import prolog.ast.terms.Atom import prolog.ast.terms.Operator import prolog.ast.terms.Term import prolog.logic.applySubstitution import prolog.logic.unifyLazy /** * Write [Term] to the current output, using brackets and operators where appropriate. */ class Write(private val term: Term) : Operator(Atom("write"), null, term), Satisfiable { override fun satisfy(subs: Substitutions): Answers { val t = applySubstitution(term, subs) Terminal().say(t.toString()) Program.storeNewLine = true return sequenceOf(Result.success(emptyMap())) } override fun toString(): String = "write($term)" } /** * Write a newline character to the current output stream. */ object Nl : Atom("nl"), Satisfiable { override fun satisfy(subs: Substitutions): Answers { Terminal().say("\n") Program.storeNewLine = false return sequenceOf(Result.success(emptyMap())) } } /** * Read the next Prolog term from the current input stream and unify it with [Term]. * * On reaching end-of-file, [Term] is unified with the [Atom] `end_of_file`. */ class Read(private val term: Term) : Operator(Atom("read"), null, term), Satisfiable { private val io = Terminal() private val parser = ReplParser() private fun readTerm(): Term { val input = io.readLine() Logger.debug("Read input: $input") return when (input) { "end_of_file" -> Atom("end_of_file") else -> { val out = parser.parse(input).query Logger.debug("Parsed input: $out") out as? Term ?: throw IllegalArgumentException("Expected a term, but got: $out") } } } override fun satisfy(subs: Substitutions): Answers = sequence { val t1 = applySubstitution(term, subs) val t2 = readTerm() Logger.debug("Read term: $t2") yieldAll(unifyLazy(t1, t2, subs)) } }