Checkpoint

This commit is contained in:
Tibo De Peuter 2025-05-04 21:50:58 +02:00
parent 5bfa1691dd
commit a85169dced
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
27 changed files with 377 additions and 250 deletions

View file

@ -1,15 +1,14 @@
package e2e
import interpreter.FileLoader
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import org.junit.jupiter.params.provider.ValueSource
import prolog.Program
import prolog.ast.Database.Program
import java.io.ByteArrayOutputStream
import java.io.PrintStream
@ -26,21 +25,39 @@ class Examples {
System.setOut(PrintStream(outStream))
}
@Test
fun debugHelper() {
loader.load("examples/basics/backtracking.pl")
}
@ParameterizedTest
@MethodSource("expectations")
fun test(inputFile: String, expected: String) {
loader.load(inputFile)
@MethodSource("basics")
fun `Identical output for basics`(inputFile: String, expected: String) {
loader.load("examples/basics/$inputFile")
assertEquals(expected, outStream.toString())
}
fun expectations() = listOf(
Arguments.of("examples/basics/arithmetics.pl", "gimli is a level 4 fighter with 35 hitpoints.\nlegolas is a level 5 ranger with 30 hitpoints.\ngandalf is a level 10 wizard with 25 hitpoints.\nfrodo is a level 2 rogue with 20 hitpoints.\nlegolas threw gimli, and gimli took 5 damage.\ngimli is a level 4 fighter with 30 hitpoints.\ngandalf casts aid.\ngimli is a level 4 fighter with 35 hitpoints.\nlegolas leveled up.\nlegolas is a level 6 ranger with 30 hitpoints"),
Arguments.of("examples/basics/backtracking.pl", "0\ns(0)\ns(s(0))\ns(s(s(0)))\n"),
Arguments.of("examples/basics/cut.pl", "0\n"),
Arguments.of("examples/basics/disjunction.pl", "Alice likes Italian food.\nBob likes Italian food.\n"),
Arguments.of("examples/basics/equality.pl", "X == Y failed\nX = Y succeeded\nX == Y succeeded\nX = Y succeeded\nX == Y succeeded\n"),
Arguments.of("examples/basics/fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
Arguments.of("examples/basics/unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
Arguments.of("examples/basics/write.pl", "gpl zegt: dag(wereld)\n"),
@ParameterizedTest
@MethodSource("other")
fun `Identical output for other`(inputFile: String, expected: String) {
loader.load("examples/$inputFile")
assertEquals(expected, outStream.toString())
}
fun basics() = listOf(
Arguments.of("arithmetics.pl", "gimli is a level 4 fighter with 35 hitpoints.\nlegolas is a level 5 ranger with 30 hitpoints.\ngandalf is a level 10 wizard with 25 hitpoints.\nfrodo is a level 2 rogue with 20 hitpoints.\nlegolas threw gimli, and gimli took 5 damage.\ngimli is a level 4 fighter with 30 hitpoints.\ngandalf casts aid.\ngimli is a level 4 fighter with 35 hitpoints.\nlegolas leveled up.\nlegolas is a level 6 ranger with 30 hitpoints"),
Arguments.of("backtracking.pl", "0\ns(0)\ns(s(0))\ns(s(s(0)))\n"),
Arguments.of("cut.pl", "0\n"),
Arguments.of("disjunction.pl", "Alice likes Italian food.\nBob likes Italian food.\n"),
Arguments.of("equality.pl", "X == Y failed\nX = Y succeeded\nX == Y succeeded\nX = Y succeeded\nX == Y succeeded\n"),
Arguments.of("forall.pl", "Only alice likes pizza.\n"),
Arguments.of("fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
Arguments.of("liberty.pl", "Give me Liberty, or give me Death!\nI disapprove of what you say, but I will defend to the death your right to say it.\nThe revolution devours its own children.\nSo this is how liberty dies, with thunderous applause.\n"),
Arguments.of("unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
Arguments.of("write.pl", "gpl zegt: dag(wereld)\n"),
)
}
fun other() = listOf(
Arguments.of("program.pl", "10\nhello(world)")
)
}

View file

@ -6,7 +6,6 @@ import org.junit.jupiter.api.Nested
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import parser.grammars.TermsGrammar
import prolog.Program
import prolog.ast.arithmetic.Float
import prolog.ast.arithmetic.Integer
import prolog.ast.terms.Atom

View file

@ -604,5 +604,19 @@ class PreprocessorTests {
assertEquals(expected, result)
}
@Test
fun `dynamic declaration`() {
val input = Structure(
Atom("dynamic"), listOf(
Atom("declaration/1")
)
)
val expected = Dynamic("declaration/1")
val result = preprocessor.preprocess(input)
assertEquals(expected, result)
}
}
}

View file

@ -2,12 +2,12 @@ package interpreter
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import prolog.Program
import prolog.ast.Database.Program
class SourceFileReaderTests {
@BeforeEach
fun setup() {
Program.clear()
Program.reset()
}
@Test

View file

@ -2,13 +2,13 @@ package parser.builtins
import com.github.h0tk3y.betterParse.grammar.Grammar
import com.github.h0tk3y.betterParse.grammar.parseToEnd
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import parser.grammars.TermsGrammar
import prolog.ast.terms.Atom
import prolog.ast.terms.Structure
import prolog.ast.terms.Term
import kotlin.test.assertEquals
class DatabaseOperatorsParserTests {
private lateinit var parser: Grammar<Term>
@ -62,4 +62,14 @@ class DatabaseOperatorsParserTests {
assertEquals(expected, result)
}
@Test
fun `parse dynamic declaration`() {
val input = "dynamic declaration/1"
val expected = Structure(Atom("dynamic"), listOf(Atom("declaration/1")))
val result = parser.parseToEnd(input)
assertEquals(expected, result)
}
}

View file

@ -13,11 +13,12 @@ import prolog.logic.equivalent
import prolog.ast.terms.Atom
import prolog.ast.terms.Structure
import prolog.ast.terms.Variable
import prolog.ast.Database.Program
class EvaluationTests {
@BeforeEach
fun setUp() {
Program.clear()
Program.reset()
}
@Test
@ -350,7 +351,7 @@ class EvaluationTests {
)
)
Program.clear()
Program.reset()
Program.load(listOf(fact1, fact2, fact3, rule1))
}

View file

@ -3,7 +3,7 @@ package prolog.builtins
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import prolog.Program
import prolog.ast.Database.Program
import prolog.ast.logic.Fact
import prolog.ast.logic.Rule
import prolog.ast.terms.Atom
@ -14,7 +14,7 @@ import prolog.ast.terms.Variable
class ControlOperatorsTests {
@BeforeEach
fun setUp() {
Program.clear()
Program.reset()
}
@Test
@ -55,7 +55,7 @@ class ControlOperatorsTests {
// Now with cut
Program.clear()
Program.reset()
Program.load(
listOf(
@ -104,7 +104,7 @@ class ControlOperatorsTests {
// Now with cut in the middle
Program.clear()
Program.reset()
Program.load(
listOf(
@ -138,7 +138,7 @@ class ControlOperatorsTests {
// Now with cut at the end
Program.clear()
Program.reset()
Program.load(
listOf(

View file

@ -1,12 +1,15 @@
package prolog.builtins
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import prolog.Program
import prolog.ast.Database
import prolog.ast.Database.Program
import prolog.ast.logic.Clause
import prolog.ast.logic.Fact
import prolog.ast.logic.Predicate
@ -14,12 +17,11 @@ import prolog.ast.logic.Rule
import prolog.ast.terms.Atom
import prolog.ast.terms.Structure
import prolog.ast.terms.Variable
import kotlin.test.assertTrue
class DatabaseOperatorsTests {
@BeforeEach
fun setup() {
Program.clear()
Program.reset()
}
abstract class AssertTestsBase<T : Structure> {
@ -27,7 +29,7 @@ class DatabaseOperatorsTests {
@BeforeEach
fun setup() {
Program.clear()
Program.reset()
}
@ParameterizedTest
@ -36,8 +38,8 @@ class DatabaseOperatorsTests {
val fact = Fact(Atom("a"))
createAssert(fact).satisfy(emptyMap())
assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate")
assertEquals(fact, Program.internalDb.predicates["a/_"]!!.clauses[0])
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
assertEquals(fact, Program.db.predicates["a/_"]!!.clauses[0])
}
@Test
@ -45,8 +47,8 @@ class DatabaseOperatorsTests {
val fact = Fact(Structure(Atom("a"), listOf(Atom("b"))))
createAssert(fact).satisfy(emptyMap())
assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate")
assertEquals(fact, Program.internalDb.predicates["a/1"]!!.clauses[0])
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
assertEquals(fact, Program.db.predicates["a/1"]!!.clauses[0])
}
@Test
@ -57,8 +59,8 @@ class DatabaseOperatorsTests {
)
createAssert(rule).satisfy(emptyMap())
assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate")
assertEquals(rule, Program.internalDb.predicates["a/1"]!!.clauses[0])
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
assertEquals(rule, Program.db.predicates["a/1"]!!.clauses[0])
}
}
@ -88,9 +90,9 @@ class DatabaseOperatorsTests {
AssertA(rule1).satisfy(emptyMap())
AssertA(rule2).satisfy(emptyMap())
assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate")
assertEquals(rule2, Program.internalDb.predicates["a/1"]!!.clauses[0])
assertEquals(rule1, Program.internalDb.predicates["a/1"]!!.clauses[1])
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
assertEquals(rule2, Program.db.predicates["a/1"]!!.clauses[0])
assertEquals(rule1, Program.db.predicates["a/1"]!!.clauses[1])
}
}
@ -113,9 +115,9 @@ class DatabaseOperatorsTests {
AssertZ(rule1).satisfy(emptyMap())
AssertZ(rule2).satisfy(emptyMap())
assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate")
assertEquals(rule1, Program.internalDb.predicates["a/1"]!!.clauses[0])
assertEquals(rule2, Program.internalDb.predicates["a/1"]!!.clauses[1])
assertEquals(1, Program.db.predicates.size, "Expected 1 predicate")
assertEquals(rule1, Program.db.predicates["a/1"]!!.clauses[0])
assertEquals(rule2, Program.db.predicates["a/1"]!!.clauses[1])
}
}
@ -130,13 +132,13 @@ class DatabaseOperatorsTests {
@Test
fun `simple retract`() {
val predicate = Predicate(listOf(Fact(Atom("a"))))
Program.internalDb.load(predicate)
Program.db.load(predicate)
assertEquals(1, Program.query(Atom("a")).count())
val retract = Retract(Atom("a"))
assertTrue(retract.satisfy(emptyMap()).any(), "Expected 1 result")
assertEquals(1, retract.satisfy(emptyMap()).toList().size, "Expected 1 result")
assertEquals(0, predicate.clauses.size, "Expected 0 clauses")
assertTrue(retract.satisfy(emptyMap()).none())
@ -149,7 +151,7 @@ class DatabaseOperatorsTests {
Fact(Atom("a")),
Fact(Atom("a"))
))
Program.internalDb.load(predicate)
Program.db.load(predicate)
val control = Program.query(Atom("a")).toList()
@ -157,20 +159,25 @@ class DatabaseOperatorsTests {
val retract = Retract(Atom("a"))
val result = retract.satisfy(emptyMap())
val result = retract.satisfy(emptyMap()).iterator()
assertEquals(3, predicate.clauses.size, "Expected 3 clauses")
var answer = result.first()
assertTrue(result.hasNext(), "Expected more results")
val answer = result.next()
assertTrue(answer.isSuccess, "Expected success")
var subs = answer.getOrNull()!!
assertTrue(subs.isEmpty(), "Expected no substitutions")
assertTrue(answer.getOrNull()!!.isEmpty(), "Expected no substitutions")
assertTrue(result.hasNext(), "Expected more results")
assertEquals(2, predicate.clauses.size, "Expected 2 clauses")
assertTrue(result.first().isSuccess)
assertTrue(result.first().isSuccess)
assertTrue(result.next().isSuccess)
assertTrue(result.hasNext(), "Expected more results")
assertTrue(result.next().isSuccess)
assertFalse(result.hasNext(), "Expected more results")
assertEquals(0, predicate.clauses.size, "Expected no remaining clauses")
}
@ -181,7 +188,7 @@ class DatabaseOperatorsTests {
Fact(Structure(Atom("a"), listOf(Atom("c")))),
Fact(Structure(Atom("a"), listOf(Atom("d"))))
))
Program.internalDb.load(predicate)
Program.db.load(predicate)
val control = Program.query(Structure(Atom("a"), listOf(Variable("X")))).toList()
@ -189,38 +196,40 @@ class DatabaseOperatorsTests {
val retract = Retract(Structure(Atom("a"), listOf(Variable("X"))))
val result = retract.satisfy(emptyMap())
val result = retract.satisfy(emptyMap()).iterator()
assertEquals(3, predicate.clauses.size, "Expected 3 clauses")
var answer = result.first()
assertTrue(result.hasNext(), "Expected more results")
var answer = result.next()
assertTrue(answer.isSuccess, "Expected success")
var subs = answer.getOrNull()!!
assertTrue(subs.isNotEmpty(), "Expected substitutions")
assertTrue(Variable("X") in subs, "Expected variable X")
assertEquals(Atom("b"), subs[Variable("X")], "Expected b")
assertTrue(result.hasNext(), "Expected more results")
assertEquals(2, predicate.clauses.size, "Expected 2 clauses")
answer = result.first()
answer = result.next()
assertTrue(answer.isSuccess, "Expected success")
subs = answer.getOrNull()!!
assertTrue(subs.isNotEmpty(), "Expected substitutions")
assertTrue(Variable("X") in subs, "Expected variable X")
assertEquals(Atom("c"), subs[Variable("X")], "Expected c")
assertTrue(result.hasNext(), "Expected more results")
assertEquals(1, predicate.clauses.size, "Expected 1 clause")
answer = result.first()
answer = result.next()
assertTrue(answer.isSuccess, "Expected success")
subs = answer.getOrNull()!!
assertTrue(subs.isNotEmpty(), "Expected substitutions")
assertTrue(Variable("X") in subs, "Expected variable X")
assertEquals(Atom("d"), subs[Variable("X")], "Expected d")
assertFalse(result.hasNext(), "Expected no more results")
assertEquals(0, predicate.clauses.size, "Expected no clauses")
assertEquals(0, result.count(), "Expected no remaining results")
}
@Test

View file

@ -29,7 +29,7 @@ class TermsTests {
assertEquals(start + 1, end, "Expected end to be incremented by 1")
assertEquals(1, subs.size, "Expected one substitution")
assertTrue(subs.containsKey(term), "Expected subs to contain the original term")
assertEquals(Variable("X($start)"), subs[term], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs[term], "Expected subs to contain the new term")
}
@Test
@ -53,9 +53,9 @@ class TermsTests {
assertEquals(start + 2, end, "Expected end to be incremented by 2")
assertEquals(2, subs.size, "Expected two substitutions")
assertTrue(subs.containsKey(term.arguments[0]), "Expected subs to contain the first original term")
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs[term.arguments[0]], "Expected subs to contain the new term")
assertTrue(subs.containsKey(term.arguments[1]), "Expected subs to contain the second original term")
assertEquals(Variable("Y(${start + 1})"), subs[term.arguments[1]], "Expected subs to contain the new term")
assertEquals(Variable("Y@${start + 1}"), subs[term.arguments[1]], "Expected subs to contain the new term")
}
@Test
@ -68,9 +68,9 @@ class TermsTests {
assertEquals(start + 1, end, "Expected end to be incremented by 1")
assertEquals(1, subs.size, "Expected one substitution")
assertTrue(subs.containsKey(term.arguments[0]), "Expected subs to contain the first original term")
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs[term.arguments[0]], "Expected subs to contain the new term")
assertTrue(subs.containsKey(term.arguments[1]), "Expected subs to contain the second original term")
assertEquals(Variable("X($start)"), subs[term.arguments[1]], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs[term.arguments[1]], "Expected subs to contain the new term")
}
@Test
@ -83,7 +83,7 @@ class TermsTests {
assertEquals(start + 1, end, "Expected end to be incremented by 1")
assertEquals(1, subs.size, "Expected one substitution")
assertTrue(subs.containsKey(Variable("X")), "Expected subs to contain the variable")
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs[term.arguments[0]], "Expected subs to contain the new term")
}
@Test
@ -97,13 +97,14 @@ class TermsTests {
assertEquals(start + 1, end1, "Expected end to be incremented by 1")
assertEquals(1, subs1.size, "Expected one substitution")
assertTrue(subs1.containsKey(variable), "Expected subs to contain the variable")
assertEquals(Variable("X($start)"), subs1[variable], "Expected subs to contain the new term")
assertEquals(Variable("X@$start"), subs1[variable], "Expected subs to contain the new term")
val variable1 = subs1[variable] as Variable
val (end2, subs2) = numbervars(term, end1, subs1)
assertEquals(start + 2, end2, "Expected end to be incremented by 2")
assertEquals(1, subs2.size, "Expected one substitution")
assertTrue(subs2.containsKey(variable), "Expected subs to contain the variable")
assertEquals(Variable("X($end1)"), subs2[variable], "Expected subs to contain the new term")
assertTrue(subs2.containsKey(variable1), "Expected subs to contain the variable")
assertEquals(Variable("X@$start@$end1"), subs2[variable1], "Expected subs to contain the new term")
}
}