Rework parsing structure
This commit is contained in:
parent
a4ec29f084
commit
b9f419a59d
17 changed files with 246 additions and 278 deletions
131
tests/parser/grammars/LogicGrammarTests.kt
Normal file
131
tests/parser/grammars/LogicGrammarTests.kt
Normal file
|
@ -0,0 +1,131 @@
|
|||
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.builtins.Conjunction
|
||||
|
||||
class LogicGrammarTests {
|
||||
private lateinit var parser: Grammar<List<Clause>>
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
parser = LogicGrammar() as Grammar<List<Clause>>
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 fact")
|
||||
Assertions.assertTrue(result[0] is Fact, "Expected a fact")
|
||||
Assertions.assertEquals(input, "${result[0].toString()}.", "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)
|
||||
|
||||
Assertions.assertEquals(2, result.size, "Expected 2 facts")
|
||||
Assertions.assertTrue(result[0] is Fact, "Expected a fact")
|
||||
Assertions.assertTrue(result[1] is Fact, "Expected a fact")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `simplest rule`() {
|
||||
val input = "a :- b."
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 rule")
|
||||
Assertions.assertTrue(result[0] is Rule, "Expected a rule")
|
||||
Assertions.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)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 rule")
|
||||
Assertions.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)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 rule")
|
||||
Assertions.assertTrue(result[0] is Rule, "Expected a rule")
|
||||
|
||||
val rule = result[0] as Rule
|
||||
|
||||
Assertions.assertTrue(rule.head is Structure, "Expected head to be a structure")
|
||||
val head = rule.head as Structure
|
||||
Assertions.assertEquals("parent/2", head.functor, "Expected functor 'parent/2'")
|
||||
Assertions.assertEquals(Variable("X"), head.arguments[0], "Expected first argument 'X'")
|
||||
Assertions.assertEquals(Variable("Y"), head.arguments[1], "Expected second argument 'Y'")
|
||||
|
||||
Assertions.assertTrue(rule.body is Structure, "Expected body to be a structure")
|
||||
val body = rule.body as Structure
|
||||
Assertions.assertEquals("father/2", body.functor, "Expected functor 'father/2'")
|
||||
Assertions.assertEquals(Variable("X"), body.arguments[0], "Expected first argument 'X'")
|
||||
Assertions.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)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 rule")
|
||||
Assertions.assertInstanceOf(Rule::class.java, result[0], "Expected a rule")
|
||||
val rule = result[0] as Rule
|
||||
Assertions.assertInstanceOf(Conjunction::class.java, rule.body, "Expected body to be a conjunction")
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
Assertions.assertEquals(1, result.size, "Expected 1 rule")
|
||||
val rule = result[0] as Rule
|
||||
Assertions.assertTrue(rule.body is Conjunction, "Expected body to be a conjunction")
|
||||
val conjunction = rule.body as Conjunction
|
||||
Assertions.assertEquals("invited/2", (conjunction.left as CompoundTerm).functor, "Expected functor 'invited/2'")
|
||||
}
|
||||
}
|
155
tests/parser/grammars/TermsGrammarTests.kt
Normal file
155
tests/parser/grammars/TermsGrammarTests.kt
Normal file
|
@ -0,0 +1,155 @@
|
|||
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.arithmetic.Float
|
||||
import prolog.ast.arithmetic.Integer
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.logic.equivalent
|
||||
|
||||
class TermsGrammarTests {
|
||||
private lateinit var parser: Grammar<Term>
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
parser = TermsGrammar() as Grammar<Term>
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["a", "foo", "foo1", "fooBar", "foo_bar"])
|
||||
fun `parse atom`(name: String) {
|
||||
val result = parser.parseToEnd(name)
|
||||
|
||||
Assertions.assertEquals(Atom(name), result, "Expected atom '$name'")
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["X", "X1", "X_1"])
|
||||
fun `parse variable`(name: String) {
|
||||
val result = parser.parseToEnd(name)
|
||||
|
||||
Assertions.assertEquals(Variable(name), result, "Expected atom '$name'")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty compound term`() {
|
||||
val input = "f()"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Structure(Atom("f"), emptyList()), result, emptyMap()),
|
||||
"Expected atom 'f'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse compound term f(a)`() {
|
||||
val input = "f(a)"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Structure(Atom("f"), listOf(Atom("a"))), result, emptyMap()),
|
||||
"Expected atom 'f(a)'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse compound term f(a, b)`() {
|
||||
val input = "f(a, b)"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Structure(Atom("f"), listOf(Atom("a"), Atom("b"))), result, emptyMap()),
|
||||
"Expected atom 'f(a, b)'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse compound term with variable f(a, X)`() {
|
||||
val input = "f(a, X)"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Structure(Atom("f"), listOf(Atom("a"), Variable("X"))), result, emptyMap()),
|
||||
"Expected atom 'f(a, X)'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse nested compound term f(a, g(b))`() {
|
||||
val input = "f(a, g(b))"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(
|
||||
Structure(Atom("f"), listOf(Atom("a"), Structure(Atom("g"), listOf(Atom("b"))))),
|
||||
result,
|
||||
emptyMap()
|
||||
),
|
||||
"Expected atom 'f(a, g(b))'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse compound term with variable f(a, g(X))`() {
|
||||
val input = "f(a, g(X))"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(
|
||||
Structure(Atom("f"), listOf(Atom("a"), Structure(Atom("g"), listOf(Variable("X"))))),
|
||||
result,
|
||||
emptyMap()
|
||||
),
|
||||
"Expected atom 'f(a, g(X))'"
|
||||
)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = [-987654321, -543, -21, -1, 0, 1, 5, 12, 345, 123456789])
|
||||
fun `parse integer`(number: Int) {
|
||||
val input = number.toString()
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertEquals(Integer(number), result, "Expected integer '$number'")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse float`() {
|
||||
val input = "42.0"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Float(42.0f), result, emptyMap()),
|
||||
"Expected float '42.0'"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse negative float`() {
|
||||
val input = "-42.0"
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Float(-42.0f), result, emptyMap()),
|
||||
"Expected float '-42.0'"
|
||||
)
|
||||
}
|
||||
}
|
Reference in a new issue