diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt index 5740152f..899cd1c0 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt @@ -22,13 +22,20 @@ import jetbrains.mps.logic.reactor.core.Occurrence import jetbrains.mps.logic.reactor.evaluation.RuleMatch import jetbrains.mps.logic.reactor.evaluation.StoreView import java.util.* +import kotlin.collections.ArrayList interface MatchHistory { + data class View(val chunks: List, val nextChunkId: Int) + data class Chunk(val match: RuleMatch, val id: Int, val justifications: TIntSet) { - data class Entry(val occ: Occurrence, val isDiscarded: Boolean = false) + data class Entry(val occ: Occurrence, val isDiscarded: Boolean = false) { + override fun toString() = (if (isDiscarded) '-' else '+') + occ.toString() + } var occurrences: MutableList = mutableListOf() + + override fun toString() = "(id=$id, $justifications, $occurrences)" } class RemoveChunkIterator(val it: MutableListIterator): Iterator by it { @@ -44,6 +51,7 @@ interface MatchHistory { fun removeIterator(): RemoveChunkIterator fun resetStore() fun storeView(): StoreView + fun view(): MatchHistory.View fun logMatch(match: RuleMatch) fun logOccurence(occ: Occurrence) @@ -56,12 +64,38 @@ interface MatchHistory { fun rollTo(futurePos: HistoryPos) companion object { - fun getMatchHistory(chunkIdSeed: Int = 0): MatchHistory = MatchHistoryImpl(chunkIdSeed) + fun fromSeed(chunkIdSeed: Int = 0): MatchHistory = MatchHistoryImpl(chunkIdSeed) + fun fromView(view: MatchHistory.View): MatchHistory = MatchHistoryImpl(view) } } -internal class MatchHistoryImpl(chunkIdSeed: Int): MatchHistory { +internal class MatchHistoryImpl(view: MatchHistory.View?): MatchHistory { + + private val hist: MutableList + private var nextChunkId: Int + + // private var order: Map = emptyMap() + private val frameStack: FrameStack = FrameStack(null) + + init { + if (view == null) { + hist = LinkedList() + nextChunkId = 0 + } else { + hist = LinkedList(view.chunks) + nextChunkId = view.nextChunkId + } + } + + constructor(chunkIdSeed: Int) : this(null) { + nextChunkId = chunkIdSeed + } + + // FIXME: provide initial chunk? possibly initialized from StoreView, with empty justifications + private lateinit var current: MatchHistory.Chunk + private var pos: MutableListIterator = hist.listIterator() + override fun removeIterator() = MatchHistory.RemoveChunkIterator(hist.listIterator()) @@ -73,6 +107,8 @@ internal class MatchHistoryImpl(chunkIdSeed: Int): MatchHistory { override fun storeView(): StoreView = frameStack.current.store.view() + override fun view() = MatchHistory.View(ArrayList(hist), nextChunkId) + override fun logMatch(match: RuleMatch) { val m = match as RuleMatchImpl @@ -121,8 +157,9 @@ internal class MatchHistoryImpl(chunkIdSeed: Int): MatchHistory { val tp = timepoint as HistoryPosImpl frameStack.reset(tp.frame) - while (tp.chunk != current && pos.hasPrevious()) { + while (pos.hasPrevious()) { current = pos.previous() + if (current == tp.chunk) break pos.remove() } current.occurrences = current.occurrences.take(tp.occsRetained) as MutableList @@ -140,6 +177,7 @@ internal class MatchHistoryImpl(chunkIdSeed: Int): MatchHistory { rollOccurences(current.occurrences) } } + fun rollTo(chunk: MatchHistory.Chunk) { while (current != chunk && pos.hasNext()) { current = pos.next() @@ -162,17 +200,6 @@ internal class MatchHistoryImpl(chunkIdSeed: Int): MatchHistory { // fun resetOrder() { order = hist.mapToIndex() } - private val hist: MutableList = LinkedList() -// private var order: Map = emptyMap() - private val frameStack: FrameStack = FrameStack(null) - - // FIXME: provide initial chunk? possibly initialized from StoreView, with empty justifications - private lateinit var current: MatchHistory.Chunk - private var pos: MutableListIterator = hist.listIterator() - - private var nextChunkId: Int = chunkIdSeed; - - } private fun RuleMatch.headJustifications(): TIntSet { diff --git a/reactor/Test/test/TestMatchHistory.kt b/reactor/Test/test/TestMatchHistory.kt index 7b370459..747ee769 100644 --- a/reactor/Test/test/TestMatchHistory.kt +++ b/reactor/Test/test/TestMatchHistory.kt @@ -1,10 +1,6 @@ import gnu.trove.set.hash.TIntHashSet import jetbrains.mps.logic.reactor.core.* -import jetbrains.mps.logic.reactor.core.internal.createOccurrenceMatcher -import jetbrains.mps.logic.reactor.core.internal.logical import jetbrains.mps.logic.reactor.core.internal.MatchHistory -import jetbrains.mps.logic.reactor.program.ConstraintSymbol -import jetbrains.mps.logic.reactor.program.ConstraintSymbol.symbol import org.junit.Test import org.junit.Assert.* @@ -29,7 +25,7 @@ class TestMatchHistory { @Test fun testJustificationTracking() { - val hist = MatchHistory.getMatchHistory() + val hist = MatchHistory.fromSeed() with(programWithRules( rule("rule1", @@ -125,7 +121,7 @@ class TestMatchHistory { @Test fun testResetThenRoll() { - val hist = MatchHistory.getMatchHistory() + val hist = MatchHistory.fromSeed() with(programWithRules( rule("rule1", @@ -198,7 +194,7 @@ class TestMatchHistory { @Test fun testPushExecReset() { - val hist = MatchHistory.getMatchHistory() + val hist = MatchHistory.fromSeed() with(programWithRules( rule("rule1", @@ -274,6 +270,7 @@ class TestMatchHistory { hist.logOccurence(bazzOcc2) d = d.expand(bazzOcc2) + val oldState = hist.view() val oldStore = hist.storeView().allOccurrences() val savedPos = hist.currentPos() hist.push() @@ -285,16 +282,20 @@ class TestMatchHistory { with(d.matches().first()) { rule().tag() shouldBe "rule4" + hist.view().chunks.size shouldBe 2 hist.logMatch(this) + hist.view().chunks.size shouldBe 3 } val lastOcc = occurrence("last") hist.logOccurence(lastOcc) d = d.expand(lastOcc) + assertNotEquals(oldState.chunks, hist.view().chunks) assertNotEquals(oldStore, hist.storeView().allOccurrences()) hist.reset(savedPos) - assertEquals(oldStore, hist.storeView().allOccurrences()) + hist.view().chunks shouldBe oldState.chunks + hist.storeView().allOccurrences() shouldBe oldStore hist.currentPos().chunk() shouldBe savedPos.chunk() hist.currentPos().occsRetained() shouldBe savedPos.occsRetained()