Refactoring: simplify contract b/w controller and logical state.

This commit is contained in:
Fedor Isakov 2020-01-14 12:58:22 +01:00
parent 0fbc7f6571
commit 8af582f9b2
10 changed files with 66 additions and 88 deletions

View File

@ -33,9 +33,7 @@ interface Controller {
fun reactivate(occ: Occurrence): FeedbackStatus
fun logicalState(): LogicalStateObservable
fun clearState()
fun logicalStateObservable(): LogicalStateObservable
/** For tests only */
fun evaluate(occ: Occurrence): StoreView

View File

@ -28,14 +28,6 @@ interface LogicalStateObservable {
fun removeForwardingObserver(logical: Logical<*>, observer: ForwardingLogicalObserver)
fun init(controller: Controller): InitToken
interface InitToken {
fun clear()
}
}
interface ForwardingLogicalObserver {

View File

@ -40,7 +40,7 @@ import jetbrains.mps.logic.reactor.util.profile
internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.DispatchingFront,
journal: MatchJournalImpl,
private val ruleIndex: RuleIndex,
val logicalState: LogicalState = LogicalState(),
val logicalState: LogicalState,
private val ispec: IncrementalProgramSpec = IncrementalProgramSpec.DefaultSpec,
val trace: EvaluationTrace = EvaluationTrace.NULL,
val profiler: Profiler? = null)
@ -200,7 +200,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
val histView = view()
resetStore() // clear observers
val rules = ArrayList<Rule>().apply { ruleIndex.forEach { add(it) } }
return SessionTokenImpl(histView, rules, dispatchingFront.state(), logicalState)
return SessionTokenImpl(histView, rules, dispatchingFront.state(), logicalState.clear())
}
/**

View File

@ -36,15 +36,13 @@ internal class ControllerImpl (
val profiler: Profiler? = null) : Controller
{
private val initToken: LogicalStateObservable.InitToken = processing.init(this)
/** For tests only */
override fun storeView(): StoreView = processing.storeView()
/** For tests only */
override fun evaluate(occ: Occurrence): StoreView {
// create the internal occurrence
val active = occ.constraint().occurrence(logicalState(), occ.arguments(), occ.justifications(), object: LogicalContext {
val active = occ.constraint().occurrence(logicalStateObservable(), occ.arguments(), occ.justifications(), object: LogicalContext {
override fun <V : Any> variable(metaLogical: MetaLogical<V>): Logical<V>? = null
})
@ -79,13 +77,9 @@ internal class ControllerImpl (
return context.currentStatus()
}
override fun logicalState(): LogicalStateObservable =
override fun logicalStateObservable(): LogicalStateObservable =
processing
override fun clearState() {
initToken.clear()
}
override fun ask(invocation: PredicateInvocation): Boolean {
val solver = invocation.predicate().symbol().solver()
val result = solver.ask(invocation)
@ -223,7 +217,7 @@ internal class ControllerImpl (
profiler.profile<FeedbackStatus>("activate_${constraint.symbol()}") {
constraint.occurrence(logicalState(), args, justsCopy(justs), context.logicalContext, context.ruleUniqueTag).let { occ ->
constraint.occurrence(logicalStateObservable(), args, justsCopy(justs), context.logicalContext, context.ruleUniqueTag).let { occ ->
trace.activate(occ)
processing.processActivated(this, occ, status)
}
@ -336,15 +330,16 @@ fun createController(
supervisor: Supervisor,
ruleIndex: RuleIndex,
trace: EvaluationTrace = EvaluationTrace.NULL,
profiler: Profiler? = null) : Controller =
ControllerImpl(
profiler: Profiler? = null) : Controller
{
val logicalState = LogicalState()
val controller = ControllerImpl(
supervisor,
ConstraintsProcessing(
Dispatcher(ruleIndex).front(),
MatchJournalImpl(),
ruleIndex,
LogicalState(),
logicalState,
IncrementalProgramSpec.DefaultSpec,
trace,
profiler
@ -353,3 +348,6 @@ fun createController(
trace,
profiler
)
logicalState.init(controller)
return controller
}

View File

@ -36,39 +36,42 @@ internal class EvaluationSessionImpl private constructor (
val params: Map<ParameterKey<*>, *>?) : EvaluationSession()
{
lateinit var controller: ControllerImpl
@Suppress("UNCHECKED_CAST")
override fun <T : Any> parameter(key: ParameterKey<T>): T? = params ?.get(key) as T
private fun launch(
main: Constraint, profiler: Profiler?,
token: SessionToken?, rulesDiff: RulesDiff, ispec: IncrementalProgramSpec
) : FeedbackStatus {
) : Pair<FeedbackStatus, SessionToken> {
val ruleIndex = RuleIndex(program.rulesLists())
if (ispec is IncrementalProgramSpec.NonIncrSpec || token == null) {
val processing
= ConstraintsProcessing(
val logicalState = LogicalState()
val processing = ConstraintsProcessing(
Dispatcher(ruleIndex).front(),
MatchJournalImpl(ispec),
ruleIndex, LogicalState(), ispec, trace, profiler
ruleIndex, logicalState, ispec, trace, profiler
)
this.controller = ControllerImpl(supervisor, processing, ispec, trace, profiler)
return controller.activate(main)
val controller = ControllerImpl(supervisor, processing, ispec, trace, profiler)
logicalState.init(controller)
return controller.activate(main) to processing.endSession()
} else {
val tkn = token as SessionTokenImpl
val logicalState = tkn.logicalState
val processing = ConstraintsProcessing(
Dispatcher(ruleIndex, tkn.getFrontState()).front(),
MatchJournalImpl(ispec, tkn.journalView),
ruleIndex, tkn.logicalState, ispec, trace, profiler
ruleIndex, logicalState, ispec, trace, profiler
)
this.controller = ControllerImpl(supervisor, processing, ispec, trace, profiler)
return controller.incrLaunch(main, rulesDiff)
val controller = ControllerImpl(supervisor, processing, ispec, trace, profiler)
logicalState.init(controller)
return controller.incrLaunch(main, rulesDiff) to processing.endSession()
}
}
@ -117,16 +120,20 @@ internal class EvaluationSessionImpl private constructor (
session = EvaluationSessionImpl(program, supervisor, evaluationTrace, parameters)
Backend.ourBackend.ourSession.set(session)
var failure: Feedback? = null
try {
val main = parameters[ParameterKey.of("main", Constraint::class.java)] as Constraint
val status = session.launch(main, profiler, token, program.incrementalDiff(), ispec)
if (status is FAILED) {
failure = status.failure
val (status, token) = session.launch(main, profiler, token, program.incrementalDiff(), ispec)
return object : EvaluationResult {
override fun token(): SessionToken = token
override fun storeView(): StoreView = token.journalView.storeView
override fun feedback(): EvaluationFeedback? = if (status is FAILED) status.failure else null
}
}
finally {
session.controller.clearState()
try {
profiler?.run {
formattedData().entries.forEach { e -> durations.put(e.key, e.value) }
@ -139,15 +146,6 @@ internal class EvaluationSessionImpl private constructor (
Backend.ourBackend.ourSession.set(null)
}
return object : EvaluationResult {
private val token = session.controller.processing.endSession()
override fun token(): SessionToken = token
override fun storeView(): StoreView = token.journalView.storeView
override fun feedback(): EvaluationFeedback? = failure
}
}
}

View File

@ -49,16 +49,15 @@ class LogicalState : LogicalStateObservable, LogicalObserver
stateFrames.push(LogicalStateFrame())
}
override fun init(controller: Controller): LogicalStateObservable.InitToken {
assert(this@LogicalState.controller === null)
fun init(controller: Controller) {
assert(this.controller === null)
this.controller = controller
}
return object : LogicalStateObservable.InitToken {
override fun clear() {
assert(this@LogicalState.controller !== null)
this@LogicalState.controller = null
}
}
fun clear() : LogicalState {
assert(this.controller !== null)
this.controller = null
return this
}
fun currentFrame() : LogicalStateFrame =
@ -73,9 +72,9 @@ class LogicalState : LogicalStateObservable, LogicalObserver
fun reset() {
// Clear logicals from this forwarding observer on full reset
currentFrame().observed().forEach {
it.removeObserver(this)
}
// currentFrame().observed().forEach {
// it.removeObserver(this)
// }
reset(stateFrames.last)
}

View File

@ -42,8 +42,8 @@ interface StoreAwareJournal : MatchJournal, LogicalStateObservable {
internal open class StoreAwareJournalImpl(private val journal: MatchJournal,
private val state: LogicalState = LogicalState())
: MatchJournal by journal, StoreAwareJournal, LogicalStateObservable by state
private val logicalState: LogicalState = LogicalState())
: MatchJournal by journal, StoreAwareJournal, LogicalStateObservable by logicalState
{
private class FramePos(
@ -53,25 +53,25 @@ internal open class StoreAwareJournalImpl(private val journal: MatchJournal,
) : MatchJournal.Pos(chunk, entriesCount)
fun push() = state.push()
fun push() = logicalState.push()
override fun testPush() { state.push() }
override fun testPush() { logicalState.push() }
// Reset only store & history position, don't modify history
override fun resetStore() {
state.reset()
logicalState.reset()
this.resetPos()
}
override fun currentPos(): MatchJournal.Pos =
FramePos(state.currentFrame(), journal.currentPos().chunk, journal.currentPos().entriesCount)
FramePos(logicalState.currentFrame(), journal.currentPos().chunk, journal.currentPos().entriesCount)
// Throw away recently added chunks and reset store accordingly
// NB: not checking that chunks are actually recently added, from this exec session
override fun reset(pastPos: MatchJournal.Pos) {
if (pastPos is FramePos) {
state.reset(pastPos.frame)
logicalState.reset(pastPos.frame)
journal.reset(pastPos)
} else {
throw IllegalArgumentException()

View File

@ -174,15 +174,15 @@ fun equals(left: Any, right: Any): ConjBuilder.() -> Unit = {
fun occurrence(id: String, vararg args: Any): Occurrence =
MockConstraint(ConstraintSymbol.symbol(id, args.size))
.occurrence(MockController().logicalState(), listOf(* args), justsOf(), noLogicalContext)
.occurrence(MockController().logicalStateObservable(), listOf(* args), justsOf(), noLogicalContext)
fun taggedOccurrence(ruleUniqueTag: Any, id: String, vararg args: Any): Occurrence =
MockConstraint(ConstraintSymbol.symbol(id, args.size))
.occurrence(MockController().logicalState(), listOf(* args), justsOf(), noLogicalContext, ruleUniqueTag)
.occurrence(MockController().logicalStateObservable(), listOf(* args), justsOf(), noLogicalContext, ruleUniqueTag)
fun justifiedOccurrence(id: String, justs: Justs, vararg args: Any): Occurrence =
MockConstraint(ConstraintSymbol.symbol(id, args.size), true)
.occurrence(MockController().logicalState(), listOf(* args), justs, noLogicalContext)
.occurrence(MockController().logicalStateObservable(), listOf(* args), justs, noLogicalContext)
fun justifiedOccurrence(id: String, justs: Collection<Int>, vararg args: Any): Occurrence =
justifiedOccurrence(id, justsFromCollection(justs), * args)
@ -201,11 +201,7 @@ private val noLogicalContext = object : LogicalContext {
}
class MockController : Controller {
override fun clearState() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun ask(invocation: PredicateInvocation): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@ -222,16 +218,12 @@ class MockController : Controller {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun logicalState(): LogicalStateObservable = object : LogicalStateObservable {
override fun logicalStateObservable(): LogicalStateObservable = object : LogicalStateObservable {
override fun addForwardingObserver(logical: Logical<*>, observer: ForwardingLogicalObserver) {
}
override fun removeForwardingObserver(logical: Logical<*>, observer: ForwardingLogicalObserver) {
}
override fun init(controller: Controller): LogicalStateObservable.InitToken {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
override fun storeView(): StoreView {

View File

@ -1,4 +1,5 @@
import jetbrains.mps.logic.reactor.core.*
import jetbrains.mps.logic.reactor.core.internal.LogicalState
import jetbrains.mps.logic.reactor.core.internal.createController
import jetbrains.mps.logic.reactor.core.internal.logical
import jetbrains.mps.logic.reactor.evaluation.*

View File

@ -162,7 +162,7 @@ class TestStoreAwareJournal {
nchunks shouldBe 4 * 2 // 4 rules, each activates 1 principal occurrence
// try replay the last chunk
replay(mockController.logicalState(), lastPos)
replay(mockController.logicalStateObservable(), lastPos)
// should change nothing
storeView().constraintSymbols() shouldBe setOf(sym0("qux"), sym0("lax"))
@ -175,11 +175,11 @@ class TestStoreAwareJournal {
storeView().allOccurrences().count() shouldBe 0
view().chunks.size shouldBe nchunks
replay(mockController.logicalState(), initPos)
replay(mockController.logicalStateObservable(), initPos)
storeView().constraintSymbols() shouldBe setOf<ConstraintSymbol>()
replay(mockController.logicalState(), fooPos)
replay(mockController.logicalStateObservable(), fooPos)
storeView().constraintSymbols() shouldBe setOf(sym0("foo"))
// although storeView() results change, journal remains the same
@ -231,7 +231,7 @@ class TestStoreAwareJournal {
storeView().allOccurrences().count() shouldBe 0
replay(mockController.logicalState(), savedPos)
replay(mockController.logicalStateObservable(), savedPos)
storeView().allOccurrences() shouldBe oldStore
currentPos() shouldBe savedPos
@ -473,7 +473,7 @@ class TestStoreAwareJournal {
// store is not longer valid after removing chunks from history, so reset it
resetStore()
// move to the point where we want to insert new rule
replay(mockController.logicalState(), continueFrom)
replay(mockController.logicalStateObservable(), continueFrom)
// according to the history 'qux' wasn't activated at this point & 'bar1' wasn't discarded
storeView().constraintSymbols() shouldBe setOf<ConstraintSymbol>()
@ -498,7 +498,7 @@ class TestStoreAwareJournal {
assertNotEquals(lastPos, currentPos())
// finally, purely go the the end, applying the rest of the history to the store
replay(mockController.logicalState(), lastPos)
replay(mockController.logicalStateObservable(), lastPos)
currentPos().chunk shouldBeSame lastPos.chunk // we inserted in the middle -- the last chunk should remain the same
storeView().constraintSymbols() shouldBe setOf(sym0("bar1"), sym0("qux"), sym0("marker"))