diff --git a/src/Main.kt b/src/Main.kt index 88278c2..38efc51 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -1,14 +1,7 @@ -import better_parser.PrologParser import better_parser.SimpleReplParser import interpreter.SourceFileReader import prolog.Answer -import prolog.Program -import prolog.ast.logic.Fact -import prolog.ast.logic.Rule -import prolog.ast.terms.Atom -import prolog.ast.terms.CompoundTerm -import prolog.ast.terms.Variable -import prolog.builtins.Conjunction +import kotlin.system.exitProcess fun help(): String { println("Unknown command. Type 'h' for help.") @@ -27,10 +20,26 @@ fun say(message: String) { fun prompt(message: String): String { print("$message ") - var input: String = readlnOrNull() ?: help() - while (input.isBlank()) { - input = readlnOrNull() ?: help() + var input = readlnOrNull() + + while (input.isNullOrBlank()) { + if (input == null) { + println("Exiting Prolog REPL.") + exitProcess(0) + } + + if (input.isBlank()) { + print("$message ") + } + + input = readlnOrNull() } + + if (input == "exit") { + println("Exiting Prolog REPL.") + exitProcess(0) + } + return input } diff --git a/src/prolog/builtins/arithmeticOperators.kt b/src/prolog/builtins/arithmeticOperators.kt index 2463313..2636bf6 100644 --- a/src/prolog/builtins/arithmeticOperators.kt +++ b/src/prolog/builtins/arithmeticOperators.kt @@ -11,6 +11,23 @@ import prolog.ast.terms.* import prolog.logic.* // TODO > +class GreaterThan(private val left: Expression, private val right: Expression) : + Operator(Atom(">"), left, right), Satisfiable { + override fun satisfy(subs: Substitutions): Answers { + val t1 = left.simplify(subs) + val t2 = right.simplify(subs) + + if (!atomic(t1.to, subs) || !atomic(t2.to, subs)) { + return sequenceOf(Result.failure(IllegalArgumentException("Both operands must be instantiated"))) + } + + return if (0 < compare(t1.to, t2.to, subs)) { + sequenceOf(Result.success(emptyMap())) + } else { + emptySequence() + } + } +} // TODO < diff --git a/tests/better_parser/resources/parent.pl b/tests/better_parser/resources/parent.pl index 51178c4..8ac4196 100644 --- a/tests/better_parser/resources/parent.pl +++ b/tests/better_parser/resources/parent.pl @@ -6,4 +6,5 @@ parent(mary, jimmy). father(X, Y) :- parent(X, Y), male(X). mother(X, Y) :- parent(X, Y), female(X). -kan_goed_koken(miriam). \ No newline at end of file +foo(0). +foo(X) :- X > 0, Y is X - 1, foo(Y). diff --git a/tests/prolog/EvaluationTests.kt b/tests/prolog/EvaluationTests.kt index 6fd5fe5..e8ce952 100644 --- a/tests/prolog/EvaluationTests.kt +++ b/tests/prolog/EvaluationTests.kt @@ -3,15 +3,14 @@ package prolog import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import prolog.ast.arithmetic.Integer import prolog.ast.logic.Fact import prolog.ast.logic.Rule -import prolog.builtins.Conjunction -import prolog.builtins.Disjunction -import prolog.builtins.Query import prolog.logic.equivalent import prolog.ast.terms.Atom import prolog.ast.terms.Structure import prolog.ast.terms.Variable +import prolog.builtins.* class EvaluationTests { @BeforeEach @@ -215,4 +214,33 @@ class EvaluationTests { assertTrue(expectedResults[i].all { actualResults[i].getOrNull()!![it.key]?.let { it1 -> equivalent(it.value, it1, emptyMap()) } ?: false }, "Substitution values should match") } } + + /** + foo(0). + foo(X) :- X > 0, Y is X - 1, foo(Y). + */ + @Test + fun recursive_query() { + val fact = Fact(Structure(Atom("foo"), listOf(Integer(0)))) + val rule = Rule( + Structure(Atom("foo"), listOf(Variable("X"))), + Conjunction( + GreaterThan(Variable("X"), Integer(0)), + Conjunction( + Is(Variable("Y"), Subtract(Variable("X"), Integer(1))), + Structure(Atom("foo"), listOf(Variable("Y"))) + ) + ) + ) + + Program.load(listOf(fact, rule)) + + val result = Program.query(Structure(Atom("foo"), listOf(Integer(0)))).toList() + + val result5 = Program.query(Structure(Atom("foo"), listOf(Integer(5)))).toList() + + assertTrue(Program.query(Structure(Atom("foo"), listOf(Atom("1")))).any()) + assertTrue(Program.query(Structure(Atom("foo"), listOf(Atom("2")))).any()) + assertFalse(Program.query(Structure(Atom("foo"), listOf(Atom("-1")))).any()) + } } \ No newline at end of file