diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/Store.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/Store.kt index c32097ed..40304246 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/Store.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/Store.kt @@ -55,29 +55,38 @@ internal class Store : LogicalObserver { } + /** + * Copy constructor that accepts a view on the store. + * This can be a view on the store from previous run of the program. + */ constructor(copyFrom: StoreView, currentFrame: () -> FrameObservable) { this.currentFrame = currentFrame - var l2o = Maps.of>, IdHashSet>() - val storeItems = IdentityHashMap() - copyFrom.allOccurrences().forEach { occ -> - val item = occ.constraint().occurrence(occ.arguments(), currentFrame) - storeItems.put(occ, item) - occ.arguments().forEach { arg -> + + var log2occs = Maps.of>, IdHashSet>() + val orig2occ = IdentityHashMap() + + // process the original data and make copies as needed + for (orig in copyFrom.allOccurrences()) { + val occ = orig.constraint().occurrence(orig.arguments(), currentFrame) + orig2occ[orig] = occ + for (arg in orig.arguments()) { when (arg) { is Logical<*> -> { - l2o = l2o.put(IdWrapper(arg.findRoot()), - l2o[IdWrapper(arg.findRoot())]?.add(item) ?: singletonIdSet(item)) + val key = IdWrapper(arg.findRoot()) + log2occs = log2occs.put(key, + log2occs[key]?.add(occ) ?: singletonIdSet(occ)) + currentFrame().addObserver(arg) { frame -> frame.storeObserver() } } } } - + occ.stored = true } - this.logical2occurrences = l2o - this.symbol2occurrences = copyFrom.constraintSymbols().fold(Maps.of()) { map, sym -> - val copyFrom1 = copyFrom.occurrences(sym).map { occ -> storeItems.get(occ)!! } - val idHashSet = IdHashSet( copyFrom1 ) - - map.put(sym, idHashSet) + + // set internal structures + this.logical2occurrences = log2occs + this.symbol2occurrences = copyFrom.constraintSymbols().fold(Maps.of()) { pmap, csym -> + val occs = IdHashSet(copyFrom.occurrences(csym).map { occ -> orig2occ.get(occ)!! }) + pmap.put(csym, occs) } } @@ -112,6 +121,7 @@ internal class Store : LogicalObserver { symbol2occurrences[symbol]?.add(occ) ?: singletonIdSet(occ)) for (arg in occ.arguments()) { + // FIXME extracting the value is unnecessary here val value = if (arg is Logical<*> && arg.isBound) arg.findRoot().value() else arg when (value) { is Logical<*> -> { diff --git a/reactor/Test/src/program/MockProgram.kt b/reactor/Test/src/program/MockProgram.kt index 72084d83..7c5a8729 100644 --- a/reactor/Test/src/program/MockProgram.kt +++ b/reactor/Test/src/program/MockProgram.kt @@ -8,6 +8,7 @@ import jetbrains.mps.logic.reactor.logical.MetaLogical import jetbrains.mps.logic.reactor.program.* import java.util.* import java.util.Collections.* +import kotlin.collections.LinkedHashMap class ProgramBuilder(val registry: MockConstraintRegistry) { @@ -22,17 +23,24 @@ class ProgramBuilder(val registry: MockConstraintRegistry) { } -open class HandlerBuilder(val name: String) { - val rules = ArrayList() +class HandlerBuilder(val name: String) { - fun appendRule(rule: Rule) { - rules.add(rule) + val rules = LinkedHashMap() + + constructor(name: String, handler: Handler) : this(name) { + for (r in handler.rules()) { + appendRule(r) + } } - fun toHandler(): Handler = MockHandler(name, rules) + fun appendRule(rule: Rule) { + rules[rule.tag()] = rule + } + + fun toHandler(): Handler = MockHandler(name, rules.values.toList()) } -open class RuleBuilder(val tag: String) { +class RuleBuilder(val tag: String) { val kept = ArrayList() val replaced = ArrayList() val guard = ArrayList() diff --git a/reactor/Test/test/RulesHelper.kt b/reactor/Test/test/RulesHelper.kt index c6642da1..5a3819d4 100644 --- a/reactor/Test/test/RulesHelper.kt +++ b/reactor/Test/test/RulesHelper.kt @@ -4,6 +4,7 @@ import jetbrains.mps.logic.reactor.program.* import program.MockConstraint import solver.TestEqPredicate import java.util.* +import kotlin.collections.HashMap /** * @author Fedor Isakov @@ -32,11 +33,7 @@ class Builder(var handlers: List) : RuleLookup { } -fun programWithRules(vararg ruleBuilders: () -> Rule): Builder { - return builder(arrayOf(handler("test", * ruleBuilders))) -} - -private fun builder(handlerBlocks: Array Handler>): Builder { +private fun createBuilder(handlerBlocks: Array Handler>): Builder { val handlers = ArrayList() for (block in handlerBlocks) { handlers.add(block()) @@ -44,7 +41,16 @@ private fun builder(handlerBlocks: Array Handler>): Builder { return Builder(handlers) } -fun handler(name: String, vararg ruleBlocks: () -> Rule): () -> Handler = { +private fun updateBuilder(builder:Builder, handlerBlocks: Array Handler>): Builder { + val name2handler = HashMap(builder.handlers.map { it.name() to it }.toMap()) + for (block in handlerBlocks) { + val h = block() + name2handler[h.name()] = h + } + return Builder(name2handler.values.toList()) +} + +private fun createHandler(name: String, vararg ruleBlocks: () -> Rule): () -> Handler = { val hb = HandlerBuilder(name) for (block in ruleBlocks) { hb.appendRule(block()) @@ -52,6 +58,22 @@ fun handler(name: String, vararg ruleBlocks: () -> Rule): () -> Handler = { hb.toHandler() } +private fun updateHandler(name: String, handler: Handler, vararg ruleBlocks: () -> Rule): () -> Handler = { + val hb = HandlerBuilder(name, handler) + for (block in ruleBlocks) { + hb.appendRule(block()) + } + hb.toHandler() +} + +// builder DSL for constructing program + +fun programWithRules(vararg ruleBuilders: () -> Rule): Builder = + createBuilder(arrayOf(createHandler("test", * ruleBuilders))) + +fun Builder.programWithRules(vararg ruleBuilders: () -> Rule): Builder = + updateBuilder(this, arrayOf(updateHandler("test", handlers.first(), * ruleBuilders))) + fun rule(tag: String, vararg component: RuleBuilder.() -> Unit): () -> Rule = { val rb = RuleBuilder(tag) for (cmp in component) { @@ -92,6 +114,15 @@ fun equals(left: Any, right: Any): ConjBuilder.() -> Unit = { fun occurrence(id: String, vararg args: Any): Occurrence = MockConstraint(ConstraintSymbol.symbol(id, args.size)).occurrence(listOf(* args), { fooObservable }) +fun sym0(id: String): ConstraintSymbol = + ConstraintSymbol(id, 0) + +fun sym1(id: String): ConstraintSymbol = + ConstraintSymbol(id, 1) + +fun sym2(id: String): ConstraintSymbol = + ConstraintSymbol(id, 2) + object fooObservable : FrameObservable { override fun storeObserver(): LogicalObserver { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. diff --git a/reactor/Test/test/TestIncrementalProgram.kt b/reactor/Test/test/TestIncrementalProgram.kt index 3541a80f..267637ba 100644 --- a/reactor/Test/test/TestIncrementalProgram.kt +++ b/reactor/Test/test/TestIncrementalProgram.kt @@ -56,20 +56,14 @@ class TestIncrementalProgram { } private fun Builder.relaunch(name: String, storeView: StoreView, resultHandler: (EvaluationResult) -> Unit) { - + val result = EvaluationSession.newSession(program(name)) + .withParameter(EvaluationSession.ParameterKey.of("main", Constraint::class.java), MockConstraint(ConstraintSymbol("main", 0))) + .withStoreView(storeView) + .start() + result.failure()?.let { throw it.cause } + resultHandler(result) } - -// private fun StoreView.launch(name: String): StoreView { -// val programBuilder = ProgramBuilder(MockConstraintRegistry()) -// for (h in handlers) { -// programBuilder.addHandler(h) -// } -// val result = EvaluationSession.newSession(programBuilder.program(name)).withParam("main", MockConstraint(ConstraintSymbol("main", 0))).start() -// return result.storeView() -// -// } - @Test fun replace() { programWithRules( @@ -89,10 +83,22 @@ class TestIncrementalProgram { ) ) ).launch("replace") { result -> - result.storeView().constraintSymbols() shouldBe setOf(ConstraintSymbol("foo", 0), ConstraintSymbol("bar", 0)) + result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar")) }.also { (builder, storeView) -> + builder.programWithRules ( + rule("main.foo", + headKept( + constraint("foo") + ), + body( + constraint("baz") + ) + ) + ).relaunch("test", storeView) { result -> + result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"), sym0("baz")) + } } }