Preprocessing

This commit is contained in:
Tibo De Peuter 2025-04-27 22:02:50 +02:00
parent 82a8fccf87
commit 174855d7a3
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
5 changed files with 284 additions and 7 deletions

View file

@ -1,4 +1,93 @@
package interpreter
class Preprocessor {
import io.Logger
import prolog.ast.logic.Clause
import prolog.ast.logic.Fact
import prolog.ast.logic.LogicOperand
import prolog.ast.logic.Rule
import prolog.ast.terms.Atom
import prolog.ast.terms.Body
import prolog.ast.terms.Goal
import prolog.ast.terms.Head
import prolog.ast.terms.Structure
import prolog.ast.terms.Term
import prolog.builtins.Conjunction
import prolog.builtins.Cut
import prolog.builtins.Disjunction
import prolog.builtins.Fail
import prolog.builtins.False
import prolog.builtins.Not
import prolog.builtins.Query
import prolog.builtins.True
/**
* Preprocessor for Prolog
*
* This class preprocesses Prolog code and applies various transformations such as recognizing builtins.
*/
open class Preprocessor {
/**
* Preprocesses the input Prolog code.
*
* @param input The already parsed Prolog code as a list of clauses.
* @return The preprocessed Prolog code as a list of clauses.
*/
fun preprocess(input: List<Clause>): List<Clause> {
return input.map { preprocess(it) }
}
fun preprocess(input: Query): Query {
return Query(preprocess(input.query) as Goal)
}
private fun preprocess(clause: Clause): Clause {
return when (clause) {
is Fact -> {
Fact(preprocess(clause.head) as Head)
}
is Rule -> {
Rule(
preprocess(clause.head) as Head,
preprocess(clause.body as Term) as Body
)
}
else -> clause
}
}
protected open fun preprocess(term: Term): Term {
val prepped = when (term) {
Atom("true") -> True
Structure(Atom("true"), emptyList()) -> True
Atom("false") -> False
Structure(Atom("false"), emptyList()) -> False
Atom("fail") -> Fail
Structure(Atom("fail"), emptyList()) -> Fail
Atom("!") -> Cut()
Structure(Atom("!"), emptyList()) -> Cut()
else -> {
when {
term is Structure && term.functor == ",/2" -> {
val args = term.arguments.map { preprocess(it) }
Conjunction(args[0] as LogicOperand, args[1] as LogicOperand)
}
term is Structure && term.functor == ";/2" -> {
val args = term.arguments.map { preprocess(it) }
Disjunction(args[0] as LogicOperand, args[1] as LogicOperand)
}
term is Structure && term.functor == "\\+/1" -> {
val args = term.arguments.map { preprocess(it) }
Not(args[0] as Goal)
}
else -> term
}
}
}
if (prepped != term || prepped::class != term::class) {
Logger.debug("Preprocessed term: $term -> $prepped (${prepped::class})")
}
return prepped
}
}

View file

@ -152,8 +152,8 @@ class Between(private val expr1: Expression, private val expr2: Expression, priv
require(e1.to is Integer && e2.to is Integer) { "Arguments must be integers" }
val v1 = e1.to as Integer
val v2 = e2.to as Integer
val v1 = e1.to
val v2 = e2.to
return if (variable(e3.to, subs)) {
between(v1, v2, e3.to as Variable).map { answer ->

View file

@ -1,5 +1,6 @@
package repl
import interpreter.Preprocessor
import io.Logger
import io.Terminal
import parser.ReplParser
@ -9,6 +10,7 @@ import prolog.Answers
class Repl {
private val io = Terminal()
private val parser = ReplParser()
private val preprocessor = Preprocessor()
fun start() {
io.say("Prolog REPL. Type '^D' to quit.\n")
@ -23,7 +25,8 @@ class Repl {
fun query(): Answers {
val queryString = io.prompt("?-", { "" })
val query = parser.parse(queryString)
val simpleQuery = parser.parse(queryString)
val query = preprocessor.preprocess(simpleQuery)
return query.satisfy(emptyMap())
}
@ -46,7 +49,10 @@ class Repl {
}
when (command) {
";" -> previous = iterator.next()
";" -> {
previous = iterator.next()
io.say(prettyPrint(previous))
}
"a" -> return
"." -> return
"h" -> {
@ -55,8 +61,6 @@ class Repl {
}
}
}
io.say(prettyPrint(previous))
}
io.say("\n")