package parser.grammars import com.github.h0tk3y.betterParse.grammar.Grammar import com.github.h0tk3y.betterParse.grammar.parseToEnd import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import prolog.ast.logic.Clause import prolog.ast.logic.Fact import prolog.ast.logic.Rule import prolog.ast.terms.CompoundTerm import prolog.ast.terms.Structure import prolog.ast.terms.Variable import prolog.ast.terms.Functor class LogicGrammarTests { private lateinit var parser: Grammar> @BeforeEach fun setup() { parser = LogicGrammar() as Grammar> } @ParameterizedTest @ValueSource(strings = [ "john.", "mary.", "jimmy.", "male(john).", "male(jimmy).", "female(mary).", "not(not(true)).", "not(a, not(b, c), d, not(not(a)))." ]) fun `parse simple fact`(input: String) { val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 fact") assertTrue(result[0] is Fact, "Expected a fact") assertEquals(input, "${result[0]}.", "Expected fact to be '$input'") } @ParameterizedTest @ValueSource(strings = [ "john. mary.", "likes(john, mary). likes(mary, john).", "belgium. capital(belgium, brussels).", "plus(1, 2, 3). plus(3, 4, 7).", ]) fun `parse multiple facts`(input: String) { val result = parser.parseToEnd(input) assertEquals(2, result.size, "Expected 2 facts") assertTrue(result[0] is Fact, "Expected a fact") assertTrue(result[1] is Fact, "Expected a fact") } @Test fun `simplest rule`() { val input = "a :- b." val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") assertTrue(result[0] is Rule, "Expected a rule") assertEquals("a :- b", result[0].toString()) } @ParameterizedTest @ValueSource(strings = [ "parent(X, Y) :- father(X, Y).", "parent(X, Y) :- mother(X, Y)." ]) fun `parse simple rule`(input: String) { val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") assertTrue(result[0] is Rule, "Expected a rule") } @Test fun `parse rule with very verbose checks`() { val input = "parent(X, Y) :- father(X, Y)." val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") assertTrue(result[0] is Rule, "Expected a rule") val rule = result[0] as Rule assertTrue(rule.head is Structure, "Expected head to be a structure") val head = rule.head as Structure assertEquals(Functor.of("parent/2"), head.functor, "Expected functor 'parent/2'") assertEquals(Variable("X"), head.arguments[0], "Expected first argument 'X'") assertEquals(Variable("Y"), head.arguments[1], "Expected second argument 'Y'") assertTrue(rule.body is Structure, "Expected body to be a structure") val body = rule.body as Structure assertEquals(Functor.of("father/2"), body.functor, "Expected functor 'father/2'") assertEquals(Variable("X"), body.arguments[0], "Expected first argument 'X'") assertEquals(Variable("Y"), body.arguments[1], "Expected second argument 'Y'") } @Test fun `parse rule with conjunction`() { val input = "father(X, Y) :- parent(X, Y), male(X)." val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") assertInstanceOf(Rule::class.java, result[0], "Expected a rule") val rule = result[0] as Rule assertInstanceOf(CompoundTerm::class.java, rule.body, "Expected body to be a compound term") } @Test fun `parse rule with nested conjunction`() { val input = "guest(X, Y) :- invited(Y, X), has_time(X), not(sick(Y))." val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") val rule = result[0] as Rule assertEquals(Functor.of("guest/2"), rule.head.functor, "Expected functor 'guest/2'") assertEquals(Functor.of(",/2"), (rule.body as CompoundTerm).functor, "Expected functor ',/2'") val l1 = (rule.body as CompoundTerm).arguments[0] as CompoundTerm assertEquals(Functor.of(",/2"), l1.functor, "Expected functor ',/2'") val l2 = l1.arguments[0] as CompoundTerm assertEquals(Functor.of("invited/2"), l2.functor, "Expected functor 'invited/2'") } @Test fun `parse check_identical(X, Y)`() { var input = "check_identical(X, Y) :- X == Y." assertDoesNotThrow { val result = parser.parseToEnd(input) } input = "check_identical(X, Y) :- X = Y, !, write('X == Y succeeded'), nl." assertDoesNotThrow { val result = parser.parseToEnd(input) } } @Test fun `parse constraints`() { val input = ":- a." val result = parser.parseToEnd(input) assertEquals(1, result.size, "Expected 1 rule") assertTrue(result[0] is Rule, "Expected a rule") val rule = result[0] as Rule assertEquals(Functor.of("/0"), rule.head.functor, "Expected a constraint") } }