Handle case of invalidating stale discarding matches (MPSCR-35)
This commit is contained in:
parent
18fc4592f0
commit
efd22872a9
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,13 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
|
|||
*/
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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<Int>()
|
||||
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<MatchJournal.Chunk.Entry>) =
|
||||
occSpecs.forEach {
|
||||
if (it.discarded) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue