Clause
This commit is contained in:
parent
752c278cb0
commit
8bda3c5af4
15 changed files with 361 additions and 114 deletions
|
@ -1,20 +1,24 @@
|
|||
package prolog.builtins
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import prolog.ast.Database.Program
|
||||
import prolog.ast.arithmetic.Integer
|
||||
import prolog.ast.logic.Fact
|
||||
import prolog.ast.logic.Rule
|
||||
import prolog.ast.terms.CompoundTerm
|
||||
import prolog.ast.terms.AnonymousVariable
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Variable
|
||||
|
||||
class AnalysingAndConstructionOperatorsTests {
|
||||
class AnalysisOperatorsTests {
|
||||
@Test
|
||||
fun `functor(foo, foo, 0)`() {
|
||||
val functor = Functor(Atom("foo"), Atom("foo"), Integer(0))
|
||||
val functor = FunctorOp(Atom("foo"), Atom("foo"), Integer(0))
|
||||
|
||||
val result = functor.satisfy(emptyMap()).toList()
|
||||
|
||||
|
@ -25,7 +29,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
|
||||
@Test
|
||||
fun `functor(foo(X), foo, Y)`() {
|
||||
val functor = Functor(
|
||||
val functor = FunctorOp(
|
||||
Structure(Atom("foo"), listOf(Variable("X"))),
|
||||
Atom("foo"),
|
||||
Variable("Y")
|
||||
|
@ -43,7 +47,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
@Test
|
||||
fun `functor(foo, X, Y)`() {
|
||||
val atom = Atom("foo")
|
||||
val functor = Functor(atom, Variable("X"), Variable("Y"))
|
||||
val functor = FunctorOp(atom, Variable("X"), Variable("Y"))
|
||||
|
||||
val result = functor.satisfy(emptyMap()).toList()
|
||||
|
||||
|
@ -57,7 +61,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
|
||||
@Test
|
||||
fun `functor(X, foo, 1)`() {
|
||||
val functor = Functor(Variable("X"), Atom("foo"), Integer(1))
|
||||
val functor = FunctorOp(Variable("X"), Atom("foo"), Integer(1))
|
||||
|
||||
val result = functor.satisfy(emptyMap()).toList()
|
||||
|
||||
|
@ -74,7 +78,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
|
||||
@Test
|
||||
fun `functor(foo(a), foo, 0)`() {
|
||||
val functor = Functor(Structure(Atom("foo"), listOf(Atom("a"))), Atom("foo"), Integer(0))
|
||||
val functor = FunctorOp(Structure(Atom("foo"), listOf(Atom("a"))), Atom("foo"), Integer(0))
|
||||
|
||||
val result = functor.satisfy(emptyMap()).toList()
|
||||
|
||||
|
@ -83,7 +87,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
|
||||
@Test
|
||||
fun `functor(foo(X), foo, 0)`() {
|
||||
val functor = Functor(Structure(Atom("foo"), listOf(Variable("X"))), Atom("foo"), Integer(0))
|
||||
val functor = FunctorOp(Structure(Atom("foo"), listOf(Variable("X"))), Atom("foo"), Integer(0))
|
||||
|
||||
val result = functor.satisfy(emptyMap()).toList()
|
||||
|
||||
|
@ -92,7 +96,7 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
|
||||
@Test
|
||||
fun `functor(X, Y, 1)`() {
|
||||
val functor = Functor(Variable("X"), Variable("Y"), Integer(1))
|
||||
val functor = FunctorOp(Variable("X"), Variable("Y"), Integer(1))
|
||||
|
||||
val exception = assertThrows<Exception> {
|
||||
functor.satisfy(emptyMap()).toList()
|
||||
|
@ -233,4 +237,168 @@ class AnalysingAndConstructionOperatorsTests {
|
|||
}
|
||||
assertEquals("Domain error: not_less_than_zero", exception.message)
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class `Clause operator` {
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
Program.reset()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause fact atom without variables`() {
|
||||
Program.load(listOf(Fact(Atom("foo"))))
|
||||
|
||||
val result = ClauseOp(
|
||||
Atom("foo"),
|
||||
True
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "Expected empty substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause fact compound without variables`() {
|
||||
Program.load(
|
||||
listOf(
|
||||
Fact(CompoundTerm(Atom("foo"), listOf(Atom("a"), Atom("b"))))
|
||||
)
|
||||
)
|
||||
|
||||
val result = ClauseOp(
|
||||
CompoundTerm(Atom("foo"), listOf(Atom("a"), Atom("b"))),
|
||||
True
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "Expected empty substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause rule without variables`() {
|
||||
Program.load(listOf(Rule(Atom("foo"), Atom("bar"))))
|
||||
|
||||
val result = ClauseOp(
|
||||
Atom("foo"),
|
||||
Atom("bar")
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertTrue(subs.isEmpty(), "Expected empty substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause fact variable body`() {
|
||||
Program.load(listOf(Fact(Atom("foo"))))
|
||||
|
||||
val variable = Variable("Term")
|
||||
val result = ClauseOp(
|
||||
Atom("foo"),
|
||||
variable
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(1, subs.size, "Expected 1 substitution")
|
||||
assertEquals(True, subs[variable])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause fact with variable head`() {
|
||||
Program.load(
|
||||
listOf(
|
||||
Fact(CompoundTerm(Atom("foo"), listOf(Atom("a"))))
|
||||
)
|
||||
)
|
||||
|
||||
val result = ClauseOp(
|
||||
CompoundTerm(Atom("foo"), listOf(Variable("X"))),
|
||||
True
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(1, subs.size, "Expected 1 substitution")
|
||||
assertEquals(Atom("a"), subs[Variable("X")])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause rule with variable body`() {
|
||||
Program.load(listOf(Rule(Atom("foo"), Atom("bar"))))
|
||||
|
||||
val result = ClauseOp(
|
||||
Atom("foo"),
|
||||
Variable("Term")
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(1, subs.size, "Expected 1 substitution")
|
||||
assertEquals(Atom("bar"), subs[Variable("Term")])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clause fact variable value with backtracking`() {
|
||||
Program.load(
|
||||
listOf(
|
||||
Fact(CompoundTerm(Atom("bar"), listOf(Atom("d")))),
|
||||
Fact(CompoundTerm(Atom("bar"), listOf(Atom("e")))),
|
||||
Fact(CompoundTerm(Atom("foo"), listOf(Atom("a")))),
|
||||
Fact(CompoundTerm(Atom("foo"), listOf(Atom("b")))),
|
||||
Fact(CompoundTerm(Atom("foo"), listOf(Atom("c")))),
|
||||
Rule(
|
||||
CompoundTerm(Atom("foo"), listOf(Variable("X"))),
|
||||
CompoundTerm(Atom("bar"), listOf(Variable("X")))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val x = Variable("X")
|
||||
val term = Variable("Term")
|
||||
|
||||
val result = ClauseOp(
|
||||
CompoundTerm(Atom("foo"), listOf(x)),
|
||||
term
|
||||
).satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(4, result.size, "Expected 4 results")
|
||||
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs1 = result[0].getOrNull()!!
|
||||
assertEquals(2, subs1.size, "Expected 2 substitutions")
|
||||
assertEquals(Atom("a"), subs1[x], "Expected a")
|
||||
assertEquals(True, subs1[term], "Expected True")
|
||||
|
||||
assertTrue(result[1].isSuccess, "Expected success")
|
||||
val subs2 = result[1].getOrNull()!!
|
||||
assertEquals(2, subs2.size, "Expected 2 substitutions")
|
||||
assertEquals(Atom("b"), subs2[x], "Expected b")
|
||||
assertEquals(True, subs2[term], "Expected True")
|
||||
|
||||
assertTrue(result[2].isSuccess, "Expected success")
|
||||
val subs3 = result[2].getOrNull()!!
|
||||
assertEquals(2, subs3.size, "Expected 2 substitutions")
|
||||
assertEquals(Atom("c"), subs3[x], "Expected c")
|
||||
assertEquals(True, subs3[term], "Expected True")
|
||||
|
||||
assertTrue(result[3].isSuccess, "Expected success")
|
||||
val subs4 = result[3].getOrNull()!!
|
||||
assertEquals(1, subs4.size, "Expected 2 substitutions")
|
||||
assertEquals(
|
||||
CompoundTerm(Atom("bar"), listOf(Variable("X"))),
|
||||
subs4[term],
|
||||
"Expected bar(X)"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import prolog.ast.logic.Fact
|
|||
import prolog.ast.logic.Predicate
|
||||
import prolog.ast.logic.Rule
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.FunctorInfo
|
||||
import prolog.ast.terms.Functor
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Variable
|
||||
|
||||
|
@ -39,7 +39,7 @@ class DatabaseOperatorsTests {
|
|||
createAssert(fact).satisfy(emptyMap())
|
||||
|
||||
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
|
||||
assertEquals(fact, Program.db.predicates[FunctorInfo.of("a/_")]!!.clauses[0])
|
||||
assertEquals(fact, Program.db.predicates[Functor.of("a/_")]!!.clauses[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -48,7 +48,7 @@ class DatabaseOperatorsTests {
|
|||
createAssert(fact).satisfy(emptyMap())
|
||||
|
||||
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
|
||||
assertEquals(fact, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[0])
|
||||
assertEquals(fact, Program.db.predicates[Functor.of("a/1")]!!.clauses[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -60,7 +60,7 @@ class DatabaseOperatorsTests {
|
|||
createAssert(rule).satisfy(emptyMap())
|
||||
|
||||
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
|
||||
assertEquals(rule, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[0])
|
||||
assertEquals(rule, Program.db.predicates[Functor.of("a/1")]!!.clauses[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +91,8 @@ class DatabaseOperatorsTests {
|
|||
AssertA(rule2).satisfy(emptyMap())
|
||||
|
||||
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
|
||||
assertEquals(rule2, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[0])
|
||||
assertEquals(rule1, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[1])
|
||||
assertEquals(rule2, Program.db.predicates[Functor.of("a/1")]!!.clauses[0])
|
||||
assertEquals(rule1, Program.db.predicates[Functor.of("a/1")]!!.clauses[1])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,8 +116,8 @@ class DatabaseOperatorsTests {
|
|||
AssertZ(rule2).satisfy(emptyMap())
|
||||
|
||||
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
|
||||
assertEquals(rule1, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[0])
|
||||
assertEquals(rule2, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses[1])
|
||||
assertEquals(rule1, Program.db.predicates[Functor.of("a/1")]!!.clauses[0])
|
||||
assertEquals(rule2, Program.db.predicates[Functor.of("a/1")]!!.clauses[1])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,20 +308,20 @@ class DatabaseOperatorsTests {
|
|||
|
||||
val control = Program.query(Structure(Atom("a"), listOf(Variable("X")))).toList()
|
||||
assertEquals(3, control.size, "Expected 3 results")
|
||||
assertEquals(3, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses.size, "Expected 3 clauses")
|
||||
assertEquals(3, Program.db.predicates[Functor.of("a/1")]!!.clauses.size, "Expected 3 clauses")
|
||||
|
||||
val retract = RetractAll(Structure(Atom("a"), listOf(Variable("X"))))
|
||||
val result = retract.satisfy(emptyMap()).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
assertEquals(0, Program.db.predicates[FunctorInfo.of("a/1")]!!.clauses.size, "Expected 0 clauses")
|
||||
assertEquals(0, Program.db.predicates[Functor.of("a/1")]!!.clauses.size, "Expected 0 clauses")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `If Head refers to a predicate that is not defined, it is implicitly created as a dynamic predicate`() {
|
||||
val predicateName = "idonotyetexist"
|
||||
val predicateFunctor = FunctorInfo.of("$predicateName/1")
|
||||
val predicateFunctor = Functor.of("$predicateName/1")
|
||||
|
||||
assertFalse(predicateFunctor in Program.db.predicates, "Expected predicate to not exist before")
|
||||
|
||||
|
|
Reference in a new issue