diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Justified.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Justified.kt index adb1011f..ff74d977 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Justified.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Justified.kt @@ -66,6 +66,11 @@ interface Justified { */ fun justifiedByAny(others: Collection): Boolean = others.any { this.justifiedBy(it) } + + /** + * Append [Justifications] from [other] entity to justifications of this [Justified] + */ + fun justifyBy(other: Justified): Unit { justifications().addAll(other.justifications()) } } 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 f1cc0c1a..be45fba9 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 @@ -165,7 +165,9 @@ internal class ControllerImpl ( // then they must be tracked somewhere above --- i.e. in its parent match.allHeads().filter { it.isPrincipal() && !it.justifiedBy(parent) }.forEach { // Avoid justifying parent by its child! - parent.justifyBy(it) + processing.forEachChunkFrom(parent.toPos()) { child -> + child.justifyBy(it) + } } } @@ -239,6 +241,7 @@ internal class ControllerImpl ( profiler.profile("activate_${constraint.symbol()}") { + // fixme: maybe provide no evidence for non-principal constraints? constraint.occurrence(logicalStateObservable(), args, processing.nextEvidence(), justifications, context.logicalContext, context.ruleUniqueTag).let { occ -> trace.activate(occ) processing.processActivated(this, occ, parent, status) 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 a72a6f0c..51564a58 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 @@ -88,6 +88,13 @@ interface MatchJournal : MutableIterable, EvidenceSource { */ fun replay(observable: LogicalStateObservable, futurePos: Pos) + /** + * Walk from specified [from] position in journal until current position + * while applying [action] to each visited [Chunk]. + * Occurrences are accordingly reset and replayed + */ + fun forEachChunkFrom(from: Pos, action: (Chunk) -> Unit) + /** * Returns snapshot of the journal. */ @@ -167,8 +174,6 @@ interface MatchJournal : MutableIterable, EvidenceSource { class MatchChunk(override val evidence: Evidence, val match: RuleMatch) : Chunk { private val justifications = match.justifications().apply { add(evidence) } - fun justifyBy(other: Justified): Unit { justifications.addAll(other.justifications()) } - override fun justifications(): Justifications = justifications override var entries: MutableList = mutableListOf() 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 1ec9302d..cc7adca8 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 @@ -148,6 +148,12 @@ internal open class MatchJournalImpl( if (currentPos() != pastPos) throw IllegalStateException() } + override fun forEachChunkFrom(from: Pos, action: (Chunk) -> Unit) { + val to = currentPos() + resetPos(from, false) + replayWith(to, action) + } + override fun replay(observable: LogicalStateObservable, futurePos: MatchJournal.Pos) = replayWith(futurePos, {}) private fun replayWith(futurePos: MatchJournal.Pos, action: (Chunk) -> Unit) {