Provide additional information about parent principal chunk to Feedback (MPSCR-32)

Allows to track connection between invalidated matches and reported feedback.
In future this Journal info can help in simplifying error reporting.
This commit is contained in:
Grigorii Kirgizov 2020-01-29 12:52:08 +03:00
parent 119daf05d9
commit a4b28509a8
9 changed files with 33 additions and 12 deletions

View File

@ -33,12 +33,12 @@ class CompositeFeedback private constructor(private val elements: List<Feedback>
this.severity = maxSeverity(elements)
}
override fun handle(ruleMatch: RuleMatch, supervisor: Supervisor): Boolean {
override fun handle(currentRuleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, supervisor: Supervisor): Boolean {
var unhandled = 0
for (feedback in elements) {
if (!feedback.alreadyHandled()) {
unhandled += 1
if (supervisor.handleFeedback(ruleMatch, feedback)) {
if (supervisor.handleFeedback(currentRuleMatch, parentPrincipalMatch, feedback)) {
feedback.setHandled()
unhandled -= 1
}

View File

@ -40,8 +40,8 @@ abstract class Feedback : EvaluationFeedback() {
/**
* Returns true if the feedback has been handled.
*/
open fun handle(ruleMatch: RuleMatch, supervisor: Supervisor): Boolean {
if (!alreadyHandled() && supervisor.handleFeedback(ruleMatch, this)) {
open fun handle(currentRuleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, supervisor: Supervisor): Boolean {
if (!alreadyHandled() && supervisor.handleFeedback(currentRuleMatch, parentPrincipalMatch, this)) {
setHandled()
}
return alreadyHandled()

View File

@ -27,12 +27,15 @@ import jetbrains.mps.logic.reactor.program.Constraint
typealias Justs = TIntSet
//fun emptyJusts() = object : TIntSet {}
fun emptyJusts() = TIntHashSet(1)
fun justsOf(vararg elements: Int) = TIntHashSet(elements)
fun justsFromCollection(collection: Collection<Int>) = TIntHashSet(collection)
fun justsCopy(other: Justs) = TIntHashSet(other)
fun Justs.intersects(other: Iterable<Int>): Boolean = other.any { this.contains(it) }
/**
* Class representing a single constraint occurrence.
*
@ -112,4 +115,3 @@ fun Constraint.occurrence(observable: LogicalStateObservable,
logicalContext: LogicalContext,
ruleUniqueTag: Any? = null): Occurrence =
Occurrence(observable, this, logicalContext, arguments, justifications, ruleUniqueTag)

View File

@ -324,8 +324,6 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
private fun Occurrence.isPrincipal() = ispec.isPrincipal(this.constraint())
private fun Justs.intersects(other: Iterable<Int>): Boolean = other.any { this.contains(it) }
private fun RuleMatch.allHeads() = matchHeadKept() + matchHeadReplaced()
private fun RuleMatch.allStored() = allHeads().all { co -> (co as Occurrence).stored }

View File

@ -168,7 +168,7 @@ internal class ControllerImpl (
if (itemOk) {
context.withStatus { status ->
if (status.feedback?.alreadyHandled() == false) {
status.feedback.handle(match, supervisor)
status.feedback.handle(match, processing.ancestorMatch().match, supervisor)
}
}
@ -188,7 +188,9 @@ internal class ControllerImpl (
status
// if failure can be handled here then recover
} else if (status.feedback?.alreadyHandled() == false && status.failure.handle(match, supervisor)) {
} else if (status.feedback?.alreadyHandled() == false
&& status.failure.handle(match, processing.ancestorMatch().match, supervisor)) {
status.recover()
// else propagate further up the stack

View File

@ -16,7 +16,6 @@
package jetbrains.mps.logic.reactor.core.internal
import gnu.trove.set.TIntSet
import jetbrains.mps.logic.reactor.core.*
import jetbrains.mps.logic.reactor.evaluation.*
import jetbrains.mps.logic.reactor.program.*
@ -37,6 +36,12 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
*/
fun logActivation(occ: Occurrence)
/**
* Returns nearest MatchChunk which justifies current chunk.
* If current chunk is [MatchChunk], then it is returned.
* May return initial chunk. For initial chunk case returns it.
*/
fun ancestorMatch(): MatchChunk
/**
* Current position at the journal.

View File

@ -85,6 +85,20 @@ internal open class MatchJournalImpl(
current.entries.add(Chunk.Entry(occ))
}
override fun ancestorMatch(): MatchChunk {
if (current is MatchChunk) {
return current as MatchChunk
}
val rit = hist.listIterator(posPtr.previousIndex())
while (rit.hasPrevious()) {
val prev = rit.previous()
if (prev is MatchChunk && current.justifications.contains(prev.id)) {
return prev
}
}
return hist.first() as MatchChunk // initial chunk
}
override fun currentPos(): MatchJournal.Pos = current.toPos()

View File

@ -34,7 +34,7 @@ public interface Supervisor {
* Override this method in order to "handle" the feedback.
* Returns true if the method has handled (consumed) the feedback.
*/
default boolean handleFeedback(RuleMatch ruleMatch, EvaluationFeedback feedback) {
default boolean handleFeedback(RuleMatch ruleMatch, RuleMatch parentPrincipalMatch, EvaluationFeedback feedback) {
return false;
}

View File

@ -70,7 +70,7 @@ class TestController {
vararg occurrences: ConstraintOccurrence): Controller {
val program = MockProgram("test", rulesLists, registry = MockConstraintRegistry())
val supervisor = object : MockSupervisor() {
override fun handleFeedback(ruleMatch: RuleMatch, feedback: EvaluationFeedback): Boolean =
override fun handleFeedback(ruleMatch: RuleMatch, parentPrincipalMatch: RuleMatch, feedback: EvaluationFeedback): Boolean =
feedbackHandler(ruleMatch, feedback)
}
MockSession.init(program, supervisor)