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 3b5cb526..94f82111 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 @@ -22,6 +22,7 @@ import jetbrains.mps.logic.reactor.program.IncrementalProgramSpec import jetbrains.mps.logic.reactor.evaluation.RuleMatch import jetbrains.mps.logic.reactor.evaluation.SessionToken import jetbrains.mps.logic.reactor.program.Rule +import jetbrains.mps.logic.reactor.util.Id import jetbrains.mps.logic.reactor.util.Profiler import jetbrains.mps.logic.reactor.util.profile @@ -46,7 +47,8 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di val profiler: Profiler? = null) : StoreAwareJournalImpl(journal, logicalState) { - private val execQueue: ExecutionQueue = ExecutionQueue(journal.index(), RuleOrdering(ruleIndex)) + private val journalIndex: MatchJournal.Index = journal.index() + private val execQueue: ExecutionQueue = ExecutionQueue(journalIndex, RuleOrdering(ruleIndex)) private data class MatchCandidate(val rule: Rule, val occChunk: MatchJournal.OccChunk) @@ -208,10 +210,13 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di push() assert(active.alive) + val activationChunk: MatchJournal.OccChunk? if (!active.stored) { active.stored = true - logActivation(active) + activationChunk = logActivation(active) active.revive(logicalState) + } else { + activationChunk = journalIndex.activatingChunkOf(Id(active)) } profiler.profile("dispatch_${active.constraint().symbol()}") { @@ -223,6 +228,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di val matches = dispatchingFront.matches().toList() val newCurrentMatches = // todo: assert that there can be no future matches on non-principal occurrences? + // with that move withPostponedMatches to else-branch if (isFront() || !active.isPrincipal()) { matches } else { @@ -232,6 +238,13 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di val currentMatches = execQueue.withPostponedMatches(active, newCurrentMatches) val outStatus = currentMatches.fold(inStatus) { status, match -> + if (activationChunk != null && !isFront()) { + val discards = match.matchHeadReplaced().contains(active) + if (discards) { + dropDiscardingMatchesFor(activationChunk) + } + } + // TODO: paranoid check. should be isAlive() instead // FIXME: move this check elsewhere if (status.operational && active.stored && match.allStored()) @@ -248,6 +261,12 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di return outStatus } + private fun dropDiscardingMatchesFor(ancestor: MatchJournal.OccChunk) = + this.dropDescendantsWhile(ancestor) { chunk -> + chunk is MatchJournal.MatchChunk + && chunk.match.matchHeadReplaced().contains(ancestor.occ) + } + private inline fun FeedbackStatus.then(action: (FeedbackStatus) -> FeedbackStatus) : FeedbackStatus = if (operational) action(this) else this 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 1bd06ca9..3801289c 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 @@ -69,6 +69,13 @@ interface MatchJournal : MutableIterable { */ fun reset(pastPos: Pos) + /** + * Removes [Chunk]s among descendants of [ancestor] if they satisfy [dropIf] predicate. + * Transitively removes descendants of removed chunks. + * Only erases future chunks and leaves journal position intact. + */ + fun dropDescendantsWhile(ancestor: Chunk, dropIf: (Chunk) -> Boolean) + /** * Replay activated and discarded occurrences logged in journal between current and provided positions. * Advances journal position to specified position. 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 00f5b0c5..2190e13a 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 @@ -175,6 +175,36 @@ internal open class MatchJournalImpl( if (currentPos() != until) throw IllegalStateException() } + override fun dropDescendantsWhile(ancestor: Chunk, dropIf: (Chunk) -> Boolean) { + // starts iterating from the Chunk which is next after current + // leaves 'current' and 'posPtr' intact + val droppedIds = mutableListOf() + val start = current + + while (posPtr.hasNext()) { + current = posPtr.next() + if (!current.isDescendantOf(ancestor.id)) { + break + } + + if (dropIf(current)) { + droppedIds.add(current.id) + // no need to 'resetOccurrences' because journal position is left intact + posPtr.remove() + } else if (current.justifications.intersects(droppedIds)) { + // drop descendants of dropped Chunks + posPtr.remove() + } + } + + // rollback to the start + while (current != start) { + current = posPtr.previous() + } + // make ptr point right after 'current' in case we changed anything + if (posPtr.hasNext()) posPtr.next() + } + private fun resetOccurrences(occSpecs: Iterable) = occSpecs.forEach { if (it.discarded) {