diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/CompositeFeedback.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/CompositeFeedback.kt index f6d78fcb..067ec167 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/CompositeFeedback.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/CompositeFeedback.kt @@ -33,12 +33,12 @@ class CompositeFeedback private constructor(private val elements: List 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 } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Feedback.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Feedback.kt index e46c3677..63882b2f 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Feedback.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Feedback.kt @@ -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() diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt index 1df666e1..f1290ed3 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt @@ -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) = TIntHashSet(collection) fun justsCopy(other: Justs) = TIntHashSet(other) +fun Justs.intersects(other: Iterable): 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) - diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt index b1260919..02a3801b 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt @@ -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): Boolean = other.any { this.contains(it) } - private fun RuleMatch.allHeads() = matchHeadKept() + matchHeadReplaced() private fun RuleMatch.allStored() = allHeads().all { co -> (co as Occurrence).stored } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ControllerImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ControllerImpl.kt index 2f831a95..2a8569bd 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ControllerImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ControllerImpl.kt @@ -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 diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournal.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournal.kt index e636d8f0..05f67311 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournal.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournal.kt @@ -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 { */ 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. diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournalImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournalImpl.kt index 515facf0..ee7aba75 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournalImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchJournalImpl.kt @@ -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() diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/Supervisor.java b/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/Supervisor.java index e3267727..e8425b98 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/Supervisor.java +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/Supervisor.java @@ -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; } diff --git a/reactor/Test/test/TestController.kt b/reactor/Test/test/TestController.kt index 52c8d143..e2fb3758 100644 --- a/reactor/Test/test/TestController.kt +++ b/reactor/Test/test/TestController.kt @@ -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)