diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Handler.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Handler.kt index cd43215c..8820d861 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Handler.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Handler.kt @@ -20,7 +20,7 @@ class Handler { private val occurrenceStore = OccurrenceStore() - private val propHistory = PropagationHistory() + private var propHistory = PropagationHistory() private val matcher: Matcher @@ -79,7 +79,7 @@ class Handler { val lookupMatches = matcher.lookupMatches(active, occurrenceStore, propHistory) for (match in lookupMatches) { - // FIXME: paranoid check. should be isAlive() instead + // TODO: paranoid check. should be isAlive() instead if (!active.isStored()) break if (match.occurrences().any { co -> !co.isStored() }) continue @@ -90,25 +90,39 @@ class Handler { } trace.trigger(match) - propHistory.record(match) - for ((cst, occ) in match.discarded) { occurrenceStore.discard(occ) trace.discard(occ) } + // propHistory is now functional (persistent) + // we must reassign the field on every rule triggering + // and store on the stack the last value before rule activation in order to undo in case of failure + val savedPropHistory = propHistory + this.propHistory = propHistory.record(match) + for (item in match.rule.body()) { - when (item) { - is Constraint -> process(item.occurrence(this@Handler, match.logicalContext())) - is Predicate -> tellPredicate(item.invocation(match.logicalContext()), trace) - else -> throw IllegalArgumentException("unknown item ${item}") + try { + when (item) { + is Constraint -> process(item.occurrence(this@Handler, match.logicalContext())) + is Predicate -> tellPredicate(item.invocation(match.logicalContext()), trace) + else -> throw IllegalArgumentException("unknown item ${item}") + } + } + catch (ex: Throwable) { + // abrupt termination: restore the state + this.propHistory = savedPropHistory + throw ex + } + finally { + } } trace.finish(match) } - // FIXME: should be isAlive() + // TODO: should be isAlive() if (active.isStored()) { trace.suspend(active) } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/PropagationHistory.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/PropagationHistory.kt index dcb7da7b..6420cfdd 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/PropagationHistory.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/PropagationHistory.kt @@ -2,12 +2,22 @@ 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 com.github.andrewoma.dexx.collection.List as PersList import jetbrains.mps.logic.reactor.evaluation.ConstraintOccurrence import jetbrains.mps.logic.reactor.program.Rule class PropagationHistory { - var recordedPropagation = Maps.of>>>() + val recordedPropagation : PersMap>>> + + constructor() { + this.recordedPropagation = Maps.of>>> () + } + + private constructor(recorded : PersMap>>>) { + this.recordedPropagation = recorded + } fun isRecorded(pm: PartialMatch): Boolean { if (!pm.isPropagation()) return false @@ -20,15 +30,15 @@ class PropagationHistory { } ?: false } - fun record(pm: PartialMatch): PartialMatch { + fun record(pm: PartialMatch): PropagationHistory { if (pm.isPropagation()) { val idOccs = pm.kept.map { pair -> IdWrapper(pair.second) }.sortedBy { id -> id.idHash }.toList() val hist = recordedPropagation.get(pm.rule) ?: ConsList.empty>>() - recordedPropagation = recordedPropagation.put(pm.rule, hist.prepend(idOccs)) + return PropagationHistory(recordedPropagation.put(pm.rule, hist.prepend(idOccs))) } - return pm + return this } } \ No newline at end of file