Introduce StoreView as a parameter to launching evaluation session. Minor code refactoring/extracting.
This commit is contained in:
parent
c68d9a0bd7
commit
cae150819f
|
|
@ -6,9 +6,6 @@ import jetbrains.mps.logic.reactor.program.Program;
|
|||
import jetbrains.mps.logic.reactor.program.PredicateSymbol;
|
||||
import jetbrains.mps.logic.reactor.program.ConstraintSymbol;
|
||||
|
||||
/**
|
||||
* AKA "Handler"
|
||||
*/
|
||||
public abstract class EvaluationSession {
|
||||
|
||||
public static EvaluationSession current() {
|
||||
|
|
@ -31,6 +28,8 @@ public abstract class EvaluationSession {
|
|||
|
||||
public abstract EvaluationSession.Config withTrace(EvaluationTrace computingTracer);
|
||||
|
||||
public abstract EvaluationSession.Config withStoreView(StoreView storeView);
|
||||
|
||||
public abstract EvaluationSession.Config withParam(String key, Object param);
|
||||
|
||||
public abstract EvaluationSession start(SessionSolver sessionSolver);
|
||||
|
|
|
|||
|
|
@ -1,164 +1,33 @@
|
|||
package jetbrains.mps.logic.reactor.core
|
||||
|
||||
import com.github.andrewoma.dexx.collection.ConsList
|
||||
import com.github.andrewoma.dexx.collection.Maps
|
||||
import com.github.andrewoma.dexx.collection.Map as PersMap
|
||||
import jetbrains.mps.logic.reactor.evaluation.*
|
||||
import jetbrains.mps.logic.reactor.logical.Logical
|
||||
import jetbrains.mps.logic.reactor.logical.LogicalContext
|
||||
import jetbrains.mps.logic.reactor.logical.LogicalUnification
|
||||
import jetbrains.mps.logic.reactor.logical.MetaLogical
|
||||
import jetbrains.mps.logic.reactor.program.*
|
||||
import jetbrains.mps.logic.reactor.util.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author Fedor Isakov
|
||||
*/
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.Predicate
|
||||
import jetbrains.mps.logic.reactor.program.Program
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
import jetbrains.mps.logic.reactor.util.Profiler
|
||||
import jetbrains.mps.logic.reactor.util.profile
|
||||
import com.github.andrewoma.dexx.collection.Map as PersMap
|
||||
|
||||
|
||||
class FrameStack : LogicalObserver {
|
||||
|
||||
lateinit var current: Frame
|
||||
|
||||
val observing = HashSet<IdWrapper<Logical<*>>>()
|
||||
|
||||
constructor() {
|
||||
this.current = Frame(this)
|
||||
}
|
||||
|
||||
fun push(): Frame {
|
||||
val frame = Frame(this, current)
|
||||
this.current = frame
|
||||
return frame
|
||||
}
|
||||
|
||||
fun reset(frame: Frame): Unit {
|
||||
this.current = frame
|
||||
}
|
||||
|
||||
fun addObserver(logical: Logical<*>) {
|
||||
val token = IdWrapper(logical)
|
||||
if (!observing.contains(token)) {
|
||||
logical.addObserver(this)
|
||||
observing.add(token)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeObserver(logical: Logical<*>) {
|
||||
// NOP
|
||||
// yes, keep listening, the updates are still filtered down the stream
|
||||
}
|
||||
|
||||
override fun valueUpdated(logical: Logical<*>) {
|
||||
current.valueUpdated(logical)
|
||||
}
|
||||
|
||||
override fun parentUpdated(logical: Logical<*>) {
|
||||
current.parentUpdated(logical)
|
||||
}
|
||||
}
|
||||
|
||||
interface StoreHolder {
|
||||
|
||||
fun store(): Store
|
||||
|
||||
fun addObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver)
|
||||
|
||||
fun removeObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver)
|
||||
}
|
||||
|
||||
|
||||
class Frame : LogicalObserver, StoreHolder
|
||||
class Controller(
|
||||
val program: Program,
|
||||
val trace: EvaluationTrace = EvaluationTrace.NULL,
|
||||
val profiler: Profiler? = null,
|
||||
val storeView: StoreView? = null)
|
||||
{
|
||||
val prev: Frame?
|
||||
|
||||
val store: Store
|
||||
private val ruleIndex: RuleIndex = RuleIndex(program.handlers())
|
||||
|
||||
private var stack: FrameStack
|
||||
|
||||
private lateinit var observers: PersMap<IdWrapper<Logical<*>>, ConsList<(StoreHolder) -> LogicalObserver>>
|
||||
|
||||
constructor(stack: FrameStack, prev: Frame? = null) {
|
||||
this.stack = stack
|
||||
this.prev = prev
|
||||
this.observers = prev?.observers ?: Maps.of()
|
||||
this.store = Store(prev?.store ?: Store { stack.current }, { stack.current })
|
||||
}
|
||||
|
||||
override fun store() = store
|
||||
|
||||
override fun addObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver) {
|
||||
val logicalId = IdWrapper(logical)
|
||||
if (!observers.containsKey(logicalId)) {
|
||||
stack.addObserver(logical)
|
||||
}
|
||||
this.observers = observers.put(logicalId,
|
||||
observers[logicalId]?.prepend(obs) ?: cons(obs))
|
||||
}
|
||||
|
||||
override fun removeObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver) {
|
||||
val logicalId = IdWrapper(logical)
|
||||
observers[logicalId].remove(obs)?.let { newList ->
|
||||
this.observers = observers.put(logicalId, newList)
|
||||
if (newList.isEmpty) {
|
||||
stack.removeObserver(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun valueUpdated(logical: Logical<*>) {
|
||||
observers[IdWrapper(logical)]?.let { list ->
|
||||
for (obs in list) {
|
||||
obs(this).valueUpdated(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parentUpdated(logical: Logical<*>) {
|
||||
observers[IdWrapper(logical)]?.let { list ->
|
||||
for (obs in list) {
|
||||
obs(this).parentUpdated(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Controller {
|
||||
|
||||
private val frameStack = FrameStack()
|
||||
private val frameStack = FrameStack(storeView)
|
||||
|
||||
// persistent (functional) object. reassigned on update
|
||||
private var propHistory = PropagationHistory()
|
||||
|
||||
val program: Program
|
||||
|
||||
val ruleIndex: RuleIndex
|
||||
|
||||
private val trace: EvaluationTrace
|
||||
|
||||
private val profiler: Profiler?
|
||||
|
||||
constructor(
|
||||
program: Program,
|
||||
trace: EvaluationTrace = EvaluationTrace.NULL,
|
||||
profiler: Profiler? = null,
|
||||
// for testing purposes only
|
||||
occurrences: Iterable<ConstraintOccurrence>? = null)
|
||||
{
|
||||
this.program = program
|
||||
this.ruleIndex = RuleIndex(program.handlers())
|
||||
this.trace = trace
|
||||
this.profiler = profiler
|
||||
if (occurrences != null) {
|
||||
frameStack.current.store.storeAll(occurrences)
|
||||
}
|
||||
}
|
||||
|
||||
fun storeView(): StoreView =
|
||||
frameStack.current.store.view()
|
||||
fun storeView(): StoreView = frameStack.current.store.view()
|
||||
|
||||
fun activate(constraint: Constraint) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
package jetbrains.mps.logic.reactor.core
|
||||
|
||||
import com.github.andrewoma.dexx.collection.ConsList
|
||||
import com.github.andrewoma.dexx.collection.Map
|
||||
import com.github.andrewoma.dexx.collection.Maps
|
||||
import jetbrains.mps.logic.reactor.evaluation.StoreView
|
||||
import jetbrains.mps.logic.reactor.logical.Logical
|
||||
import jetbrains.mps.logic.reactor.util.IdWrapper
|
||||
import jetbrains.mps.logic.reactor.util.cons
|
||||
import jetbrains.mps.logic.reactor.util.remove
|
||||
import java.util.*
|
||||
|
||||
internal class Frame: LogicalObserver, StoreKeeper {
|
||||
|
||||
val stack: FrameStack
|
||||
|
||||
val store: Store
|
||||
|
||||
private var observers: Map<IdWrapper<Logical<*>>, ConsList<(StoreKeeper) -> LogicalObserver>>
|
||||
|
||||
constructor(stack: FrameStack) {
|
||||
this.stack = stack
|
||||
this.store = Store() { stack.current }
|
||||
this.observers = Maps.of()
|
||||
}
|
||||
|
||||
constructor(stack: FrameStack, prev: Frame) {
|
||||
this.stack = stack
|
||||
this.store = Store(prev.store) { stack.current }
|
||||
this.observers = prev.observers
|
||||
}
|
||||
|
||||
constructor(stack: FrameStack, storeView: StoreView) {
|
||||
this.stack = stack
|
||||
this.store = Store(storeView) { stack.current }
|
||||
this.observers = Maps.of()
|
||||
}
|
||||
|
||||
override fun store() = store
|
||||
|
||||
override fun addObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver) {
|
||||
val logicalId = IdWrapper(logical)
|
||||
if (!observers.containsKey(logicalId)) {
|
||||
stack.addObserver(logical)
|
||||
}
|
||||
this.observers = observers.put(logicalId,
|
||||
observers[logicalId]?.prepend(obs) ?: cons(obs))
|
||||
}
|
||||
|
||||
override fun removeObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver) {
|
||||
val logicalId = IdWrapper(logical)
|
||||
observers[logicalId].remove(obs)?.let { newList ->
|
||||
this.observers = observers.put(logicalId, newList)
|
||||
if (newList.isEmpty) {
|
||||
stack.removeObserver(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun valueUpdated(logical: Logical<*>) {
|
||||
observers[IdWrapper(logical)]?.let { list ->
|
||||
for (obs in list) {
|
||||
obs(this).valueUpdated(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parentUpdated(logical: Logical<*>) {
|
||||
observers[IdWrapper(logical)]?.let { list ->
|
||||
for (obs in list) {
|
||||
obs(this).parentUpdated(logical)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class FrameStack(storeView: StoreView?) : LogicalObserver {
|
||||
|
||||
var current: Frame
|
||||
|
||||
val observing = HashSet<IdWrapper<Logical<*>>>()
|
||||
|
||||
init {
|
||||
this.current = if (storeView != null) Frame(this, storeView) else Frame(this)
|
||||
}
|
||||
|
||||
fun push(): Frame {
|
||||
val frame = Frame(this, current)
|
||||
this.current = frame
|
||||
return frame
|
||||
}
|
||||
|
||||
fun reset(frame: Frame): Unit {
|
||||
this.current = frame
|
||||
}
|
||||
|
||||
fun addObserver(logical: Logical<*>) {
|
||||
val token = IdWrapper(logical)
|
||||
if (!observing.contains(token)) {
|
||||
logical.addObserver(this)
|
||||
observing.add(token)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeObserver(logical: Logical<*>) {
|
||||
// NOP
|
||||
// yes, keep listening, the updates are still filtered down the stream
|
||||
}
|
||||
|
||||
override fun valueUpdated(logical: Logical<*>) {
|
||||
current.valueUpdated(logical)
|
||||
}
|
||||
|
||||
override fun parentUpdated(logical: Logical<*>) {
|
||||
current.parentUpdated(logical)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,26 +21,43 @@ interface SessionObjects {
|
|||
|
||||
}
|
||||
|
||||
class MemEvaluationSession : EvaluationSession, SessionObjects {
|
||||
class MemEvaluationSession private constructor (
|
||||
val program: Program,
|
||||
val sessionSolver: SessionSolver,
|
||||
val trace: EvaluationTrace) : EvaluationSession(), SessionObjects
|
||||
{
|
||||
|
||||
lateinit var controller: Controller
|
||||
|
||||
private fun launch(main: Constraint, profiler: Profiler?, storeView: StoreView?) {
|
||||
this.controller = Controller(program, trace, profiler, storeView)
|
||||
controller.activate(main)
|
||||
}
|
||||
|
||||
private class Config(val program: Program) : EvaluationSession.Config() {
|
||||
|
||||
val myPredicateSymbols = ArrayList<PredicateSymbol>()
|
||||
val myParameters = HashMap<String, Any?>()
|
||||
var myEvaluationTrace: EvaluationTrace = EvaluationTrace.NULL
|
||||
val predicateSymbols = ArrayList<PredicateSymbol>()
|
||||
val parameters = HashMap<String, Any?>()
|
||||
var evaluationTrace: EvaluationTrace = EvaluationTrace.NULL
|
||||
var storeView: StoreView? = null
|
||||
|
||||
override fun withPredicates(vararg predicateSymbols: PredicateSymbol): EvaluationSession.Config {
|
||||
myPredicateSymbols.addAll(Arrays.asList(* predicateSymbols))
|
||||
this.predicateSymbols.addAll(Arrays.asList(* predicateSymbols))
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withTrace(computingTracer: EvaluationTrace): EvaluationSession.Config {
|
||||
myEvaluationTrace = computingTracer
|
||||
this.evaluationTrace = computingTracer
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withStoreView(storeView: StoreView): EvaluationSession.Config {
|
||||
this.storeView = storeView
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withParam(key: String, param: Any): EvaluationSession.Config {
|
||||
myParameters.put(key, param)
|
||||
this.parameters.put(key, param)
|
||||
return this
|
||||
}
|
||||
|
||||
|
|
@ -48,16 +65,17 @@ class MemEvaluationSession : EvaluationSession, SessionObjects {
|
|||
var session = ourBackend.ourSession.get()
|
||||
if (session != null) throw IllegalStateException("session already active")
|
||||
|
||||
val predicateSymbols = myPredicateSymbols.toArray<PredicateSymbol>(arrayOfNulls(myPredicateSymbols.size))
|
||||
sessionSolver.init(myEvaluationTrace, * predicateSymbols)
|
||||
sessionSolver.init(evaluationTrace, * predicateSymbols.toArray<PredicateSymbol>(arrayOfNulls(predicateSymbols.size)))
|
||||
|
||||
session = MemEvaluationSession(program, sessionSolver, myEvaluationTrace)
|
||||
ourBackend.ourSession.set(session)
|
||||
|
||||
val durations = myParameters.get("profiling.data") as MutableMap<String, String>?
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val durations =
|
||||
parameters.get("profiling.data") as MutableMap<String, String>?
|
||||
val profiler = durations?.let { Profiler() }
|
||||
|
||||
session = MemEvaluationSession(program, sessionSolver, evaluationTrace)
|
||||
ourBackend.ourSession.set(session)
|
||||
try {
|
||||
session.launch(myParameters["main"] as Constraint, profiler)
|
||||
session.launch(parameters["main"] as Constraint, profiler, storeView)
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
|
|
@ -76,23 +94,6 @@ class MemEvaluationSession : EvaluationSession, SessionObjects {
|
|||
}
|
||||
}
|
||||
|
||||
val program: Program
|
||||
val sessionSolver: SessionSolver
|
||||
val trace: EvaluationTrace
|
||||
|
||||
lateinit var controller: Controller
|
||||
|
||||
private constructor(program: Program, sessionSolver: SessionSolver, trace: EvaluationTrace): super() {
|
||||
this.program = program
|
||||
this.sessionSolver = sessionSolver
|
||||
this.trace = trace
|
||||
}
|
||||
|
||||
fun launch(main: Constraint, profiler: Profiler?) {
|
||||
this.controller = Controller(program, trace, profiler)
|
||||
controller.activate(main)
|
||||
}
|
||||
|
||||
override fun handler() = controller
|
||||
|
||||
override fun sessionSolver(): SessionSolver = sessionSolver
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import jetbrains.mps.logic.reactor.logical.Logical
|
|||
import jetbrains.mps.logic.reactor.logical.LogicalContext
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.Program
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author Fedor Isakov
|
||||
*/
|
||||
|
||||
|
||||
fun Constraint.occurrence(currentFrame: () -> Frame, program: Program, context: LogicalContext): ConstraintOccurrence =
|
||||
internal fun Constraint.occurrence(currentFrame: () -> Frame, program: Program, context: LogicalContext): ConstraintOccurrence =
|
||||
Occurrence(currentFrame, this, program.occurrenceArguments(this, context))
|
||||
|
||||
private data class Occurrence (val currentFrame: () -> Frame, val constraint: Constraint, val arguments: List<*>) :
|
||||
|
|
|
|||
|
|
@ -31,9 +31,23 @@ fun ConstraintOccurrence.isAlive(): Boolean =
|
|||
(this as StoreItem).alive
|
||||
|
||||
interface StoreItem {
|
||||
|
||||
var alive: Boolean
|
||||
|
||||
var stored: Boolean
|
||||
|
||||
fun terminate(): Unit
|
||||
|
||||
}
|
||||
|
||||
interface StoreKeeper {
|
||||
|
||||
fun store(): Store
|
||||
|
||||
fun addObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver)
|
||||
|
||||
fun removeObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver)
|
||||
|
||||
}
|
||||
|
||||
interface OccurrenceIndex {
|
||||
|
|
@ -55,7 +69,7 @@ interface OccurrenceIndex {
|
|||
*/
|
||||
class Store : LogicalObserver, OccurrenceIndex {
|
||||
|
||||
val currentFrame: () -> StoreHolder
|
||||
val currentFrame: () -> StoreKeeper
|
||||
|
||||
var symbol2occurrences: PersMap<ConstraintSymbol, IdHashSet<ConstraintOccurrence>>
|
||||
|
||||
|
|
@ -65,8 +79,7 @@ class Store : LogicalObserver, OccurrenceIndex {
|
|||
|
||||
var value2occurrences: PersMap<Any, IdHashSet<ConstraintOccurrence>>
|
||||
|
||||
constructor(copyFrom: Store, currentFrame: () -> StoreHolder)
|
||||
{
|
||||
constructor(copyFrom: Store, currentFrame: () -> StoreKeeper) {
|
||||
this.currentFrame = currentFrame
|
||||
this.symbol2occurrences = copyFrom.symbol2occurrences
|
||||
this.logical2occurrences = copyFrom.logical2occurrences
|
||||
|
|
@ -74,7 +87,32 @@ class Store : LogicalObserver, OccurrenceIndex {
|
|||
this.value2occurrences = copyFrom.value2occurrences
|
||||
}
|
||||
|
||||
constructor(currentFrame: () -> StoreHolder) {
|
||||
constructor(copyFrom: StoreView, currentFrame: () -> StoreKeeper) {
|
||||
this.currentFrame = currentFrame
|
||||
this.symbol2occurrences = copyFrom.constraintSymbols()
|
||||
.fold(Maps.of()) { map, sym -> map.put(sym, IdHashSet(copyFrom.occurrences(sym))) }
|
||||
|
||||
var l2o = Maps.of<IdWrapper<Logical<*>>, IdHashSet<ConstraintOccurrence>>()
|
||||
var t2o = TermTrie<ConstraintOccurrence>()
|
||||
var v2o = Maps.of<Any, IdHashSet<ConstraintOccurrence>>()
|
||||
|
||||
copyFrom.allOccurrences().forEach { occ ->
|
||||
occ.arguments().forEach { a ->
|
||||
when (a) {
|
||||
is Logical<*> -> l2o = l2o.put(IdWrapper(a), l2o[IdWrapper(a)]?.add(occ) ?: singletonSet(occ))
|
||||
is Term -> t2o = t2o.put(a, occ)
|
||||
is Any -> v2o = v2o.put(a, v2o[a]?.add(occ) ?: singletonSet(occ))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.logical2occurrences = l2o
|
||||
this.term2occurrences = t2o
|
||||
this.value2occurrences = v2o
|
||||
}
|
||||
|
||||
constructor(currentFrame: () -> StoreKeeper) {
|
||||
this.currentFrame = currentFrame
|
||||
this.symbol2occurrences = Maps.of()
|
||||
this.logical2occurrences = Maps.of()
|
||||
|
|
@ -121,12 +159,6 @@ class Store : LogicalObserver, OccurrenceIndex {
|
|||
}
|
||||
}
|
||||
|
||||
fun storeAll(all: Iterable<ConstraintOccurrence>): Unit {
|
||||
for(occ in all) {
|
||||
store(occ)
|
||||
}
|
||||
}
|
||||
|
||||
fun store(occ: ConstraintOccurrence): Unit {
|
||||
val symbol = occ.constraint().symbol()
|
||||
|
||||
|
|
@ -253,7 +285,7 @@ class Store : LogicalObserver, OccurrenceIndex {
|
|||
|
||||
}
|
||||
|
||||
class StoreViewImpl(occurrences: Sequence<ConstraintOccurrence>) : StoreView {
|
||||
private class StoreViewImpl(occurrences: Sequence<ConstraintOccurrence>) : StoreView {
|
||||
|
||||
val allOccurrences = occurrences.toSet()
|
||||
|
||||
|
|
@ -263,10 +295,7 @@ class StoreViewImpl(occurrences: Sequence<ConstraintOccurrence>) : StoreView {
|
|||
|
||||
override fun allOccurrences(): Iterable<ConstraintOccurrence> = allOccurrences
|
||||
|
||||
override fun occurrences(symbol: ConstraintSymbol?): Iterable<ConstraintOccurrence> =
|
||||
override fun occurrences(symbol: ConstraintSymbol): Iterable<ConstraintOccurrence> =
|
||||
allOccurrences.filter { co -> co.constraint().symbol() == symbol }.toSet()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,39 +14,48 @@ class IdHashSet<E> : AbstractSet<E> {
|
|||
|
||||
}
|
||||
|
||||
lateinit var store: DerivedKeyHashMap<Int, E>
|
||||
var storage: DerivedKeyHashMap<Int, E>
|
||||
|
||||
constructor() {
|
||||
this.store = DerivedKeyHashMap(object : KeyFunction<Int, E> {
|
||||
override fun key(value: E): Int = idkey(value)
|
||||
})
|
||||
this.storage = emptyStorage()
|
||||
}
|
||||
|
||||
constructor(setStore: DerivedKeyHashMap<Int, E>) {
|
||||
this.store = setStore
|
||||
constructor(storage: DerivedKeyHashMap<Int, E>) {
|
||||
this.storage = storage
|
||||
}
|
||||
|
||||
override fun add(value: E): IdHashSet<E> = IdHashSet(store.put(idkey(value), value))
|
||||
constructor(copyFrom: Iterable<E>) {
|
||||
this.storage = copyFrom.fold(emptyStorage()) { s, e -> s.put(idkey(e), e) }
|
||||
}
|
||||
|
||||
override fun contains(value: E): Boolean = store.containsKey(idkey(value))
|
||||
override fun add(value: E): IdHashSet<E> = IdHashSet(storage.put(idkey(value), value))
|
||||
|
||||
override fun remove(value: E): IdHashSet<E> = IdHashSet(store.remove(idkey(value)))
|
||||
override fun contains(value: E): Boolean = storage.containsKey(idkey(value))
|
||||
|
||||
override fun remove(value: E): IdHashSet<E> = IdHashSet(storage.remove(idkey(value)))
|
||||
|
||||
override fun iterator(): MutableIterator<E> = object: MutableIterator<E> {
|
||||
|
||||
val storeIt = store.iterator()
|
||||
val storageIt = storage.iterator()
|
||||
|
||||
override fun hasNext(): Boolean = storeIt.hasNext()
|
||||
override fun hasNext(): Boolean = storageIt.hasNext()
|
||||
|
||||
override fun next(): E = storeIt.next().component2()
|
||||
override fun next(): E = storageIt.next().component2()
|
||||
|
||||
override fun remove() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
private fun emptyStorage(): DerivedKeyHashMap<Int, E> {
|
||||
return DerivedKeyHashMap(object : KeyFunction<Int, E> {
|
||||
override fun key(value: E): Int = idkey(value)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <E> emptySet(): IdHashSet<E> = IdHashSet.EMPTY_SET as IdHashSet<E>
|
||||
|
||||
fun <E> singletonSet(e: E): IdHashSet<E> = emptySet<E>().add(e)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import jetbrains.mps.logic.reactor.core.Controller
|
||||
import jetbrains.mps.logic.reactor.core.SessionObjects
|
||||
import jetbrains.mps.logic.reactor.core.Store
|
||||
import jetbrains.mps.logic.reactor.evaluation.*
|
||||
import jetbrains.mps.logic.reactor.logical.Logical
|
||||
import jetbrains.mps.logic.reactor.logical.LogicalContext
|
||||
|
|
@ -60,11 +61,22 @@ class TestController {
|
|||
val solver = sessionSolver(env.expressionSolver, env.equalsSolver)
|
||||
MockSession.init(solver)
|
||||
val program = MockProgram("test", handlers, registry = MockConstraintRegistry(solver))
|
||||
val controller = Controller(program, occurrences = listOf(* occurrences))
|
||||
val controller = Controller(program, storeView = MockStoreView(listOf(* occurrences)))
|
||||
MockSession.ourBackend.session.controller = controller
|
||||
return controller
|
||||
}
|
||||
|
||||
private class MockStoreView(val occurrences: List<ConstraintOccurrence>) : StoreView {
|
||||
val symbols = occurrences.map { it.constraint().symbol() }.toSet()
|
||||
|
||||
override fun constraintSymbols(): Iterable<ConstraintSymbol> = symbols
|
||||
|
||||
override fun allOccurrences(): Iterable<ConstraintOccurrence> = occurrences
|
||||
|
||||
override fun occurrences(symbol: ConstraintSymbol): Iterable<ConstraintOccurrence> =
|
||||
occurrences.filter { it.constraint().symbol() == symbol }
|
||||
}
|
||||
|
||||
private fun <T : Any> eq(left: T, right: T) = left eq right
|
||||
|
||||
private fun <T : Any> is_eq(left: T, right: T): Boolean = left is_eq right
|
||||
|
|
|
|||
|
|
@ -14,20 +14,20 @@ import org.junit.Before
|
|||
|
||||
class TestOccurrenceStore {
|
||||
|
||||
class MockProxy(val _store: () -> Store) : LogicalObserver, StoreHolder {
|
||||
internal class MockProxy(val _store: () -> Store) : LogicalObserver, StoreKeeper {
|
||||
|
||||
private var observerList = emptyConsList<Pair<Logical<*>, LogicalObserver>>()
|
||||
|
||||
override fun store(): Store = _store()
|
||||
|
||||
override fun addObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver) {
|
||||
override fun addObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver) {
|
||||
if (!observerList.any { obs -> obs.first === logical }) { // referential equality!
|
||||
logical.addObserver(this)
|
||||
}
|
||||
this.observerList = observerList.prepend(logical.to(obs(this)))
|
||||
}
|
||||
|
||||
override fun removeObserver(logical: Logical<*>, obs: (StoreHolder) -> LogicalObserver) = TODO()
|
||||
override fun removeObserver(logical: Logical<*>, obs: (StoreKeeper) -> LogicalObserver) = TODO()
|
||||
|
||||
override fun valueUpdated(logical: Logical<*>) {
|
||||
for (obs in observerList) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue