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
|
||||
|
||||
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.predicate.ReactorSessionSolver
|
||||
import jetbrains.mps.logic.reactor.program.EvaluationSession
|
||||
import jetbrains.mps.logic.reactor.program.PlanningSession
|
||||
import jetbrains.mps.logic.reactor.rule.Rule
|
||||
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?>()
|
||||
var myComputingTracer : ComputingTracer? = null
|
||||
var myComputingTracer: ComputingTracer? = null
|
||||
|
||||
override fun withPredicates(vararg predicateSymbols: PredicateSymbol): EvaluationSession.Config {
|
||||
myPredicateSymbols.addAll(Arrays.asList(* predicateSymbols))
|
||||
|
|
@ -38,19 +42,28 @@ private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : Evalu
|
|||
if (session != null) throw IllegalStateException("session already active")
|
||||
|
||||
val predicateSymbols = myPredicateSymbols.toArray<PredicateSymbol>(arrayOfNulls(myPredicateSymbols.size))
|
||||
val sessionSolver = ReactorSessionSolver()
|
||||
val sessionSolver = program.sessionSolver()
|
||||
sessionSolver.init(myComputingTracer, * predicateSymbols)
|
||||
|
||||
session = ReactorEvaluationSession(sessionSolver)
|
||||
session = ReactorEvaluationSession(program)
|
||||
ourBackend.ourSession.set(session)
|
||||
|
||||
session.launch()
|
||||
|
||||
return session
|
||||
}
|
||||
}
|
||||
|
||||
override fun sessionSolver(): SessionSolver? {
|
||||
throw UnsupportedOperationException()
|
||||
fun launch() {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun sessionSolver(): SessionSolver = program.sessionSolver()
|
||||
|
||||
override fun constraintSymbols(): MutableIterable<ConstraintSymbol>? {
|
||||
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 createConfig(): EvaluationSession.Config = Config()
|
||||
override fun createConfig(program: PlanningSession): EvaluationSession.Config = Config(program)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -79,7 +92,7 @@ private class ReactorEvaluationSession(val sessionSolver: SessionSolver) : Evalu
|
|||
setBackend(ourBackend)
|
||||
}
|
||||
|
||||
fun deinit () {
|
||||
fun deinit() {
|
||||
clearBackend(ourBackend)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class ReactorPlanningSession(val name: String, val sessionSolver: SessionSolver)
|
|||
|
||||
override fun name(): String = name
|
||||
|
||||
override fun sessionSolver(): SessionSolver= sessionSolver
|
||||
|
||||
override fun constraintSymbols(): Iterable<ConstraintSymbol> =
|
||||
myRegistry.constraintSymbols()
|
||||
|
||||
|
|
@ -114,7 +116,7 @@ private class ConstraintRegistry(val sessionSolver: SessionSolver) {
|
|||
unmodifiableSet(myConstraintArgTypes.keys)
|
||||
|
||||
fun constraintArgTypes(symbol: ConstraintSymbol): List<Class<*>> =
|
||||
unmodifiableList(myConstraintArgTypes.getOrDefault(symbol, emptyList()))
|
||||
unmodifiableList(myConstraintArgTypes.getOrDefault(symbol, Collections.emptyList()))
|
||||
|
||||
fun predicateSymbols(): Iterable<PredicateSymbol> =
|
||||
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())
|
||||
}
|
||||
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 = {
|
||||
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 = {
|
||||
add(AbstractConstraint(ConstraintSymbol.symbol(id, 0)))
|
||||
add(TestConstraint(ConstraintSymbol.symbol(id, 0)))
|
||||
}
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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) {}
|
||||
|
|
@ -75,3 +88,31 @@ private fun buildConjunction(type: Class<out AndItem>,
|
|||
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.InvalidRuleException
|
||||
import jetbrains.mps.logic.reactor.core.ReactorPlanningSession
|
||||
import jetbrains.mps.logic.reactor.predicate.ReactorSessionSolver
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
|
|
@ -14,7 +15,7 @@ import kotlin.test.expect
|
|||
* @author Fedor Isakov
|
||||
*/
|
||||
|
||||
class Simple {
|
||||
class TestPlanningSession {
|
||||
|
||||
companion object {
|
||||
@BeforeClass @JvmStatic fun setup() {
|
||||
|
|
@ -23,10 +24,10 @@ class Simple {
|
|||
}
|
||||
|
||||
@Before fun beforeTest() {
|
||||
session = PlanningSession.newSession("test", null)
|
||||
session = PlanningSession.newSession("test", ReactorSessionSolver())
|
||||
}
|
||||
|
||||
lateinit var session:PlanningSession
|
||||
lateinit var session: PlanningSession
|
||||
|
||||
@Test fun empty() {
|
||||
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