Coverage Summary for Class: CallerBindingsKt (it.unibo.tuprolog.argumentation.core.runtime.modules)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| CallerBindingsKt |
100%
(1/1)
|
100%
(3/3)
|
100%
(4/4)
|
100%
(17/17)
|
100%
(122/122)
|
package it.unibo.tuprolog.argumentation.core.runtime.modules
import it.unibo.tuprolog.core.Struct
import it.unibo.tuprolog.core.Substitution
import it.unibo.tuprolog.core.Var
import it.unibo.tuprolog.solve.Solution
import it.unibo.tuprolog.solve.SolveOptions
import it.unibo.tuprolog.solve.Solver
/**
* Solves [goal] on behalf of a primitive, whose caller needs the bindings of all the variables of the goal.
*
* The solutions of a query only bind its variables with a name, as for a query typed by a user: the bindings of
* the anonymous and wildcard ones (`_`, `_Name`), which are the caller's variables as much as the others, would
* be lost (and with them, for instance, the bindings a module makes inside the terms it is given). They are
* renamed for the query, and bound back in each solution.
*/
internal fun Solver.solveForCaller(
goal: Struct,
options: SolveOptions,
): Sequence<Solution> {
val hidden =
goal.variables
.filter { it.isWildcard }
.distinct()
.associateWith { Var.of("CallerVar") }
if (hidden.isEmpty()) return solve(goal, options)
return solve(goal.apply(Substitution.of(hidden)).castToStruct(), options).map { solution ->
when (solution) {
is Solution.Yes -> Solution.yes(goal, solution.substitution.restoring(hidden))
else -> solution
}
}
}
// The bindings of the renamed variables, as bindings of the variables they replaced: a renamed variable is the one it
// replaced wherever it occurs, also in the value of a binding (`same(_X, _Y)` binds `_X` to `_Y`)
private fun Substitution.Unifier.restoring(renaming: Map<Var, Var>): Substitution.Unifier {
val inverse = Substitution.of(renaming.entries.associate { (original, renamedVar) -> renamedVar to original })
val restored =
renaming
.mapValues { (_, renamedVar) -> renamedVar.apply(this).apply(inverse) }
.filter { (original, value) -> value != original }
val others = filterKeys { it !in renaming.values }.mapValues { (_, value) -> value.apply(inverse) }
return Substitution.unifier(others + restored)
}