Adapting to the latest reactor API. RuleHandler and tests (no predicates yet).
This commit is contained in:
parent
1ce311a0bf
commit
a7708f3974
|
|
@ -1,8 +1,12 @@
|
||||||
package jetbrains.mps.logic.reactor.core
|
package jetbrains.mps.logic.reactor.core
|
||||||
|
|
||||||
|
import com.github.andrewoma.dexx.collection.ConsList
|
||||||
|
import com.github.andrewoma.dexx.collection.List as PList
|
||||||
|
import com.github.andrewoma.dexx.collection.LinkedList as PLinkedList
|
||||||
import jetbrains.mps.logic.reactor.constraint.*
|
import jetbrains.mps.logic.reactor.constraint.*
|
||||||
import jetbrains.mps.logic.reactor.predicate.ReactorSessionSolver
|
|
||||||
import jetbrains.mps.logic.reactor.program.EvaluationSession
|
import jetbrains.mps.logic.reactor.program.EvaluationSession
|
||||||
|
import jetbrains.mps.logic.reactor.program.PlanningSession
|
||||||
|
import jetbrains.mps.logic.reactor.rule.Rule
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -10,13 +14,13 @@ import java.util.*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : EvaluationSession() {
|
class ReactorEvaluationSession(val program: PlanningSession) : EvaluationSession() {
|
||||||
|
|
||||||
class Config : EvaluationSession.Config() {
|
class Config(val program: PlanningSession) : EvaluationSession.Config() {
|
||||||
|
|
||||||
val myPredicateSymbols = ArrayList<PredicateSymbol>()
|
val myPredicateSymbols = ArrayList<PredicateSymbol>()
|
||||||
val myParameters = HashMap<String, Any?>()
|
val myParameters = HashMap<String, Any?>()
|
||||||
var myComputingTracer : ComputingTracer? = null
|
var myComputingTracer: ComputingTracer? = null
|
||||||
|
|
||||||
override fun withPredicates(vararg predicateSymbols: PredicateSymbol): EvaluationSession.Config {
|
override fun withPredicates(vararg predicateSymbols: PredicateSymbol): EvaluationSession.Config {
|
||||||
myPredicateSymbols.addAll(Arrays.asList(* predicateSymbols))
|
myPredicateSymbols.addAll(Arrays.asList(* predicateSymbols))
|
||||||
|
|
@ -38,19 +42,28 @@ private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : Evalu
|
||||||
if (session != null) throw IllegalStateException("session already active")
|
if (session != null) throw IllegalStateException("session already active")
|
||||||
|
|
||||||
val predicateSymbols = myPredicateSymbols.toArray<PredicateSymbol>(arrayOfNulls(myPredicateSymbols.size))
|
val predicateSymbols = myPredicateSymbols.toArray<PredicateSymbol>(arrayOfNulls(myPredicateSymbols.size))
|
||||||
val sessionSolver = ReactorSessionSolver()
|
val sessionSolver = program.sessionSolver()
|
||||||
sessionSolver.init(myComputingTracer, * predicateSymbols)
|
sessionSolver.init(myComputingTracer, * predicateSymbols)
|
||||||
|
|
||||||
session = ReactorEvaluationSession(sessionSolver)
|
session = ReactorEvaluationSession(program)
|
||||||
ourBackend.ourSession.set(session)
|
ourBackend.ourSession.set(session)
|
||||||
|
|
||||||
|
session.launch()
|
||||||
|
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sessionSolver(): SessionSolver? {
|
fun launch() {
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun sessionSolver(): SessionSolver = program.sessionSolver()
|
||||||
|
|
||||||
override fun constraintSymbols(): MutableIterable<ConstraintSymbol>? {
|
override fun constraintSymbols(): MutableIterable<ConstraintSymbol>? {
|
||||||
throw UnsupportedOperationException()
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +82,7 @@ private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : Evalu
|
||||||
|
|
||||||
override fun current(): EvaluationSession = ourSession.get() ?: throw IllegalStateException("no session")
|
override fun current(): EvaluationSession = ourSession.get() ?: throw IllegalStateException("no session")
|
||||||
|
|
||||||
override fun createConfig(): EvaluationSession.Config = Config()
|
override fun createConfig(program: PlanningSession): EvaluationSession.Config = Config(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -79,7 +92,7 @@ private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : Evalu
|
||||||
setBackend(ourBackend)
|
setBackend(ourBackend)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deinit () {
|
fun deinit() {
|
||||||
clearBackend(ourBackend)
|
clearBackend(ourBackend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ class ReactorPlanningSession(val name: String, val sessionSolver: SessionSolver)
|
||||||
|
|
||||||
override fun name(): String = name
|
override fun name(): String = name
|
||||||
|
|
||||||
|
override fun sessionSolver(): SessionSolver= sessionSolver
|
||||||
|
|
||||||
override fun constraintSymbols(): Iterable<ConstraintSymbol> =
|
override fun constraintSymbols(): Iterable<ConstraintSymbol> =
|
||||||
myRegistry.constraintSymbols()
|
myRegistry.constraintSymbols()
|
||||||
|
|
||||||
|
|
@ -114,7 +116,7 @@ private class ConstraintRegistry(val sessionSolver: SessionSolver) {
|
||||||
unmodifiableSet(myConstraintArgTypes.keys)
|
unmodifiableSet(myConstraintArgTypes.keys)
|
||||||
|
|
||||||
fun constraintArgTypes(symbol: ConstraintSymbol): List<Class<*>> =
|
fun constraintArgTypes(symbol: ConstraintSymbol): List<Class<*>> =
|
||||||
unmodifiableList(myConstraintArgTypes.getOrDefault(symbol, emptyList()))
|
unmodifiableList(myConstraintArgTypes.getOrDefault(symbol, Collections.emptyList()))
|
||||||
|
|
||||||
fun predicateSymbols(): Iterable<PredicateSymbol> =
|
fun predicateSymbols(): Iterable<PredicateSymbol> =
|
||||||
unmodifiableSet(myPredicateSolvers.keys)
|
unmodifiableSet(myPredicateSolvers.keys)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
package jetbrains.mps.logic.reactor.core
|
||||||
|
|
||||||
|
import com.github.andrewoma.dexx.collection.ConsList
|
||||||
|
import jetbrains.mps.logic.reactor.constraint.*
|
||||||
|
import jetbrains.mps.logic.reactor.rule.Rule
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fedor Isakov
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RuleHandler {
|
||||||
|
|
||||||
|
private val occurrenceFactory: (Constraint) -> ConstraintOccurrence
|
||||||
|
private val rules : MutableList<Rule> = ArrayList<Rule>()
|
||||||
|
private val stored : MutableList<ConstraintOccurrence> = ArrayList<ConstraintOccurrence>()
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
programRules: Iterable<Rule>,
|
||||||
|
occurrenceFactory: (Constraint) -> ConstraintOccurrence,
|
||||||
|
// for testing purposes only
|
||||||
|
occurrences: Iterable<ConstraintOccurrence>? = null)
|
||||||
|
{
|
||||||
|
this.occurrenceFactory = occurrenceFactory
|
||||||
|
this.rules.addAll(programRules)
|
||||||
|
if (occurrences != null) {
|
||||||
|
this.stored.addAll(occurrences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun occurrences(): Set<ConstraintOccurrence> = stored.toSet()
|
||||||
|
|
||||||
|
fun process(active: ConstraintOccurrence): Boolean {
|
||||||
|
stored.add(active)
|
||||||
|
val match = lookupMatches(active).find { pm -> pm.isGuardSatisfied() }
|
||||||
|
|
||||||
|
if (match != null) {
|
||||||
|
for ((cst, occ) in match.discarded) {
|
||||||
|
discard(occ)
|
||||||
|
}
|
||||||
|
for (item in match.rule.body()) {
|
||||||
|
activate(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun discard(occ: ConstraintOccurrence) {
|
||||||
|
stored.remove(occ)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun activate(item: AndItem): Boolean {
|
||||||
|
return when(item) {
|
||||||
|
is Constraint -> process(activate(item))
|
||||||
|
is Predicate -> true
|
||||||
|
else -> throw IllegalArgumentException("unknown item ${item}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun activate(constraint: Constraint): ConstraintOccurrence = occurrenceFactory(constraint)
|
||||||
|
|
||||||
|
fun lookupMatches(occ: ConstraintOccurrence): Iterable<PartialMatch> {
|
||||||
|
val partialMatches = rules.flatMap { r ->
|
||||||
|
val matchedKept = r.headKept().filter { cst -> cst.matches(occ) }
|
||||||
|
val matchedDiscarded = r.headReplaced().filter { cst -> cst.matches(occ) }
|
||||||
|
|
||||||
|
matchedKept.map { cst -> PartialMatch(r).keep(cst, occ) } +
|
||||||
|
matchedDiscarded.map { cst -> PartialMatch(r).discard(cst, occ) }
|
||||||
|
}
|
||||||
|
return partialMatches.flatMap { pm -> completeMatch(pm) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun completeMatch(match: PartialMatch) : Iterable<PartialMatch> {
|
||||||
|
if (!match.isPartial()) return listOf(match)
|
||||||
|
|
||||||
|
val keptToSatisfy = match.rule.headKept().filter { cst -> !match.kept.any { p -> cst === p.first } }
|
||||||
|
val matchesFromKept = keptToSatisfy.flatMap { cst ->
|
||||||
|
findOccurrences(cst, { occ -> !match.hasOccurrence(occ) }).flatMap { occ -> completeMatch(match.keep(cst, occ)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val discardedToSatisfy = match.rule.headReplaced().filter { cst -> !match.discarded.any { p -> cst === p.first } }
|
||||||
|
val matchesFromDiscarded = discardedToSatisfy.flatMap { cst ->
|
||||||
|
findOccurrences(cst, { occ -> !match.hasOccurrence(occ) }).flatMap { occ -> completeMatch(match.discard(cst, occ)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchesFromKept + matchesFromDiscarded
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findOccurrences(constraint: Constraint, predicate: (ConstraintOccurrence) -> Boolean) : Iterable<ConstraintOccurrence> =
|
||||||
|
stored.filter { co -> constraint.matches(co) && predicate(co) }
|
||||||
|
|
||||||
|
class PartialMatch(val rule: Rule) {
|
||||||
|
|
||||||
|
var kept = ConsList.empty<Pair<Constraint, ConstraintOccurrence>>()
|
||||||
|
private set
|
||||||
|
var discarded = ConsList.empty<Pair<Constraint, ConstraintOccurrence>>()
|
||||||
|
private set
|
||||||
|
|
||||||
|
private constructor(
|
||||||
|
original : PartialMatch,
|
||||||
|
keep: Pair<Constraint, ConstraintOccurrence>?,
|
||||||
|
discard: Pair<Constraint, ConstraintOccurrence>?) : this(original.rule)
|
||||||
|
{
|
||||||
|
kept = if (keep != null) original.kept.append(keep) else original.kept
|
||||||
|
discarded = if (discard != null) original.discarded.append(discard) else original.discarded
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clone() : PartialMatch = PartialMatch(this, null, null)
|
||||||
|
|
||||||
|
fun keep (constraint: Constraint, occ: ConstraintOccurrence) = PartialMatch(this, Pair(constraint, occ), null)
|
||||||
|
|
||||||
|
fun discard (constraint: Constraint, occ: ConstraintOccurrence) = PartialMatch(this, null, Pair(constraint, occ))
|
||||||
|
|
||||||
|
fun hasOccurrence(occ: ConstraintOccurrence): Boolean {
|
||||||
|
return kept.any { p -> p.second === occ} || discarded.any { p -> p.second === occ }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isPartial() : Boolean =
|
||||||
|
rule.headKept().any { cst -> !kept.any { p -> p.first === cst } } ||
|
||||||
|
rule.headReplaced().any { cst -> !discarded.any { p -> p.first === cst } }
|
||||||
|
|
||||||
|
fun isGuardSatisfied() : Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True iff the constraint matches the occurrence.
|
||||||
|
*/
|
||||||
|
fun Constraint.matches(that: ConstraintOccurrence): Boolean {
|
||||||
|
if (symbol() != that.constraint().symbol())
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return arguments() == that.arguments()
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ fun headKept(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||||
appendHeadKept( * buildConjunction(Constraint::class.java, content).toArray())
|
appendHeadKept( * buildConjunction(Constraint::class.java, content).toArray())
|
||||||
}
|
}
|
||||||
fun headReplaced(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
fun headReplaced(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||||
appendHeadKept( * buildConjunction(Constraint::class.java, content).toArray())
|
appendHeadReplaced( * buildConjunction(Constraint::class.java, content).toArray())
|
||||||
}
|
}
|
||||||
fun guard(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
fun guard(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||||
appendGuard( * buildConjunction(AndItem::class.java, content).toArray())
|
appendGuard( * buildConjunction(AndItem::class.java, content).toArray())
|
||||||
|
|
@ -30,19 +30,32 @@ fun body(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun constraint(id: String): ConjBuilder.() -> Unit = {
|
fun constraint(id: String): ConjBuilder.() -> Unit = {
|
||||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, 0)))
|
add(TestConstraint(ConstraintSymbol.symbol(id, 0)))
|
||||||
}
|
}
|
||||||
fun constraint(id: String, arg: Any): ConjBuilder.() -> Unit = {
|
fun constraint(id: String, arg: Any): ConjBuilder.() -> Unit = {
|
||||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, 1), arg))
|
add(TestConstraint(ConstraintSymbol.symbol(id, 1), arg))
|
||||||
}
|
}
|
||||||
fun constraint(id: String, arg1: Any, arg2: Any): ConjBuilder.() -> Unit = {
|
fun constraint(id: String, arg1: Any, arg2: Any): ConjBuilder.() -> Unit = {
|
||||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, 2), arg1, arg2))
|
add(TestConstraint(ConstraintSymbol.symbol(id, 2), arg1, arg2))
|
||||||
}
|
}
|
||||||
fun constraint(id: String, arg1: Any, arg2: Any, arg3: Any): ConjBuilder.() -> Unit = {
|
fun constraint(id: String, arg1: Any, arg2: Any, arg3: Any): ConjBuilder.() -> Unit = {
|
||||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, 3), arg1, arg2, arg3))
|
add(TestConstraint(ConstraintSymbol.symbol(id, 3), arg1, arg2, arg3))
|
||||||
}
|
}
|
||||||
fun constraint(id: String, args: Array<out Any>): ConjBuilder.() -> Unit = {
|
fun constraint(id: String, args: Array<out Any>): ConjBuilder.() -> Unit = {
|
||||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, args.size), * args))
|
add(TestConstraint(ConstraintSymbol.symbol(id, args.size), * args))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun expression(id: String): ConjBuilder.() -> Unit = {
|
||||||
|
add(JavaPredicate(JavaPredicateSymbol(0), id))
|
||||||
|
}
|
||||||
|
fun expression(id: String, arg: Any): ConjBuilder.() -> Unit = {
|
||||||
|
add(JavaPredicate(JavaPredicateSymbol(1), id, arg))
|
||||||
|
}
|
||||||
|
fun expression(id: String, arg1: Any, arg2: Any): ConjBuilder.() -> Unit = {
|
||||||
|
add(JavaPredicate(JavaPredicateSymbol(2), id, arg1, arg2))
|
||||||
|
}
|
||||||
|
fun expression(id: String, arg1: Any, arg2: Any, arg3: Any): ConjBuilder.() -> Unit = {
|
||||||
|
add(JavaPredicate(JavaPredicateSymbol(3), id, arg1, arg2, arg3))
|
||||||
}
|
}
|
||||||
|
|
||||||
class RB(tag: String) : RuleBuilder(tag) {}
|
class RB(tag: String) : RuleBuilder(tag) {}
|
||||||
|
|
@ -75,3 +88,31 @@ private fun buildConjunction(type: Class<out AndItem>,
|
||||||
return conjBuilder
|
return conjBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class TestOccurrence(val arguments : List<Any>, val constraint : Constraint) : ConstraintOccurrence {
|
||||||
|
|
||||||
|
constructor(id: String, vararg args: Any) :
|
||||||
|
this(listOf(* args), TestConstraint(ConstraintSymbol.symbol(id, args.size))) {}
|
||||||
|
|
||||||
|
constructor(constraint: Constraint) : this(constraint.arguments(), constraint) {}
|
||||||
|
|
||||||
|
override fun constraint(): Constraint = constraint
|
||||||
|
|
||||||
|
override fun arguments(): List<Any> = arguments
|
||||||
|
|
||||||
|
override fun toString(): String = "#${constraint().symbol()}(${arguments().joinToString()})"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TestConstraint(val symbol: ConstraintSymbol, val arguments: List<Any>) : Constraint {
|
||||||
|
|
||||||
|
constructor(symbol: ConstraintSymbol, vararg args: Any) : this(symbol, listOf(* args)) {}
|
||||||
|
|
||||||
|
override fun arguments(): List<Any> = arguments
|
||||||
|
|
||||||
|
override fun symbol(): ConstraintSymbol = symbol
|
||||||
|
|
||||||
|
override fun argumentTypes(): List<Class<*>> = arguments.map { arg -> arg.javaClass }
|
||||||
|
|
||||||
|
override fun toString(): String = "${symbol()}(${arguments().joinToString()})"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import jetbrains.mps.logic.reactor.core.ReactorEvaluationSession
|
||||||
|
import jetbrains.mps.logic.reactor.core.ReactorPlanningSession
|
||||||
|
import jetbrains.mps.logic.reactor.predicate.ReactorSessionSolver
|
||||||
|
import jetbrains.mps.logic.reactor.program.EvaluationSession
|
||||||
|
import jetbrains.mps.logic.reactor.program.PlanningSession
|
||||||
|
import org.junit.AfterClass
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fedor Isakov
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TestBasicProgram {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@BeforeClass @JvmStatic fun setup() {
|
||||||
|
ReactorPlanningSession.init();
|
||||||
|
ReactorEvaluationSession.init();
|
||||||
|
}
|
||||||
|
@AfterClass @JvmStatic fun teardown() {
|
||||||
|
ReactorEvaluationSession.deinit();
|
||||||
|
ReactorPlanningSession.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before fun beforeTest() {
|
||||||
|
program = PlanningSession.newSession("test", ReactorSessionSolver())
|
||||||
|
evalConfig = EvaluationSession.newSession(program)
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var program: PlanningSession
|
||||||
|
lateinit var evalConfig: EvaluationSession.Config
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun replace() {
|
||||||
|
program.addRules(arrayListOf(
|
||||||
|
rule("main",
|
||||||
|
headReplaced(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
)),
|
||||||
|
rule("main.foo",
|
||||||
|
headReplaced(
|
||||||
|
constraint("foo")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
))
|
||||||
|
assertEquals(program.rules().count(), 2)
|
||||||
|
val session = evalConfig.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import jetbrains.mps.logic.reactor.program.PlanningSession
|
||||||
import jetbrains.mps.logic.reactor.rule.InvalidConstraintException
|
import jetbrains.mps.logic.reactor.rule.InvalidConstraintException
|
||||||
import jetbrains.mps.logic.reactor.rule.InvalidRuleException
|
import jetbrains.mps.logic.reactor.rule.InvalidRuleException
|
||||||
import jetbrains.mps.logic.reactor.core.ReactorPlanningSession
|
import jetbrains.mps.logic.reactor.core.ReactorPlanningSession
|
||||||
|
import jetbrains.mps.logic.reactor.predicate.ReactorSessionSolver
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -14,7 +15,7 @@ import kotlin.test.expect
|
||||||
* @author Fedor Isakov
|
* @author Fedor Isakov
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Simple {
|
class TestPlanningSession {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@BeforeClass @JvmStatic fun setup() {
|
@BeforeClass @JvmStatic fun setup() {
|
||||||
|
|
@ -23,10 +24,10 @@ class Simple {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before fun beforeTest() {
|
@Before fun beforeTest() {
|
||||||
session = PlanningSession.newSession("test", null)
|
session = PlanningSession.newSession("test", ReactorSessionSolver())
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var session:PlanningSession
|
lateinit var session: PlanningSession
|
||||||
|
|
||||||
@Test fun empty() {
|
@Test fun empty() {
|
||||||
session.addRules(ArrayList())
|
session.addRules(ArrayList())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
import jetbrains.mps.logic.reactor.constraint.Constraint
|
||||||
|
import jetbrains.mps.logic.reactor.constraint.ConstraintOccurrence
|
||||||
|
import jetbrains.mps.logic.reactor.core.RuleHandler
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fedor Isakov
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class TestRuleHandler {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun matchSingle() {
|
||||||
|
val main = rule("main",
|
||||||
|
headReplaced(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main), factory())
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main"))
|
||||||
|
val match = matches.single()
|
||||||
|
assertFalse(match.isPartial())
|
||||||
|
assertEquals(match.rule, main)
|
||||||
|
assertTrue(match.kept.isEmpty)
|
||||||
|
val (cst, occ) = match.discarded.single()
|
||||||
|
assert(cst.symbol().id() == "main")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun matchDiscardedKept() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headReplaced(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main"))
|
||||||
|
assertFalse { matches.any { m -> m.isPartial() } }
|
||||||
|
assertEquals(listOf(main1, main2), matches.map { m -> m.rule })
|
||||||
|
matches.forEach { m -> assertTrue { m.kept.size() + m.discarded.size() == 1 } }
|
||||||
|
matches.flatMap { m -> m.kept + m.discarded }.forEach { pair ->
|
||||||
|
val (cst, occ) = pair
|
||||||
|
assert(cst.symbol().id() == "main")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun matchComplementMissing() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
headReplaced(
|
||||||
|
constraint("secondary")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main"))
|
||||||
|
assertFalse { matches.any { m -> m.isPartial() } }
|
||||||
|
assertEquals(listOf(main2), matches.map { m -> m.rule })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun matchComplementPresent() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
headReplaced(
|
||||||
|
constraint("secondary")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory(), listOf(TestOccurrence("secondary")))
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main"))
|
||||||
|
assertFalse { matches.any { m -> m.isPartial() } }
|
||||||
|
assertEquals(listOf(main1, main2), matches.map { m -> m.rule })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun matchArgument() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main", "foo")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("main", "bar")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main", "bar"))
|
||||||
|
assertFalse { matches.any { m -> m.isPartial() } }
|
||||||
|
assertEquals(listOf(main2), matches.map { m -> m.rule })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noMatchArgument() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main", "foo")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("main", "bar")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||||
|
|
||||||
|
val matches = handler.lookupMatches(TestOccurrence("main", "qux"))
|
||||||
|
assertFalse(matches.any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun processSingle() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1), factory())
|
||||||
|
|
||||||
|
val result = handler.process(TestOccurrence("main"))
|
||||||
|
|
||||||
|
val occurrences = handler.occurrences()
|
||||||
|
val expected = setOf(TestOccurrence("main"), TestOccurrence("foo"))
|
||||||
|
assertEquals(expected, occurrences)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun processReplaced() {
|
||||||
|
val main1 = rule("main1",
|
||||||
|
headKept(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("foo")
|
||||||
|
))
|
||||||
|
val main2 = rule("main2",
|
||||||
|
headKept(
|
||||||
|
constraint("foo")
|
||||||
|
),
|
||||||
|
headReplaced(
|
||||||
|
constraint("main")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
constraint("bar")
|
||||||
|
))
|
||||||
|
|
||||||
|
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||||
|
|
||||||
|
val result = handler.process(TestOccurrence("main"))
|
||||||
|
|
||||||
|
val occurrences = handler.occurrences()
|
||||||
|
val expected = setOf(TestOccurrence("bar"), TestOccurrence("foo"))
|
||||||
|
assertEquals(expected, occurrences)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun factory() : (Constraint) -> ConstraintOccurrence = { cst -> TestOccurrence(cst) }
|
||||||
Loading…
Reference in New Issue