Cleanup code and API: provenance and feedback support
This commit is contained in:
parent
4a142a257b
commit
06a2e2c6e1
|
|
@ -18,6 +18,7 @@ package jetbrains.mps.logic.reactor.core
|
|||
|
||||
import jetbrains.mps.logic.reactor.evaluation.RuleMatch
|
||||
import jetbrains.mps.logic.reactor.evaluation.Supervisor
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
|
|
@ -27,25 +28,27 @@ import java.util.ArrayList
|
|||
class CompositeFeedback private constructor(private val elements: List<Feedback>) : Feedback() {
|
||||
private val severity: Severity = maxSeverity(elements)
|
||||
|
||||
override fun handle(currentRuleMatch: RuleMatch, feedbackKey: Any, feedbackBasis: List<Any>, supervisor: Supervisor): Boolean {
|
||||
var unhandled = 0
|
||||
for (feedback in elements) {
|
||||
if (!feedback.alreadyHandled()) {
|
||||
unhandled += 1
|
||||
if (supervisor.handleFeedback(currentRuleMatch, feedbackKey, feedbackBasis, feedback)) {
|
||||
feedback.setHandled()
|
||||
unhandled -= 1
|
||||
override fun handle(supervisor: Supervisor, ruleMatch: RuleMatch, provenance: List<Rule>): Boolean {
|
||||
var unhandled = false
|
||||
if (!alreadyHandled()) {
|
||||
for (feedback in elements) {
|
||||
if (!feedback.handle(supervisor, ruleMatch, provenance)) {
|
||||
unhandled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return unhandled == 0
|
||||
if (!unhandled) {
|
||||
setHandled()
|
||||
}
|
||||
return alreadyHandled()
|
||||
}
|
||||
|
||||
override fun handle(ruleMatch: RuleMatch) {
|
||||
for (feedback in elements) {
|
||||
if (!feedback.alreadyHandled()) {
|
||||
feedback.setHandled()
|
||||
override fun report(supervisor: Supervisor, ruleMatch: RuleMatch, provenance: List<Any>) {
|
||||
if (!alreadyHandled()) {
|
||||
for (feedback in elements) {
|
||||
feedback.report(supervisor, ruleMatch, provenance)
|
||||
}
|
||||
setHandled()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package jetbrains.mps.logic.reactor.core
|
|||
import jetbrains.mps.logic.reactor.evaluation.EvaluationFeedback
|
||||
import jetbrains.mps.logic.reactor.evaluation.RuleMatch
|
||||
import jetbrains.mps.logic.reactor.evaluation.Supervisor
|
||||
import jetbrains.mps.logic.reactor.evaluation.Supervisor.HandleResult
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
|
||||
/**
|
||||
* @author Fedor Isakov
|
||||
|
|
@ -40,15 +42,24 @@ abstract class Feedback : EvaluationFeedback() {
|
|||
/**
|
||||
* Returns true if the feedback has been handled.
|
||||
*/
|
||||
open fun handle(currentRuleMatch: RuleMatch, feedbackKey: Any, feedbackBasis: List<Any>, supervisor: Supervisor): Boolean {
|
||||
if (!alreadyHandled() && supervisor.handleFeedback(currentRuleMatch, feedbackKey, feedbackBasis, this)) {
|
||||
setHandled()
|
||||
open fun handle(supervisor: Supervisor, ruleMatch: RuleMatch, provenance: List<Rule>): Boolean {
|
||||
if (!alreadyHandled()) {
|
||||
when (supervisor.handleFeedback(this, ruleMatch, provenance)) {
|
||||
HandleResult.DROP -> { setHandled() }
|
||||
HandleResult.PROPAGATE -> { /*NOP*/ }
|
||||
HandleResult.ESCALATE -> { /*NOP*/ }
|
||||
null -> throw NullPointerException()
|
||||
}
|
||||
}
|
||||
return alreadyHandled()
|
||||
}
|
||||
|
||||
open fun handle(ruleMatch: RuleMatch) {
|
||||
/**
|
||||
* Receive the feedback and mark as handled unconditionally.
|
||||
*/
|
||||
open fun report(supervisor: Supervisor, ruleMatch: RuleMatch, provenance: List<Any>) {
|
||||
if (!alreadyHandled()) {
|
||||
supervisor.receiveFeedback(this, ruleMatch, provenance)
|
||||
setHandled()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,12 +171,8 @@ internal class ControllerImpl (
|
|||
|
||||
if (itemOk) {
|
||||
context.withStatus { status ->
|
||||
if (status.feedback?.alreadyHandled() == false) {
|
||||
status.feedback.handle(match,
|
||||
newParent.match.feedbackKey,
|
||||
processing.basisRuleTags(newParent),
|
||||
supervisor)
|
||||
}
|
||||
// FIXME support ESCALATE option
|
||||
status.feedback?.handle(supervisor, match, processing.provenanceRules(newParent))
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -187,27 +183,20 @@ internal class ControllerImpl (
|
|||
|
||||
val altOk = context.eval { status ->
|
||||
if (status is FAILED) {
|
||||
// if there's alternative body branch then try it
|
||||
// if there's alternative body branch then try it before failing
|
||||
if (altIt.hasNext()) {
|
||||
// clear the failure handled status
|
||||
// the supervisor is NOT notified here
|
||||
status.failure.handle(match)
|
||||
// report the feedback and suppress the failure
|
||||
status.failure.report(supervisor, match, processing.provenanceRules(newParent))
|
||||
status
|
||||
|
||||
// if failure can be handled here then recover
|
||||
} else if (status.feedback?.alreadyHandled() == false
|
||||
&& status.failure.handle(match,
|
||||
newParent.match.feedbackKey,
|
||||
processing.basisRuleTags(newParent),
|
||||
supervisor)) {
|
||||
// if failure can be not handled here, then propagate further up the stack
|
||||
// FIXME support ESCALATE option
|
||||
} else if (!status.failure.handle(supervisor, match, processing.provenanceRules(newParent))) {
|
||||
status
|
||||
|
||||
status.recover()
|
||||
|
||||
// else propagate further up the stack
|
||||
} else {
|
||||
status
|
||||
status.recover()
|
||||
}
|
||||
|
||||
} else {
|
||||
status
|
||||
}
|
||||
|
|
@ -303,7 +292,7 @@ internal class ControllerImpl (
|
|||
logicalContext: LogicalContext,
|
||||
rule: Rule? = null,
|
||||
trace: EvaluationTrace = EvaluationTrace.NULL) :
|
||||
this(inStatus, false, logicalContext, rule, trace)
|
||||
this(inStatus, false, logicalContext, rule, trace)
|
||||
|
||||
fun currentStatus(): FeedbackStatus = status
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,12 @@ interface MatchJournal : EvidenceSource {
|
|||
*/
|
||||
fun storeView(): StoreView
|
||||
|
||||
fun basisRuleTags(chunk: Chunk): List<Any>
|
||||
/**
|
||||
* Returns the list of rules that serve as the provenance for the given chunk.
|
||||
* Provenance can be used to determine the location(s) in the source code
|
||||
* to mark with the feedback message.
|
||||
*/
|
||||
fun provenanceRules(chunk: Chunk): List<Rule>
|
||||
|
||||
// NB: returns same collection of justifications, not copy
|
||||
fun justifications() = this.currentPos().chunk.justifications()
|
||||
|
|
|
|||
|
|
@ -178,18 +178,18 @@ internal open class MatchJournalImpl(
|
|||
|
||||
override fun storeView(): StoreView = StoreViewImpl(allOccurrences())
|
||||
|
||||
override fun basisRuleTags(chunk: Chunk): List<Any> {
|
||||
val ptags = mutableListOf<Any>()
|
||||
override fun provenanceRules(chunk: Chunk): List<Rule> {
|
||||
val rules = mutableListOf<Rule>()
|
||||
chunk.justifications().forEach { jn ->
|
||||
// hist is sequential, random access can be expensive
|
||||
(lookupChunkByEvidence(jn) as? MatchChunk)?.let {
|
||||
if (it.match.rule().isBasis) {
|
||||
ptags.add(it.ruleUniqueTag)
|
||||
if (it.match.rule().isProvenance) {
|
||||
rules.add(it.match.rule())
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
return ptags
|
||||
return rules
|
||||
}
|
||||
|
||||
private fun allOccurrences(): Sequence<Occurrence> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue