Fix the Store implementation and the test harness to support incremental
program launch.
This commit is contained in:
parent
13e8f4a205
commit
09ca1f1236
|
|
@ -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<IdWrapper<Logical<*>>, IdHashSet<Occurrence>>()
|
||||
val storeItems = IdentityHashMap<ConstraintOccurrence, Occurrence>()
|
||||
copyFrom.allOccurrences().forEach { occ ->
|
||||
val item = occ.constraint().occurrence(occ.arguments(), currentFrame)
|
||||
storeItems.put(occ, item)
|
||||
occ.arguments().forEach { arg ->
|
||||
|
||||
var log2occs = Maps.of<IdWrapper<Logical<*>>, IdHashSet<Occurrence>>()
|
||||
val orig2occ = IdentityHashMap<ConstraintOccurrence, Occurrence>()
|
||||
|
||||
// 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<*> -> {
|
||||
|
|
|
|||
|
|
@ -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<Rule>()
|
||||
class HandlerBuilder(val name: String) {
|
||||
|
||||
fun appendRule(rule: Rule) {
|
||||
rules.add(rule)
|
||||
val rules = LinkedHashMap<String, Rule>()
|
||||
|
||||
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<Constraint>()
|
||||
val replaced = ArrayList<Constraint>()
|
||||
val guard = ArrayList<Predicate>()
|
||||
|
|
|
|||
|
|
@ -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<Handler>) : RuleLookup {
|
|||
|
||||
}
|
||||
|
||||
fun programWithRules(vararg ruleBuilders: () -> Rule): Builder {
|
||||
return builder(arrayOf(handler("test", * ruleBuilders)))
|
||||
}
|
||||
|
||||
private fun builder(handlerBlocks: Array<out () -> Handler>): Builder {
|
||||
private fun createBuilder(handlerBlocks: Array<out () -> Handler>): Builder {
|
||||
val handlers = ArrayList<Handler>()
|
||||
for (block in handlerBlocks) {
|
||||
handlers.add(block())
|
||||
|
|
@ -44,7 +41,16 @@ private fun builder(handlerBlocks: Array<out () -> Handler>): Builder {
|
|||
return Builder(handlers)
|
||||
}
|
||||
|
||||
fun handler(name: String, vararg ruleBlocks: () -> Rule): () -> Handler = {
|
||||
private fun updateBuilder(builder:Builder, handlerBlocks: Array<out () -> 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.
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue