355 lines
No EOL
10 KiB
Kotlin
355 lines
No EOL
10 KiB
Kotlin
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.Assertions.assertTrue
|
|
import org.junit.jupiter.api.Assertions.assertEquals
|
|
import org.junit.jupiter.api.BeforeEach
|
|
import org.junit.jupiter.api.Nested
|
|
import org.junit.jupiter.api.Test
|
|
import org.junit.jupiter.api.assertDoesNotThrow
|
|
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.builtins.Is
|
|
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)
|
|
|
|
assertEquals(Atom(name), result, "Expected atom '$name'")
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(
|
|
strings = [
|
|
"'tick'",
|
|
"\"doubleTick\"",
|
|
"`backTick`",
|
|
"'i have spaces'",
|
|
"`i have a 'quote' inside`",
|
|
"'I have Cases'",
|
|
"'I, h@v3 many (!!!) special characters?! {}'"
|
|
]
|
|
)
|
|
fun `Parse a quoted atom`(input: String) {
|
|
val result = parser.parseToEnd(input)
|
|
|
|
val expected = input.substring(1, input.length - 1)
|
|
|
|
assertEquals(Atom(expected), result, "Expected atom")
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(strings = ["X", "X1", "X_1"])
|
|
fun `parse variable`(name: String) {
|
|
val result = parser.parseToEnd(name)
|
|
|
|
assertEquals(Variable(name), result)
|
|
}
|
|
|
|
@Test
|
|
fun `parse anonymous variable`() {
|
|
val input = "_"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Variable("_"), result, "Expected anonymous variable")
|
|
}
|
|
|
|
@Test
|
|
fun `empty compound term`() {
|
|
val input = "f()"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Structure(Atom("f"), emptyList()), result, "Expected atom 'f'")
|
|
}
|
|
|
|
@Test
|
|
fun `parse compound term f(a)`() {
|
|
val input = "f(a)"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Structure(Atom("f"), listOf(Atom("a"))), result, "Expected atom 'f(a)'")
|
|
}
|
|
|
|
@Test
|
|
fun `parse compound term f(a, b)`() {
|
|
val input = "f(a, b)"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("f"), listOf(Atom("a"), Atom("b"))),
|
|
result,
|
|
"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)
|
|
|
|
assertEquals(
|
|
Structure(Atom("f"), listOf(Atom("a"), Variable("X"))),
|
|
result,
|
|
"Expected atom 'f(a, X)'"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse compound term with var and int`() {
|
|
val input = "check_identical(A, 13)"
|
|
val result = parser.parseToEnd(input)
|
|
assertEquals(
|
|
Structure(Atom("check_identical"), listOf(Variable("A"), Integer(13))),
|
|
result,
|
|
"Expected atom 'check_identical(A, 13)'"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse nested compound term f(a, g(b))`() {
|
|
val input = "f(a, g(b))"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("f"), listOf(Atom("a"), Structure(Atom("g"), listOf(Atom("b"))))),
|
|
result,
|
|
"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)
|
|
|
|
assertEquals(
|
|
Structure(Atom("f"), listOf(Atom("a"), Structure(Atom("g"), listOf(Variable("X"))))),
|
|
result,
|
|
"Expected atom 'f(a, g(X))'"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse nested compound term with variables`() {
|
|
val input = "hit(character(Name, Class, Level, HP), character(Name, Class, Level, T))"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(
|
|
Atom("hit"),
|
|
listOf(
|
|
Structure(Atom("character"), listOf(Variable("Name"), Variable("Class"), Variable("Level"), Variable("HP"))),
|
|
Structure(Atom("character"), listOf(Variable("Name"), Variable("Class"), Variable("Level"), Variable("T")))
|
|
)
|
|
),
|
|
result,
|
|
"Expected atom 'hit(character(Name, Class, Level, HP), character(Name, Class, Level, T))'"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse compound term with anonymous variables`() {
|
|
val input = "f(a, _, g(X))"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("f"), listOf(Atom("a"), Variable("_"), Structure(Atom("g"), listOf(Variable("X"))))),
|
|
result,
|
|
"Expected atom 'f(a, _, g(X))'"
|
|
)
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(ints = [0, 1, 5, 12, 345, 123456789])
|
|
fun `parse positive integer`(number: Int) {
|
|
val input = number.toString()
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Integer(number), result, "Expected integer '$number'")
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(ints = [-987654321, -543, -21, -1])
|
|
fun `parse negative integer`(number: Int) {
|
|
val input = number.toString()
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Structure(Atom("-"), listOf(Integer(0 - number))), result, "Expected integer '$number'")
|
|
}
|
|
|
|
@Test
|
|
fun `parse float`() {
|
|
val input = "42.0"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Float(42.0f), result, "Expected float '42.0'")
|
|
}
|
|
|
|
@Test
|
|
fun `parse negative float`() {
|
|
val input = "-42.0"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(Structure(Atom("-"), listOf(Float(42.0f))), result, "Expected float '-42.0'")
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(strings = ["got_an_a(Student)", "grade(Student, Grade)"])
|
|
fun `parse unification`(input: String) {
|
|
assertDoesNotThrow { parser.parseToEnd(input) }
|
|
}
|
|
|
|
@Nested
|
|
class `Operators and precedence` {
|
|
private lateinit var parser: Grammar<Term>
|
|
|
|
@BeforeEach
|
|
fun setup() {
|
|
parser = TermsGrammar() as Grammar<Term>
|
|
}
|
|
|
|
@Test
|
|
fun `can parse equivalent`() {
|
|
val input = "X == Y"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("=="), listOf(Variable("X"), Variable("Y"))),
|
|
result,
|
|
"Expected equivalent operator"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `can parse cut`() {
|
|
val input = "!"
|
|
val result = parser.parseToEnd(input)
|
|
assertEquals(Atom("!"), result, "Expected cut operator")
|
|
}
|
|
|
|
@Test
|
|
fun `can parse 'is'`() {
|
|
val input = "T is 1"
|
|
val result = parser.parseToEnd(input)
|
|
assertEquals(
|
|
Structure(Atom("is"), listOf(Variable("T"), Integer(1))),
|
|
result
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `can parse 'is' with addition`() {
|
|
val input = "T is 1 + 2"
|
|
val result = parser.parseToEnd(input)
|
|
assertEquals(
|
|
Structure(Atom("is"), listOf(Variable("T"), Structure(Atom("+"), listOf(Integer(1), Integer(2))))),
|
|
result
|
|
)
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(strings = ["+", "-", "*", "/"])
|
|
fun `can parse with spaces`(operator: String) {
|
|
val input = "1 $operator 2"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom(operator), listOf(Integer(1), Integer(2))),
|
|
result,
|
|
"Expected operator '$operator'"
|
|
)
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(strings = ["+", "-", "*", "/"])
|
|
fun `can parse without spaces`(operator: String) {
|
|
val input = "1${operator}2"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom(operator), listOf(Integer(1), Integer(2))),
|
|
result,
|
|
"Expected operator '$operator' without spaces"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse addition and multiplication`() {
|
|
val input = "1 + 2 * 3"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("+"), listOf(Integer(1), Structure(Atom("*"), listOf(Integer(2), Integer(3))))),
|
|
result,
|
|
"Expected addition and multiplication"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `parse multiplication and addition`() {
|
|
val input = "1 * 2 + 3"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(Atom("+"), listOf(Structure(Atom("*"), listOf(Integer(1), Integer(2))), Integer(3))),
|
|
result,
|
|
"Expected multiplication and addition"
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `complex expression`() {
|
|
val input = "1 + 2 * 3 - 4 / 5"
|
|
|
|
val result = parser.parseToEnd(input)
|
|
|
|
assertEquals(
|
|
Structure(
|
|
Atom("-"),
|
|
listOf(
|
|
Structure(Atom("+"), listOf(Integer(1), Structure(Atom("*"), listOf(Integer(2), Integer(3))))),
|
|
Structure(Atom("/"), listOf(Integer(4), Integer(5)))
|
|
)
|
|
),
|
|
result,
|
|
"Expected complex expression"
|
|
)
|
|
}
|
|
}
|
|
} |