Skip to content

Commit

Permalink
fix built-in primitives with new wrappers hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
gciatto committed Jun 11, 2020
1 parent 86a6589 commit add79a7
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ import it.unibo.tuprolog.solve.exception.error.MessageError
import it.unibo.tuprolog.solve.primitive.UnaryPredicate

object Throw : UnaryPredicate<ExecutionContext>("throw") {
override fun uncheckedImplementation(request: Solve.Request<ExecutionContext>): Sequence<Solve.Response> =
sequenceOf(
request.ensuringAllArgumentsAreInstantiated()
.replyException(
handleError(request.context, request.arguments[0])
)
)

private fun handleError(context: ExecutionContext, error: Term): TuPrologRuntimeException =
when {
error is Struct && error.functor == "error" && error.arity in 1..2 -> {
Expand All @@ -29,4 +21,13 @@ object Throw : UnaryPredicate<ExecutionContext>("throw") {
}
else -> MessageError.of(error, context)
}

override fun Solve.Request<ExecutionContext>.computeAll(first: Term): Sequence<Solve.Response> {
return sequenceOf(
ensuringAllArgumentsAreInstantiated()
.replyException(
handleError(context, arguments[0])
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@ import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.SideEffect1
import it.unibo.tuprolog.solve.primitive.UnaryPredicate

abstract class AbstractAssert(suffix: String, private val before: Boolean) : SideEffect1<ExecutionContext>("assert$suffix") {
override fun accept(request: Solve.Request<ExecutionContext>, term: Term): Solve.Response =
with(request.ensuringArgumentIsStruct(0)) {
val clause = if (term is Clause) term else Fact.of(term as Struct)
replySuccess(
dynamicKb = context.dynamicKb.let {
if (before) {
it.assertA(clause)
} else {
it.assertZ(clause)
}
}
)
}
abstract class AbstractAssert(
suffix: String,
private val before: Boolean
) : UnaryPredicate.NonBacktrackable<ExecutionContext>("assert$suffix") {

override fun Solve.Request<ExecutionContext>.computeOne(first: Term): Solve.Response {
ensuringArgumentIsStruct(0)
val clause = if (first is Clause) first else Fact.of(first as Struct)
return replySuccess(
dynamicKb = context.dynamicKb.let {
if (before) {
it.assertA(clause)
} else {
it.assertZ(clause)
}
}
)
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.List as LogicList
import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solution
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.exception.error.MetaError
import it.unibo.tuprolog.solve.primitive.NonBacktrackableTernaryRelation
import it.unibo.tuprolog.solve.primitive.TernaryRelation
import it.unibo.tuprolog.unify.Unificator.Companion.mguWith
import it.unibo.tuprolog.core.List as LogicList

object FindAll : NonBacktrackableTernaryRelation<ExecutionContext>("findall") {
override fun Solve.Request<ExecutionContext>.computeOne(x: Term, y: Term, z: Term): Solve.Response {
object FindAll : TernaryRelation.NonBacktrackable<ExecutionContext>("findall") {
override fun Solve.Request<ExecutionContext>.computeOne(first: Term, second: Term, third: Term): Solve.Response {
ensuringArgumentIsInstantiated(1)
val solutions = solve(y as Struct).toList()
val solutions = solve(second as Struct).toList()
val error = solutions.asSequence().filterIsInstance<Solution.Halt>().firstOrNull()
if (error != null) {
return replyException(MetaError.of(context, error.exception))
}
val mapped = solutions.asSequence()
.filterIsInstance<Solution.Yes>()
.map { x[it.substitution].freshCopy() }
.map { first[it.substitution].freshCopy() }

return replySuccess(z.mguWith(LogicList.from(mapped)) as Substitution.Unifier)
return replySuccess(third.mguWith(LogicList.from(mapped)) as Substitution.Unifier)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package it.unibo.tuprolog.solve.stdlib.primitive
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.exception.HaltException
import it.unibo.tuprolog.solve.primitive.PrimitiveWrapper
import it.unibo.tuprolog.solve.primitive.PredicateWithoutArguments

/**
* Implementation of primitive handling `halt/0` behaviour
*
* @author Enrico
*/
object Halt : PrimitiveWrapper<ExecutionContext>("halt", 0) {

override fun uncheckedImplementation(request: Solve.Request<ExecutionContext>): Sequence<Solve.Response> =
throw HaltException(context = request.context)
object Halt : PredicateWithoutArguments.NonBacktrackable<ExecutionContext>("halt") {
override fun Solve.Request<ExecutionContext>.computeOne(): Solve.Response {
throw HaltException(context = context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,20 @@ import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.function.ArithmeticEvaluator
import it.unibo.tuprolog.solve.primitive.TermRelation
import it.unibo.tuprolog.solve.primitive.BinaryRelation
import it.unibo.tuprolog.unify.Unificator.Companion.mguWith

/**
* Implementation of 'is'/2 predicate
*
* @author Enrico
*/
object Is : TermRelation.WithSideEffects<ExecutionContext>("is") {
object Is : BinaryRelation.Functional<ExecutionContext>("is") {
private fun mgu(x: Term, y: Term): Substitution = x mguWith y

override fun Solve.Request<ExecutionContext>.computeSingleResponse(): Solve.Response =
override fun Solve.Request<ExecutionContext>.computeOneSubstitution(first: Term, second: Term): Substitution =
ArithmeticEvaluator(context).let {
when (val effects: Substitution = relationWithSideEffects(arguments[0], arguments[1].accept(it))) {
is Substitution.Unifier -> replySuccess(effects)
else -> replyFail()
}
mgu(arguments[0], arguments[1].accept(it))
}

override fun relationWithSideEffects(x: Term, y: Term): Substitution =
x mguWith y
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,15 @@ import org.gciatto.kt.math.BigInteger

// TODO doc
object Natural : UnaryPredicate<ExecutionContext>("natural") {
override fun uncheckedImplementation(request: Solve.Request<ExecutionContext>): Sequence<Solve.Response> =
when (val x = request.arguments[0]) {
is Var -> generateValues(x).map { request.replySuccess(Substitution.of(x, it)) }
is Integer -> sequenceOf(request.replyWith(checkValue(x)))
else -> sequenceOf(request.replyFail())
override fun Solve.Request<ExecutionContext>.computeAll(first: Term): Sequence<Solve.Response> =
when (first) {
is Var -> generateValues().map { replySuccess(Substitution.of(first, it)) }
is Integer -> sequenceOf(replyWith(checkValue(first)))
else -> sequenceOf(replyFail())
}

@Suppress("UNUSED_PARAMETER")
private fun generateValues(variable: Var): Sequence<Term> = sequence {
var i = BigInteger.ZERO

while (true) {
yield(Integer.of(i))

i += BigInteger.ONE
}
}
private fun generateValues(): Sequence<Term> =
generateSequence(BigInteger.ZERO) { it + BigInteger.ONE }.map { Integer.of(it) }

private fun checkValue(value: Integer): Boolean =
value.intValue.signum >= 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.SideEffect0
import it.unibo.tuprolog.solve.primitive.PredicateWithoutArguments

object NewLine : SideEffect0<ExecutionContext>("nl") {
override fun accept(request: Solve.Request<ExecutionContext>): Solve.Response {
return request.context.standardOutput.let {
object NewLine : PredicateWithoutArguments.NonBacktrackable<ExecutionContext>("nl") {
override fun Solve.Request<ExecutionContext>.computeOne(): Solve.Response {
return context.standardOutput.let {
if (it == null) {
request.replyFail()
replyFail()
} else {
it.write("\n")
request.replySuccess()
replySuccess()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.primitive.TermRelation
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.BinaryRelation
import it.unibo.tuprolog.unify.Unificator.Companion.matches

/** Implementation of '\='/2 predicate */
object NotUnifiableWith : TermRelation.WithoutSideEffects<ExecutionContext>("\\=") {
override fun relationWithoutSideEffects(x: Term, y: Term): Boolean =
(x matches y).not()
object NotUnifiableWith : BinaryRelation.Predicative<ExecutionContext>("\\=") {
override fun Solve.Request<ExecutionContext>.compute(first: Term, second: Term): Boolean =
(first matches second).not()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import it.unibo.tuprolog.core.*
import it.unibo.tuprolog.core.Var
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.BacktrackableSideEffect1
import it.unibo.tuprolog.solve.primitive.UnaryPredicate
import it.unibo.tuprolog.theory.RetractResult
import it.unibo.tuprolog.unify.Unificator.Companion.mguWith

object Retract: BacktrackableSideEffect1<ExecutionContext>("retract") {
override fun accept(request: Solve.Request<ExecutionContext>, term: Term): Sequence<Solve.Response> {
request.ensuringArgumentIsStruct(0)
val clause = if (term is Clause) term else Rule.of(term as Struct, Var.anonymous())
object Retract : UnaryPredicate<ExecutionContext>("retract") {
override fun Solve.Request<ExecutionContext>.computeAll(first: Term): Sequence<Solve.Response> {
ensuringArgumentIsStruct(0)
val clause = if (first is Clause) first else Rule.of(first as Struct, Var.anonymous())
return sequence {
var dynamicKb = request.context.dynamicKb
var dynamicKb = context.dynamicKb
while (true) {
val result = dynamicKb.retract(clause)
if (result is RetractResult.Success) {
dynamicKb = result.theory
val substitution = when (term) {
is Clause -> (term mguWith result.firstClause) as Substitution.Unifier
else -> (term mguWith result.firstClause.head!!) as Substitution.Unifier
val substitution = when (first) {
is Clause -> (first mguWith result.firstClause) as Substitution.Unifier
else -> (first mguWith result.firstClause.head!!) as Substitution.Unifier
}
yield(
request.replySuccess(substitution = substitution, dynamicKb = dynamicKb)
replySuccess(substitution = substitution, dynamicKb = dynamicKb)
)
} else {
break
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.Integer
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.currentTimeInstant
import it.unibo.tuprolog.solve.exception.TimeOutException
import it.unibo.tuprolog.solve.primitive.PrimitiveWrapper
import it.unibo.tuprolog.solve.primitive.UnaryPredicate

/**
* Implements predicate `sleep(+N)` where `N` must be instantiated as an integer.
* The predicate execution always succeeds, unless the resolution process is halted because of a [TimeOutException].
* Furthermore, the resolution of a `sleep(N)` sub-goal is guaranteed to require at least `N` milliseconds
*/
object Sleep : PrimitiveWrapper<ExecutionContext>("sleep", 1) {
override fun uncheckedImplementation(request: Solve.Request<ExecutionContext>): Sequence<Solve.Response> =
object Sleep : UnaryPredicate<ExecutionContext>("sleep") {
override fun Solve.Request<ExecutionContext>.computeAll(first: Term): Sequence<Solve.Response> =
sequence {
request.ensuringAllArgumentsAreInstantiated()
ensuringAllArgumentsAreInstantiated()
.ensuringArgumentIsInteger(0).let {
val initialTime = currentTimeInstant()
val threshold = request.arguments[0].castTo<Integer>().intValue.toLongExact()
val threshold = arguments[0].castTo<Integer>().intValue.toLongExact()
while (currentTimeInstant() - initialTime < threshold);
yield(request.replySuccess())
yield(replySuccess())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.primitive.TermRelation
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.BinaryRelation

/** Implementation of '=='/2 predicate */
object TermIdentical : TermRelation.WithoutSideEffects<ExecutionContext>("==") {
override fun relationWithoutSideEffects(x: Term, y: Term): Boolean =
x == y
object TermIdentical : BinaryRelation.Predicative<ExecutionContext>("==") {
override fun Solve.Request<ExecutionContext>.compute(first: Term, second: Term): Boolean {
return first == second
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.primitive.TermRelation
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.BinaryRelation

/** Implementation of `'\=='/2` predicate */
object TermNotIdentical : TermRelation.WithoutSideEffects<ExecutionContext>("\\==") {
override fun relationWithoutSideEffects(x: Term, y: Term): Boolean =
x != y
object TermNotIdentical : BinaryRelation.Predicative<ExecutionContext>("\\==") {
override fun Solve.Request<ExecutionContext>.compute(first: Term, second: Term): Boolean {
return first != second
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package it.unibo.tuprolog.solve.stdlib.primitive

import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.primitive.TermRelation
import it.unibo.tuprolog.unify.Unificator.Companion.mguWith
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.BinaryRelation
import it.unibo.tuprolog.unify.Unificator.Companion.matches

/** Implementation of '='/2 predicate */
object UnifiesWith : TermRelation.WithSideEffects<ExecutionContext>("=") {
override fun relationWithSideEffects(x: Term, y: Term): Substitution =
x mguWith y
object UnifiesWith : BinaryRelation.Predicative<ExecutionContext>("=") {
override fun Solve.Request<ExecutionContext>.compute(first: Term, second: Term): Boolean =
first matches second
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import it.unibo.tuprolog.core.Atom
import it.unibo.tuprolog.core.Term
import it.unibo.tuprolog.solve.ExecutionContext
import it.unibo.tuprolog.solve.Solve
import it.unibo.tuprolog.solve.primitive.SideEffect1
import it.unibo.tuprolog.solve.primitive.UnaryPredicate

object Write : SideEffect1<ExecutionContext>("write") {
override fun accept(request: Solve.Request<ExecutionContext>, term: Term): Solve.Response {
return request.context.standardOutput.let {
object Write : UnaryPredicate.NonBacktrackable<ExecutionContext>("write") {
override fun Solve.Request<ExecutionContext>.computeOne(first: Term): Solve.Response {
return context.standardOutput.let {
if (it == null) {
request.replyFail()
replyFail()
} else {
val string = when (term) {
is Atom -> term.value
else -> term.toString()
val string = when (first) {
is Atom -> first.value
else -> first.toString()
}
it.write(string)
request.replySuccess()
replySuccess()
}
}
}
Expand Down

0 comments on commit add79a7

Please sign in to comment.