Checkpoint

This commit is contained in:
Tibo De Peuter 2025-05-02 13:28:00 +02:00
parent 23b2ce9362
commit f9017da734
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
18 changed files with 814 additions and 412 deletions

View file

@ -0,0 +1,9 @@
package interpreter
import prolog.ast.terms.Term
class OpenPreprocessor : Preprocessor() {
public override fun preprocess(term: Term, nested: Boolean): Term {
return super.preprocess(term, nested)
}
}

View file

@ -0,0 +1,93 @@
package interpreter
import com.github.h0tk3y.betterParse.grammar.parseToEnd
import org.junit.jupiter.api.Assertions.assertEquals
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
import prolog.ast.terms.Goal
import prolog.ast.terms.Structure
import prolog.ast.terms.Term
import prolog.ast.terms.Variable
import prolog.builtins.Is
import prolog.builtins.Subtract
class ParserPreprocessorIntegrationTests {
@Nested
class `Arithmetic`() {
val parser = TermsGrammar()
val preprocessor = OpenPreprocessor()
@ParameterizedTest
@ValueSource(strings = ["-1", "-1.0", "-1.5"])
fun `can parse negative numbers`(input: String) {
val number = if (input.contains('.')) {
Float(input.substring(1).toFloat())
} else {
Integer(input.substring(1).toInt())
}
val negativeNumber = if (input.contains('.')) {
Float(input.toFloat())
} else {
Integer(input.toInt())
}
// Check if parser returns the same result
val parsed = parser.parseToEnd("X is $input") as Term
assertEquals(
Structure(Atom("is"), listOf(
Variable("X"),
Structure(Atom("-"), listOf(number)),
)),
parsed
)
// Check if preprocessor returns the same result
val prepped = preprocessor.preprocess(parsed)
val expected = Is(
Variable("X"),
Subtract(Integer(0), number)
)
assertEquals(expected, prepped)
assertEquals(expected.toString(), prepped.toString())
// Check if evaluation is correct
val solutions = (prepped as Is).satisfy(emptyMap()).toList()
assertEquals(1, solutions.size)
assertEquals(negativeNumber, solutions[0].getOrNull()!![Variable("X")])
}
@ParameterizedTest
@ValueSource(strings = ["X is 1 - 2", "X is 1-2"])
fun `can add negative numbers`(input: String) {
val result = parser.parseToEnd(input) as Term
assertEquals(
Structure(Atom("is"), listOf(Variable("X"), Structure(Atom("-"), listOf(Integer(1), Integer(2))))),
result
)
val prepped = preprocessor.preprocess(result)
val expected = Is(
Variable("X"),
Subtract(Integer(1), Integer(2))
)
assertEquals(expected, prepped)
assertEquals(expected.toString(), prepped.toString())
}
}
}

View file

@ -1,32 +1,80 @@
package interpreter
import org.junit.jupiter.api.Assertions.assertEquals
import com.github.h0tk3y.betterParse.grammar.parseToEnd
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import parser.grammars.TermsGrammar
import prolog.ast.arithmetic.Integer
import prolog.ast.terms.Atom
import prolog.ast.terms.CompoundTerm
import prolog.ast.terms.Term
import prolog.ast.terms.Variable
import prolog.ast.terms.*
import prolog.builtins.*
class PreprocessorTests {
class OpenPreprocessor : Preprocessor() {
public override fun preprocess(term: Term, nested: Boolean): Term {
return super.preprocess(term, nested)
}
}
val preprocessor = OpenPreprocessor()
companion object {
val preprocessor = OpenPreprocessor()
fun test(tests: Map<Term, Term>) {
for ((input, expected) in tests) {
val result = OpenPreprocessor().preprocess(input)
val result = preprocessor.preprocess(input)
assertEquals(expected, result, "Expected preprocessed")
assertEquals(expected::class, result::class, "Expected same class")
}
}
}
@Test
fun `can preprocess anonymous variable`() {
val input = Variable("_")
val result = preprocessor.preprocess(input)
assertInstanceOf(AnonymousVariable::class.java, result, "Expected anonymous variable")
assertTrue((result as Variable).name.matches("_\\d+".toRegex()), "Expected anonymous variable name")
}
@Test
fun `multiple anonymous variables should be unique`() {
val input = CompoundTerm(Atom("foo"), listOf(Variable("_"), Variable("_")))
val result = preprocessor.preprocess(input)
assertInstanceOf(CompoundTerm::class.java, result, "Expected compound term")
assertEquals(2, (result as CompoundTerm).arguments.size, "Expected two terms")
for (argument in result.arguments) {
assertTrue(
(argument as Variable).name.matches("_\\d+".toRegex()),
"Expected anonymous variable name, but got ${argument.name}"
)
}
val first = result.arguments[0] as Variable
val second = result.arguments[1] as Variable
assertNotEquals(first.name, second.name, "Expected different anonymous variable names")
}
@Test
fun `can preprocess nested anonymous variables`() {
val input = TermsGrammar().parseToEnd("name(character(Name, _, _, _))") as Term
val result = preprocessor.preprocess(input)
assertInstanceOf(CompoundTerm::class.java, result, "Expected compound term")
assertEquals(1, (result as CompoundTerm).arguments.size, "Expected one term")
assertInstanceOf(CompoundTerm::class.java, result.arguments[0], "Expected compound term")
val inner = result.arguments[0] as CompoundTerm
assertEquals(4, inner.arguments.size, "Expected four terms")
for (argument in inner.arguments) {
if ((argument as Variable).name != "Name") {
assertTrue(
(argument as Variable).name.matches("_\\d+".toRegex()),
"Expected anonymous variable name, but got ${argument.name}"
)
}
}
}
@Nested
class `Arithmetic operators` {
@Test
@ -432,5 +480,22 @@ class PreprocessorTests {
)
)
}
@Test
fun `is`() {
test(
mapOf(
CompoundTerm(Atom("is"), listOf(Variable("T"), Integer(1))) to Is(Variable("T"), Integer(1)),
CompoundTerm(Atom("is"), listOf(Variable("T"), Add(Variable("HP"), Integer(5)))) to Is(
Variable("T"),
Add(Variable("HP"), Integer(5))
),
CompoundTerm(Atom("is"), listOf(Variable("T"), Subtract(Variable("HP"), Integer(5)))) to Is(
Variable("T"),
Subtract(Variable("HP"), Integer(5))
),
)
)
}
}
}