Checkpoint
This commit is contained in:
parent
9db1c66781
commit
724e911a6f
17 changed files with 288 additions and 95 deletions
|
@ -66,6 +66,14 @@ open class Preprocessor {
|
|||
when {
|
||||
// TODO Remove hardcoding by storing the functors as constants in operators?
|
||||
// Logic
|
||||
term.functor == "=/2" -> {
|
||||
Unify(args[0], args[1])
|
||||
}
|
||||
|
||||
term.functor == "\\=/2" -> {
|
||||
NotUnify(args[0], args[1])
|
||||
}
|
||||
|
||||
term.functor == ",/2" -> {
|
||||
Conjunction(args[0] as LogicOperand, args[1] as LogicOperand)
|
||||
}
|
||||
|
@ -92,14 +100,6 @@ open class Preprocessor {
|
|||
|
||||
// Arithmetic
|
||||
|
||||
term.functor == "=/2" && args.all { it is Expression } -> {
|
||||
Unify(args[0] as Expression, args[1] as Expression)
|
||||
}
|
||||
|
||||
term.functor == "\\=/2" && args.all { it is Expression } -> {
|
||||
NotUnify(args[0] as Expression, args[1] as Expression)
|
||||
}
|
||||
|
||||
term.functor == "-/1" && args.all { it is Expression } -> {
|
||||
Negate(args[0] as Expression)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,32 @@ import prolog.ast.arithmetic.Float
|
|||
import prolog.ast.arithmetic.Integer
|
||||
import prolog.ast.terms.*
|
||||
|
||||
/**
|
||||
* Precedence is based on the following table:
|
||||
*
|
||||
* | Precedence | Type | Operators |
|
||||
* |------------|------|-----------------------------------------------------------------------------------------------|
|
||||
* | 1200 | xfx | --\>, :-, =\>, ==\> |
|
||||
* | 1200 | fx | :-, ?- |
|
||||
* | 1105 | xfy | \| |
|
||||
* | 1100 | xfy | ; |
|
||||
* | 1050 | xfy | -\>, \*-\> |
|
||||
* | 1000 | xfy | , |
|
||||
* | 990 | xfx | := |
|
||||
* | 900 | fy | \\+ |
|
||||
* | 700 | xfx | \<, =, =.., =:=, =\<, ==, =\\=, \>, \>=, \\=, \\==, as, is, \>:\<, :\< |
|
||||
* | 600 | xfy | : |
|
||||
* | 500 | yfx | +, -, /\\, \\/, xor |
|
||||
* | 500 | fx | ? |
|
||||
* | 400 | yfx | \*, /, //, div, rdiv, \<\<, \>\>, mod, rem |
|
||||
* | 200 | xfx | \*\* |
|
||||
* | 200 | xfy | ^ |
|
||||
* | 200 | fy | +, -, \\ |
|
||||
* | 100 | yfx | . |
|
||||
* | 1 | fx | $ |
|
||||
*
|
||||
* @see [SWI-Prolog Predicate op/3](https://www.swi-prolog.org/pldoc/man?predicate=op/3)
|
||||
*/
|
||||
open class TermsGrammar : Tokens() {
|
||||
|
||||
// Basic named terms
|
||||
|
@ -19,7 +45,7 @@ open class TermsGrammar : Tokens() {
|
|||
) use { Atom(text.substring(1, text.length - 1)) }
|
||||
protected val atom: Parser<Atom> by (quotedAtom or simpleAtom)
|
||||
protected val compound: Parser<Structure> by (atom * -leftParenthesis * separated(
|
||||
parser(::term),
|
||||
parser(::termNoConjunction),
|
||||
comma,
|
||||
acceptZero = true
|
||||
) * -rightParenthesis) use {
|
||||
|
@ -30,51 +56,57 @@ open class TermsGrammar : Tokens() {
|
|||
protected val int: Parser<Integer> by integerToken use { Integer(text.toInt()) }
|
||||
protected val float: Parser<Float> by floatToken use { Float(text.toFloat()) }
|
||||
|
||||
// Operators
|
||||
protected val ops: Parser<String> by (dummy
|
||||
// Logic
|
||||
or comma
|
||||
or semicolon
|
||||
// Arithmetic
|
||||
or plus
|
||||
or equals
|
||||
or notEquals
|
||||
) use { this.text }
|
||||
protected val simpleOperand: Parser<Operand> by (dummy
|
||||
// Logic
|
||||
// Base terms (atoms, compounds, variables, numbers)
|
||||
protected val baseTerm: Parser<Term> by (dummy
|
||||
or (-leftParenthesis * parser(::term) * -rightParenthesis)
|
||||
or compound
|
||||
or atom
|
||||
or variable
|
||||
// Arithmetic
|
||||
or int
|
||||
or float
|
||||
or int
|
||||
)
|
||||
protected val operand: Parser<Operand> by (dummy
|
||||
or parser(::operator)
|
||||
or simpleOperand
|
||||
)
|
||||
protected val operator: Parser<CompoundTerm> by (simpleOperand * ops * operand) use {
|
||||
CompoundTerm(Atom(t2), listOf(t1, t3))
|
||||
|
||||
// Level 200 - prefix operators (+, -, \)
|
||||
protected val op200: Parser<CompoundTerm> by ((plus or minus) * parser(::term200)) use {
|
||||
CompoundTerm(Atom(t1.text), listOf(t2))
|
||||
}
|
||||
protected val term200: Parser<Term> by (op200 or baseTerm)
|
||||
|
||||
// Level 400 - multiplication, division
|
||||
protected val op400: Parser<String> by (multiply or divide) use { text }
|
||||
protected val term400: Parser<Term> by (term200 * zeroOrMore(op400 * term200)) use {
|
||||
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
|
||||
}
|
||||
|
||||
// Parts
|
||||
protected val head: Parser<Head> by (dummy
|
||||
or compound
|
||||
or atom
|
||||
)
|
||||
protected val body: Parser<Body> by (dummy
|
||||
or operator
|
||||
or head
|
||||
or variable
|
||||
) use { this as Body }
|
||||
// Level 500 - addition, subtraction
|
||||
protected val op500: Parser<String> by (plus or minus) use { text }
|
||||
protected val term500: Parser<Term> by (term400 * zeroOrMore(op500 * term400)) use {
|
||||
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
|
||||
}
|
||||
|
||||
protected val term: Parser<Term> by (dummy
|
||||
or float
|
||||
or int
|
||||
or variable
|
||||
or compound
|
||||
or atom
|
||||
)
|
||||
// Level 700 - comparison operators
|
||||
protected val op700: Parser<String> by (equals or notEquals) use { text }
|
||||
protected val term700: Parser<Term> by (term500 * optional(op700 * term500)) use {
|
||||
if (t2 == null) t1 else CompoundTerm(Atom(t2!!.t1), listOf(t1, t2!!.t2))
|
||||
}
|
||||
|
||||
// Level 1000 - conjunction (,)
|
||||
protected val term1000: Parser<Term> by (term700 * zeroOrMore(comma * term700)) use {
|
||||
t2.fold(t1) { acc, (_, term) -> CompoundTerm(Atom(","), listOf(acc, term)) }
|
||||
}
|
||||
|
||||
// Level 1100 - disjunction (;)
|
||||
protected val term1100: Parser<Term> by (term1000 * zeroOrMore(semicolon * term1000)) use {
|
||||
t2.fold(t1) { acc, (_, term) -> CompoundTerm(Atom(";"), listOf(acc, term)) }
|
||||
}
|
||||
|
||||
// Term - highest level expression
|
||||
protected val term: Parser<Term> by term1100
|
||||
protected val termNoConjunction: Parser<Term> by term700
|
||||
|
||||
// Parts for clauses
|
||||
protected val head: Parser<Head> by (compound or atom)
|
||||
protected val body: Parser<Body> by term use { this as Body }
|
||||
|
||||
override val rootParser: Parser<Any> by term
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ abstract class Tokens : Grammar<Any>() {
|
|||
protected val equals: Token by literalToken("=")
|
||||
protected val notEquals: Token by literalToken("\\=")
|
||||
protected val plus: Token by literalToken("+")
|
||||
protected val minus: Token by literalToken("-")
|
||||
protected val multiply: Token by literalToken("*")
|
||||
protected val divide: Token by literalToken("/")
|
||||
protected val dot by literalToken(".")
|
||||
|
||||
// Ignored tokens
|
||||
|
|
|
@ -48,4 +48,10 @@ object Program : Resolvent {
|
|||
|
||||
correspondingDBs.forEach { it.clear() }
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
clear()
|
||||
variableRenamingStart = 0
|
||||
storeNewLine = false
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
package prolog.ast.arithmetic
|
||||
|
||||
import prolog.Answers
|
||||
import prolog.Substitutions
|
||||
import prolog.ast.logic.LogicOperand
|
||||
|
||||
data class Integer(override val value: Int) : Number {
|
||||
data class Integer(override val value: Int) : Number, LogicOperand() {
|
||||
// Integers are already evaluated
|
||||
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||
|
||||
override fun satisfy(subs: Substitutions): Answers = sequenceOf(Result.success(emptyMap()))
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
|
||||
override operator fun plus(other: Number): Number = when (other) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import prolog.builtins.True
|
|||
import prolog.flags.AppliedCut
|
||||
import prolog.logic.applySubstitution
|
||||
import prolog.logic.numbervars
|
||||
import prolog.logic.occurs
|
||||
import prolog.logic.unifyLazy
|
||||
|
||||
/**
|
||||
|
@ -46,7 +47,7 @@ abstract class Clause(val head: Head, val body: Body) : Resolvent {
|
|||
.mapValues { reverse[it.value] ?: it.value }
|
||||
result = result.map { it.key to applySubstitution(it.value, result) }
|
||||
.toMap()
|
||||
.filterNot { it.key in renamed.keys }
|
||||
.filterNot { it.key in renamed.keys && !occurs(it.key as Variable, goal, emptyMap())}
|
||||
yield(Result.success(result))
|
||||
},
|
||||
onFailure = { error ->
|
||||
|
|
|
@ -4,8 +4,9 @@ import prolog.Answers
|
|||
import prolog.Substitutions
|
||||
import prolog.ast.arithmetic.Expression
|
||||
import prolog.ast.arithmetic.Simplification
|
||||
import prolog.ast.logic.LogicOperand
|
||||
|
||||
data class Variable(val name: String) : Term, Body, Expression {
|
||||
data class Variable(val name: String) : Term, Body, Expression, LogicOperand() {
|
||||
override fun simplify(subs: Substitutions): Simplification {
|
||||
// If the variable is bound, return the value of the binding
|
||||
// If the variable is not bound, return the variable itself
|
||||
|
|
|
@ -18,7 +18,12 @@ import prolog.logic.unifyLazy
|
|||
*/
|
||||
class Write(private val term: Term) : Operator(Atom("write"), null, term), Satisfiable {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
val t = applySubstitution(term, subs)
|
||||
var t = term
|
||||
var temp = applySubstitution(t, subs)
|
||||
while (t != temp) {
|
||||
t = temp
|
||||
temp = applySubstitution(t, subs)
|
||||
}
|
||||
|
||||
Terminal().say(t.toString())
|
||||
|
||||
|
|
Reference in a new issue