From 1b3280a94784aeb061f0baa7cc2a41026450c8f2 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Fri, 18 Apr 2025 20:36:11 +0200 Subject: [PATCH] REPL checkpoint --- src/Debug.kt | 3 + src/Main.kt | 101 +++++++++++++- src/better_parser/PrologParser.kt | 17 +++ src/better_parser/PrologSourceParser.kt | 70 ++++++++++ src/better_parser/SimplePrologParser.kt | 46 +++--- src/better_parser/SimpleReplParser.kt | 27 ++++ src/better_parser/SimpleSourceParser.kt | 48 +++++++ src/interpreter/SourceFileReader.kt | 23 +++ src/prolog/Program.kt | 6 +- src/prolog/ast/logic/Clause.kt | 2 +- src/prolog/ast/logic/Predicate.kt | 5 + src/prolog/ast/terms/Operator.kt | 2 - src/prolog/builtins/controlOperators.kt | 2 +- src/repl/Repl.kt | 4 + ...ts.kt => SimplePrologPrologParserTests.kt} | 4 +- .../SimpleSourcePrologParserTests.kt | 132 ++++++++++++++++++ tests/better_parser/resources/a.pl | 1 + tests/better_parser/resources/foo.pl | 1 + tests/better_parser/resources/parent.pl | 9 ++ tests/interpreter/SourceFileReaderTests.kt | 32 +++++ ...rologTests.kt => ScanPrologParserTests.kt} | 2 +- 21 files changed, 503 insertions(+), 34 deletions(-) create mode 100644 src/Debug.kt create mode 100644 src/better_parser/PrologParser.kt create mode 100644 src/better_parser/PrologSourceParser.kt create mode 100644 src/better_parser/SimpleReplParser.kt create mode 100644 src/better_parser/SimpleSourceParser.kt create mode 100644 src/interpreter/SourceFileReader.kt create mode 100644 src/repl/Repl.kt rename tests/better_parser/{SimplePrologParserTests.kt => SimplePrologPrologParserTests.kt} (97%) create mode 100644 tests/better_parser/SimpleSourcePrologParserTests.kt create mode 100644 tests/better_parser/resources/a.pl create mode 100644 tests/better_parser/resources/foo.pl create mode 100644 tests/better_parser/resources/parent.pl create mode 100644 tests/interpreter/SourceFileReaderTests.kt rename tests/lexer/{ScanPrologTests.kt => ScanPrologParserTests.kt} (98%) diff --git a/src/Debug.kt b/src/Debug.kt new file mode 100644 index 0000000..ba9e63e --- /dev/null +++ b/src/Debug.kt @@ -0,0 +1,3 @@ +data object Debug { + val on: Boolean = true +} \ No newline at end of file diff --git a/src/Main.kt b/src/Main.kt index fd9fcc2..88278c2 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -1,9 +1,98 @@ -fun main() { - for (i in 1..10) { - println("Hello, Kotlin Command Line Utility!") - } +import better_parser.PrologParser +import better_parser.SimpleReplParser +import interpreter.SourceFileReader +import prolog.Answer +import prolog.Program +import prolog.ast.logic.Fact +import prolog.ast.logic.Rule +import prolog.ast.terms.Atom +import prolog.ast.terms.CompoundTerm +import prolog.ast.terms.Variable +import prolog.builtins.Conjunction + +fun help(): String { + println("Unknown command. Type 'h' for help.") + println("Commands:") + println(" ; - find next solution") + println(" a - abort") + println(" . - end query") + println(" h - help") + println(" exit - exit Prolog REPL") + return "" } -fun testMe(): String { - return "Hello, Kotlin Command Line Utility!" +fun say(message: String) { + println(message) +} + +fun prompt(message: String): String { + print("$message ") + var input: String = readlnOrNull() ?: help() + while (input.isBlank()) { + input = readlnOrNull() ?: help() + } + return input +} + +fun prettyResult(result: Answer): String { + result.fold( + onSuccess = { + val subs = result.getOrNull()!! + if (subs.isEmpty()) { + return "true." + } + return subs.entries.joinToString(", ") { "${it.key} = ${it.value}" } + }, + onFailure = { + return "Failure: ${result.exceptionOrNull()!!}" + } + ) +} + +val knownCommands = setOf(";", "a", ".") + +fun main() { + SourceFileReader().readFile("tests/better_parser/resources/parent.pl") + + val parser = SimpleReplParser(debug = false) + + say("Prolog REPL. Type 'exit' to quit.") + + while (true) { + val queryString = prompt("?-") + + try { + val query = parser.parse(queryString) + val answers = query.satisfy(emptyMap()) + + if (answers.none()) { + say("false.") + } else { + val iterator = answers.iterator() + + var previous = iterator.next() + + while (iterator.hasNext()) { + var command = prompt(prettyResult(previous)) + + while (command !in knownCommands) { + say("Unknown action: $command (h for help)") + command = prompt("Action?") + } + + when (command) { + ";" -> previous = iterator.next() + "a" -> break + "." -> break + } + } + + say(prettyResult(previous)) + } + + } catch (e: Exception) { + println("Error: ${e.message}") + } + } + } diff --git a/src/better_parser/PrologParser.kt b/src/better_parser/PrologParser.kt new file mode 100644 index 0000000..73e63eb --- /dev/null +++ b/src/better_parser/PrologParser.kt @@ -0,0 +1,17 @@ +package better_parser + +import com.github.h0tk3y.betterParse.grammar.Grammar +import com.github.h0tk3y.betterParse.grammar.parseToEnd +import prolog.Program +import prolog.ast.logic.Clause +import prolog.ast.terms.Atom + +class PrologParser { + private val parser: Grammar> = SimpleSourceParser() as Grammar> + + public fun parse(input: String) { + val clauses: List = parser.parseToEnd(input) + + Program.load(clauses) + } +} \ No newline at end of file diff --git a/src/better_parser/PrologSourceParser.kt b/src/better_parser/PrologSourceParser.kt new file mode 100644 index 0000000..0383507 --- /dev/null +++ b/src/better_parser/PrologSourceParser.kt @@ -0,0 +1,70 @@ +package better_parser + +import com.github.h0tk3y.betterParse.combinators.* +import com.github.h0tk3y.betterParse.grammar.Grammar +import com.github.h0tk3y.betterParse.lexer.literalToken +import com.github.h0tk3y.betterParse.lexer.regexToken +import com.github.h0tk3y.betterParse.parser.Parser +import prolog.ast.logic.Fact +import prolog.ast.arithmetic.Integer +import prolog.ast.arithmetic.Float +import prolog.ast.logic.Clause +import prolog.ast.logic.LogicOperand +import prolog.ast.logic.Rule +import prolog.ast.terms.* +import prolog.builtins.Conjunction +import prolog.builtins.Disjunction + +class PrologSourceParser : Grammar>() { + // Define the tokens + private val atom by regexToken("[a-z][a-zA-Z0-9_]*") + private val variable by regexToken("[A-Z][a-zA-Z0-9_]*") + private val number by regexToken("-?[0-9]+(\\.[0-9]+)?") + private val whitespace by regexToken("\\s+", ignore = true) + + private val comma by literalToken(",") + private val semicolon by literalToken(";") + private val neck by literalToken(":-") + private val lparen by literalToken("(") + private val rparen by literalToken(")") + private val dot by literalToken(".") + + private val atomParser by atom use { Atom(text) } + private val variableParser by variable use { Variable(text) } + private val intParser by number use { Integer(text.toInt()) } + private val floatParser by number use { Float(text.toFloat()) } + private val numberParser by (intParser or floatParser) + private val compoundTermParser by (atomParser and skip(lparen) and separated( + atomParser or variableParser, + comma + ) and skip(rparen)) use { + CompoundTerm(t1, t2.terms) + } + + private val termParser: Parser by (numberParser or variableParser or compoundTermParser or atomParser) + + private val logicOperandParser: Parser by (termParser or compoundTermParser or atomParser) map { + it as LogicOperand + } + + private val conjunctionParser: Parser by (logicOperandParser and comma and logicOperandParser) use { + Conjunction(t1, t3) + } + private val disjunctionParser: Parser by (logicOperandParser and semicolon and logicOperandParser) use { + Disjunction(t1, t3) + } + + private val operatorParser: Parser by (conjunctionParser or disjunctionParser) + + private val headParser by (compoundTermParser or atomParser) + private val bodyParser by (operatorParser or compoundTermParser or atomParser) + + private val factParser by (headParser and dot) use { Fact(t1 as Head) } + private val ruleParser by (headParser and neck and bodyParser and dot) use { + Rule(t1 as Head, t3 as Body) + } + + private val clauseParser: Parser by (factParser or ruleParser) + + override val rootParser: Parser> by zeroOrMore(clauseParser) +} diff --git a/src/better_parser/SimplePrologParser.kt b/src/better_parser/SimplePrologParser.kt index 26e1a15..1fb49c7 100644 --- a/src/better_parser/SimplePrologParser.kt +++ b/src/better_parser/SimplePrologParser.kt @@ -6,6 +6,7 @@ import com.github.h0tk3y.betterParse.grammar.parser import com.github.h0tk3y.betterParse.lexer.Token import com.github.h0tk3y.betterParse.lexer.literalToken import com.github.h0tk3y.betterParse.lexer.regexToken +import com.github.h0tk3y.betterParse.lexer.token import com.github.h0tk3y.betterParse.parser.Parser import prolog.ast.arithmetic.Float import prolog.ast.arithmetic.Integer @@ -16,28 +17,32 @@ import prolog.ast.terms.Variable open class SimplePrologParser : Grammar() { // Prolog tokens - private val nameToken: Token by regexToken("[a-z][a-zA-Z0-9_]*") - private val variableToken: Token by regexToken("[A-Z][a-zA-Z0-9_]*") + protected val nameToken: Token by regexToken("[a-z][a-zA-Z0-9_]*") + protected val variableToken: Token by regexToken("[A-Z][a-zA-Z0-9_]*") // Arithmetic tokens private val floatToken: Token by regexToken("-?[1-9][0-9]*\\.[0-9]+") private val integerToken: Token by regexToken("-?([1-9][0-9]*|0)") // Special tokens - private val comma: Token by literalToken(",") - private val leftParenthesis: Token by literalToken("(") - private val rightParenthesis: Token by literalToken(")") + protected val neck by literalToken(":-") + protected val comma: Token by literalToken(",") + protected val leftParenthesis: Token by literalToken("(") + protected val rightParenthesis: Token by literalToken(")") + protected val dot by literalToken(".") // Ignored tokens - private val whitespace: Token by regexToken("\\s+", ignore = true) - private val singleLineComment: Token by regexToken("%[^\\n]*", ignore = true) - private val multiLineComment: Token by regexToken("/\\*.*?\\*/", ignore = true) + protected val whitespace: Token by regexToken("\\s+", ignore = true) + protected val singleLineComment: Token by regexToken("%[^\\n]*", ignore = true) + protected val multiLineComment: Token by regexToken("/\\*.*?\\*/", ignore = true) + + protected val dummy by token { _, _ -> -1 } use { throw IllegalStateException("This parser should not be used") } // Prolog parsers - private val atomParser: Parser by nameToken use { Atom(text) } - private val variableParser: Parser by variableToken use { Variable(text) } - private val structureParser: Parser by (atomParser and skip(leftParenthesis) and separated( - parser(this::termParser), + protected val variable: Parser by variableToken use { Variable(text) } + protected val atom: Parser by nameToken use { Atom(text) } + protected val compound: Parser by (atom and skip(leftParenthesis) and separated( + parser(::term), comma, acceptZero = true ) and skip(rightParenthesis)) use { @@ -45,17 +50,18 @@ open class SimplePrologParser : Grammar() { } // Arithmetic parsers - private val integerParser: Parser by integerToken use { Integer(text.toInt()) } - private val floatParser: Parser by floatToken use { + private val int: Parser by integerToken use { Integer(text.toInt()) } + private val float: Parser by floatToken use { Float(text.toFloat()) } - private val termParser: Parser by (floatParser - or integerParser - or variableParser - or structureParser - or atomParser + protected val term: Parser by (dummy + or float + or int + or variable + or compound + or atom ) map { it } - override val rootParser: Parser = termParser + override val rootParser: Parser = term } \ No newline at end of file diff --git a/src/better_parser/SimpleReplParser.kt b/src/better_parser/SimpleReplParser.kt new file mode 100644 index 0000000..0c8a598 --- /dev/null +++ b/src/better_parser/SimpleReplParser.kt @@ -0,0 +1,27 @@ +package better_parser + +import com.github.h0tk3y.betterParse.combinators.times +import com.github.h0tk3y.betterParse.combinators.unaryMinus +import com.github.h0tk3y.betterParse.combinators.use +import com.github.h0tk3y.betterParse.grammar.parseToEnd +import com.github.h0tk3y.betterParse.parser.Parser +import prolog.ast.logic.LogicOperand +import prolog.builtins.Query + +class SimpleReplParser(val debug: Boolean = false) : SimpleSourceParser() { + override val rootParser: Parser by (body * -dot) use { Query(this as LogicOperand) } + + fun parse(input: String): Query { + if (debug) { + println("Parsing input: $input") + } + + val query = parseToEnd(input) as Query + + if (debug) { + println("Parsed query: $query") + } + + return query + } +} \ No newline at end of file diff --git a/src/better_parser/SimpleSourceParser.kt b/src/better_parser/SimpleSourceParser.kt new file mode 100644 index 0000000..437f9ed --- /dev/null +++ b/src/better_parser/SimpleSourceParser.kt @@ -0,0 +1,48 @@ +package better_parser + +import com.github.h0tk3y.betterParse.combinators.* +import com.github.h0tk3y.betterParse.grammar.parser +import com.github.h0tk3y.betterParse.lexer.literalToken +import com.github.h0tk3y.betterParse.parser.Parser +import prolog.ast.arithmetic.ArithmeticOperator +import prolog.ast.logic.* +import prolog.ast.terms.* +import prolog.builtins.Conjunction +import prolog.builtins.Disjunction + +open class SimpleSourceParser : SimplePrologParser() { + protected val simpleLogicOperand: Parser by (dummy + or compound + or atom + ) + protected val logicOperand: Parser by (dummy + or parser(::operator) + or simpleLogicOperand + ) + + protected val arithmeticOperator: Parser by dummy + protected val logicOperator: Parser by (simpleLogicOperand * comma * logicOperand) use { + Conjunction(t1, t3) + } + + protected val operator: Parser by (arithmeticOperator or logicOperator) use { this as Operator } + + protected val head: Parser by (dummy + or compound + or atom + ) + protected val body: Parser by (dummy + or operator + or head + ) use { this as Body } + + // ---- + + private val rule: Parser by (head * -neck * body) use { Rule(t1, t2) } + private val fact: Parser by head use { Fact(this) } + + private val clause: Parser by ((rule or fact) * -dot) + private val clauses: Parser> by zeroOrMore(clause) + + override val rootParser: Parser by clauses +} \ No newline at end of file diff --git a/src/interpreter/SourceFileReader.kt b/src/interpreter/SourceFileReader.kt new file mode 100644 index 0000000..e3e58cc --- /dev/null +++ b/src/interpreter/SourceFileReader.kt @@ -0,0 +1,23 @@ +package interpreter + +import better_parser.PrologParser + +class SourceFileReader { + private val parser = PrologParser() + + fun readFile(filePath: String) { + return try { + val file = java.io.File(filePath) + if (!file.exists()) { + throw IllegalArgumentException("File not found: $filePath") + } + + val content = file.readText() + + // Parse the content using SimpleSourceParser + parser.parse(content) + } catch (e: Exception) { + throw RuntimeException("Error reading file: $filePath", e) + } + } +} \ No newline at end of file diff --git a/src/prolog/Program.kt b/src/prolog/Program.kt index 46adef1..398b71a 100644 --- a/src/prolog/Program.kt +++ b/src/prolog/Program.kt @@ -1,5 +1,6 @@ package prolog +import Debug import prolog.ast.logic.Clause import prolog.ast.logic.Predicate import prolog.ast.logic.Resolvent @@ -12,13 +13,16 @@ typealias Database = Program * Prolog Program or database. */ object Program: Resolvent { - private var predicates: Map = emptyMap() + var predicates: Map = emptyMap() init { setup() } private fun setup() { + if (Debug.on) { + println("Setting up Prolog program...") + } // Initialize the program with built-in predicates load(listOf( )) diff --git a/src/prolog/ast/logic/Clause.kt b/src/prolog/ast/logic/Clause.kt index 38aa3a0..58b2eb4 100644 --- a/src/prolog/ast/logic/Clause.kt +++ b/src/prolog/ast/logic/Clause.kt @@ -18,7 +18,7 @@ import prolog.logic.unifyLazy * @see [prolog.ast.terms.Variable] * @see [Predicate] */ -abstract class Clause(private val head: Head, private val body: Body) : Resolvent { +abstract class Clause(val head: Head, val body: Body) : Resolvent { val functor: Functor = head.functor override fun solve (goal: Goal, subs: Substitutions): Answers = sequence { diff --git a/src/prolog/ast/logic/Predicate.kt b/src/prolog/ast/logic/Predicate.kt index f25d3d5..1396cd1 100644 --- a/src/prolog/ast/logic/Predicate.kt +++ b/src/prolog/ast/logic/Predicate.kt @@ -39,6 +39,11 @@ class Predicate : Resolvent { */ fun add(clause: Clause) { require(clause.functor == functor) { "Clause functor does not match predicate functor" } + + if (Debug.on) { + println("Adding clause $clause to predicate $functor") + } + clauses.add(clause) } diff --git a/src/prolog/ast/terms/Operator.kt b/src/prolog/ast/terms/Operator.kt index 8a5af51..9d0e067 100644 --- a/src/prolog/ast/terms/Operator.kt +++ b/src/prolog/ast/terms/Operator.kt @@ -1,7 +1,5 @@ package prolog.ast.terms -import prolog.ast.arithmetic.Expression - typealias Operand = Term abstract class Operator( diff --git a/src/prolog/builtins/controlOperators.kt b/src/prolog/builtins/controlOperators.kt index 791d029..c1ebe63 100644 --- a/src/prolog/builtins/controlOperators.kt +++ b/src/prolog/builtins/controlOperators.kt @@ -39,7 +39,7 @@ class Cut() : Atom("!") { /** * Conjunction (and). True if both Goal1 and Goal2 are true. */ -class Conjunction(private val left: LogicOperand, private val right: LogicOperand) : +class Conjunction(val left: LogicOperand, private val right: LogicOperand) : LogicOperator(Atom(","), left, right) { override fun satisfy(subs: Substitutions): Answers = sequence { // Satisfy the left part first, which either succeeds or fails diff --git a/src/repl/Repl.kt b/src/repl/Repl.kt new file mode 100644 index 0000000..34e999c --- /dev/null +++ b/src/repl/Repl.kt @@ -0,0 +1,4 @@ +package repl + +class Repl { +} \ No newline at end of file diff --git a/tests/better_parser/SimplePrologParserTests.kt b/tests/better_parser/SimplePrologPrologParserTests.kt similarity index 97% rename from tests/better_parser/SimplePrologParserTests.kt rename to tests/better_parser/SimplePrologPrologParserTests.kt index 4036acd..9135c42 100644 --- a/tests/better_parser/SimplePrologParserTests.kt +++ b/tests/better_parser/SimplePrologPrologParserTests.kt @@ -16,8 +16,8 @@ import prolog.ast.terms.Term import prolog.ast.terms.Variable import prolog.logic.equivalent -class SimplePrologParserTests { - lateinit var parser: Grammar +class SimplePrologPrologParserTests { + private lateinit var parser: Grammar @BeforeEach fun setup() { diff --git a/tests/better_parser/SimpleSourcePrologParserTests.kt b/tests/better_parser/SimpleSourcePrologParserTests.kt new file mode 100644 index 0000000..1eac0f9 --- /dev/null +++ b/tests/better_parser/SimpleSourcePrologParserTests.kt @@ -0,0 +1,132 @@ +package better_parser + +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 +import prolog.builtins.Disjunction + +class SimpleSourcePrologParserTests { + private lateinit var parser: Grammar> + + @BeforeEach + fun setup() { + parser = SimpleSourceParser() 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].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) + + 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("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("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(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) + + assertEquals(1, result.size, "Expected 1 rule") + val rule = result[0] as Rule + assertTrue(rule.body is Conjunction, "Expected body to be a conjunction") + val conjunction = rule.body as Conjunction + assertEquals("invited/2", (conjunction.left as CompoundTerm).functor, "Expected functor 'invited/2'") + } +} \ No newline at end of file diff --git a/tests/better_parser/resources/a.pl b/tests/better_parser/resources/a.pl new file mode 100644 index 0000000..7f7d821 --- /dev/null +++ b/tests/better_parser/resources/a.pl @@ -0,0 +1 @@ +a. \ No newline at end of file diff --git a/tests/better_parser/resources/foo.pl b/tests/better_parser/resources/foo.pl new file mode 100644 index 0000000..f0abdb4 --- /dev/null +++ b/tests/better_parser/resources/foo.pl @@ -0,0 +1 @@ +foo. \ No newline at end of file diff --git a/tests/better_parser/resources/parent.pl b/tests/better_parser/resources/parent.pl new file mode 100644 index 0000000..51178c4 --- /dev/null +++ b/tests/better_parser/resources/parent.pl @@ -0,0 +1,9 @@ +male(john). +male(jimmy). +female(mary). +parent(john, jimmy). +parent(mary, jimmy). +father(X, Y) :- parent(X, Y), male(X). +mother(X, Y) :- parent(X, Y), female(X). + +kan_goed_koken(miriam). \ No newline at end of file diff --git a/tests/interpreter/SourceFileReaderTests.kt b/tests/interpreter/SourceFileReaderTests.kt new file mode 100644 index 0000000..f999baf --- /dev/null +++ b/tests/interpreter/SourceFileReaderTests.kt @@ -0,0 +1,32 @@ +package interpreter + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import prolog.Program + +class SourceFileReaderTests { + @BeforeEach + fun setup() { + Program.clear() + } + + @Test + fun a() { + val inputFile = "tests/better_parser/resources/a.pl" + val reader = SourceFileReader() + + reader.readFile(inputFile) + + println(Program.predicates) + } + + @Test + fun foo() { + val inputFile = "tests/better_parser/resources/foo.pl" + val reader = SourceFileReader() + + reader.readFile(inputFile) + + println(Program.predicates) + } +} \ No newline at end of file diff --git a/tests/lexer/ScanPrologTests.kt b/tests/lexer/ScanPrologParserTests.kt similarity index 98% rename from tests/lexer/ScanPrologTests.kt rename to tests/lexer/ScanPrologParserTests.kt index 101cc49..5e99b01 100644 --- a/tests/lexer/ScanPrologTests.kt +++ b/tests/lexer/ScanPrologParserTests.kt @@ -10,7 +10,7 @@ import kotlin.test.assertEquals * * These tests are based on the Prolog syntax. */ -class ScanPrologTests { +class ScanPrologParserTests { @Test fun scan_simple_atom() { val tokens = Lexer("atom.").scan()