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 df84500a..d657fb89 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 @@ -76,15 +76,21 @@ interface MatchJournal : Iterable, EvidenceSource { val cursor: RemovingJournalIterator /** - * Reset journal's position to the beginning, don't modify journal. + * Same as [resetCursor], moves [cursor] before [initialChunk]. */ - fun resetCursor() + fun resetCursor() = resetCursor(Pos(initialChunk(), 0)) /** - * Erase part of the journal between [currentPos] and [pastPos]. - * Resets journal position to specified position. + * Moves [cursor] before [pastPos], so that [ChunkReader.next] is [pastPos]. + * Doesn't modify journal contents, as opposed to [reset]. + */ + fun resetCursor(pastPos: Pos) + + /** + * Erase journal between [currentPos] (erased) and [pastPos] (not erased). + * Moves [cursor] at [pastPos], so that [ChunkReader.current] is [pastPos]. * @param pastPos position to reset to. - * @throws IllegalStateException when position is not from the past (relative to current pos). + * @throws IllegalStateException when position is not from the past (relative to [cursor]). */ fun reset(pastPos: Pos) @@ -92,7 +98,7 @@ interface MatchJournal : Iterable, EvidenceSource { * Replay activated and discarded occurrences logged in journal between current * and provided positions. Advances journal position to specified position. * Idempotent operation (can be called multiple times on same [Pos]]). - * @throws IllegalStateException when position is not from the future (relative to current pos). + * @throws IllegalStateException when [futurePos] is not from the future (relative to [cursor]). */ fun replay(futurePos: Pos) @@ -131,6 +137,12 @@ interface MatchJournal : Iterable, EvidenceSource { */ fun isKnown(chunk: Chunk): Boolean + /** + * Same as [isKnown], but for [Occurrence]. + * Returns [true] for indexed [Occurrence]s. + */ + fun isKnown(occ: Occurrence): Boolean = activatingChunkOf(occ) != null + /** * Returns [Chunk] where [occ] was activated. * Returns null for non-principal occurrences & those not from indexed session. 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 757dd74d..f1899d35 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 @@ -189,19 +189,25 @@ internal open class MatchJournalImpl( override fun isFront(): Boolean = __cursor.atEnd() - override fun reset(pastPos: MatchJournal.Pos) = reset(pastPos, true) + override fun reset(pastPos: MatchJournal.Pos) { + reset(pastPos, true) + replay(pastPos) + } - override fun resetCursor() = reset(Pos(initialChunk(), 0), false) + override fun resetCursor(pastPos: Pos) { + reset(pastPos, false) + } - private fun reset(pastPos: MatchJournal.Pos, removing: Boolean) = with(__cursor) { - moveToPastRemoving(pastPos) { + private fun reset(pastPos: MatchJournal.Pos, removing: Boolean) { + __cursor.moveToPastRemoving(pastPos) { popAncestor() resetOccurrences(it.entries()) - removing + removing && it !== pastPos.chunk } // drop occurrences at final chunk - if (removing) current.entries = current.entries.subList(0, pastPos.entriesCount) - resetOccurrences(current.entries.drop(pastPos.entriesCount)) + if (removing) with(pastPos.chunk as ChunkImpl) { + entries = entries.subList(0, pastPos.entriesCount) + } } private fun popAncestor() { @@ -324,8 +330,9 @@ internal open class MatchJournalImpl( /** - * Walk in journal in direct order ([from] -> [next]) - * while applying [action] to each visited [Chunk]. + * Walk in journal in direct order ([from] -> [current]) + * while applying [action] to each visited [Chunk] + * (not including [from], but including [__current]). * No journal state is changed, except by [action] effects * (i.e. no reset or replay of occurrences is performed). */ @@ -343,21 +350,24 @@ internal open class MatchJournalImpl( } /** - * Walk in journal in inverse order ([next] -> [pastPos]) - * while applying [action] to each visited [Chunk] - * and removing it if [action] return [true] for it. + * Walk in journal in inverse order ([pastPos] <- [current]) while + * applying [action] to each [Chunk] (including [pastPos]) + * and removing it if [action] returns true for it. + * + * Contract: after the call [__next] points to [pastPos]. */ inline fun moveToPastRemoving(pastPos: Pos, action: (Chunk) -> Boolean) { while (!atStart()) { __current = it.previous() + if (action(__current)) { + it.remove() + } if (this at pastPos) { - it.next() // make it point right after _previous_ + __current = it.previous() + it.next() // make it point right after __current updateNext() return } - if (action(current)) { - it.remove() - } } this assertAt pastPos }