Initial support for expressions
This commit is contained in:
parent
a7708f3974
commit
fc372c1420
|
|
@ -11,16 +11,19 @@ import java.util.*
|
|||
|
||||
class RuleHandler {
|
||||
|
||||
private val sessionSolver: SessionSolver
|
||||
private val occurrenceFactory: (Constraint) -> ConstraintOccurrence
|
||||
private val rules : MutableList<Rule> = ArrayList<Rule>()
|
||||
private val stored : MutableList<ConstraintOccurrence> = ArrayList<ConstraintOccurrence>()
|
||||
|
||||
constructor(
|
||||
sessionSolver: SessionSolver,
|
||||
programRules: Iterable<Rule>,
|
||||
occurrenceFactory: (Constraint) -> ConstraintOccurrence,
|
||||
// for testing purposes only
|
||||
occurrences: Iterable<ConstraintOccurrence>? = null)
|
||||
{
|
||||
this.sessionSolver = sessionSolver
|
||||
this.occurrenceFactory = occurrenceFactory
|
||||
this.rules.addAll(programRules)
|
||||
if (occurrences != null) {
|
||||
|
|
@ -51,16 +54,27 @@ class RuleHandler {
|
|||
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(item: AndItem) {
|
||||
when(item) {
|
||||
is Constraint -> process(activate(item))
|
||||
is Predicate -> tellPredicate(item)
|
||||
else -> throw IllegalArgumentException("unknown item ${item}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun activate(constraint: Constraint): ConstraintOccurrence = occurrenceFactory(constraint)
|
||||
|
||||
private fun tellPredicate(predicate: Predicate) {
|
||||
when (predicate.symbol()) {
|
||||
is JavaPredicateSymbol -> evalJava(predicate)
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private fun evalJava(expr: Predicate) {
|
||||
sessionSolver.tell(expr.symbol(), * expr.arguments().toTypedArray())
|
||||
}
|
||||
|
||||
fun lookupMatches(occ: ConstraintOccurrence): Iterable<PartialMatch> {
|
||||
val partialMatches = rules.flatMap { r ->
|
||||
val matchedKept = r.headKept().filter { cst -> cst.matches(occ) }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,17 @@ import jetbrains.mps.logic.reactor.constraint.*
|
|||
* @author Fedor Isakov
|
||||
*/
|
||||
|
||||
class ReactorSessionSolver : SessionSolver() {
|
||||
class ReactorSessionSolver(val expressionSolver: Queryable) : SessionSolver() {
|
||||
|
||||
constructor() : this(object: Queryable {
|
||||
override fun ask(predicateSymbol: PredicateSymbol?, vararg args: Any?): Boolean {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun tell(symbol: Symbol?, vararg args: Any?) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
})
|
||||
|
||||
override fun solverClass(predicateSymbol: PredicateSymbol?): Class<out Queryable>? {
|
||||
throw UnsupportedOperationException()
|
||||
|
|
@ -14,10 +24,9 @@ class ReactorSessionSolver : SessionSolver() {
|
|||
|
||||
override fun registerSymbol(predicateSymbol: PredicateSymbol, computingTracer: ComputingTracer?) {
|
||||
when (predicateSymbol) {
|
||||
|
||||
is JavaPredicateSymbol -> registerSolver(predicateSymbol, expressionSolver)
|
||||
else -> throw UnsupportedOperationException("not implemented")
|
||||
}
|
||||
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,28 @@ import jetbrains.mps.logic.reactor.constraint.*
|
|||
import jetbrains.mps.logic.reactor.rule.Rule
|
||||
import jetbrains.mps.logic.reactor.rule.RuleBuilder
|
||||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* @author Fedor Isakov
|
||||
*/
|
||||
|
||||
fun rule(tag: String, vararg component:RB.() -> Unit): Rule {
|
||||
val rb = RB(tag)
|
||||
fun program(vararg ruleBuilders : Environment.() -> Rule): Program {
|
||||
val env = Environment()
|
||||
val rules = ArrayList<Rule>()
|
||||
with (env) {
|
||||
for (rb in ruleBuilders) {
|
||||
rules.add(rb())
|
||||
}
|
||||
}
|
||||
return Program(env, rules)
|
||||
}
|
||||
|
||||
fun rule(tag: String, vararg component:RB.() -> Unit): Environment.() -> Rule = {
|
||||
rule(tag, this, * component)
|
||||
}
|
||||
|
||||
fun rule(tag: String, env: Environment, vararg component:RB.() -> Unit): Rule {
|
||||
val rb = RB(tag, env)
|
||||
for (cmp in component) {
|
||||
rb.cmp()
|
||||
}
|
||||
|
|
@ -17,55 +31,89 @@ fun rule(tag: String, vararg component:RB.() -> Unit): Rule {
|
|||
}
|
||||
|
||||
fun headKept(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||
appendHeadKept( * buildConjunction(Constraint::class.java, content).toArray())
|
||||
appendHeadKept( * buildConjunction(Constraint::class.java, env, content).toArray())
|
||||
}
|
||||
fun headReplaced(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||
appendHeadReplaced( * buildConjunction(Constraint::class.java, content).toArray())
|
||||
appendHeadReplaced( * buildConjunction(Constraint::class.java, env, content).toArray())
|
||||
}
|
||||
fun guard(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||
appendGuard( * buildConjunction(AndItem::class.java, content).toArray())
|
||||
appendGuard( * buildConjunction(Predicate::class.java, env, content).toArray())
|
||||
}
|
||||
fun body(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
|
||||
appendBody( * buildConjunction(AndItem::class.java, content).toArray())
|
||||
appendBody( * buildConjunction(AndItem::class.java, env, content).toArray())
|
||||
}
|
||||
|
||||
fun constraint(id: String): ConjBuilder.() -> Unit = {
|
||||
add(TestConstraint(ConstraintSymbol.symbol(id, 0)))
|
||||
}
|
||||
fun constraint(id: String, arg: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestConstraint(ConstraintSymbol.symbol(id, 1), arg))
|
||||
}
|
||||
fun constraint(id: String, arg1: Any, arg2: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestConstraint(ConstraintSymbol.symbol(id, 2), arg1, arg2))
|
||||
}
|
||||
fun constraint(id: String, arg1: Any, arg2: Any, arg3: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestConstraint(ConstraintSymbol.symbol(id, 3), arg1, arg2, arg3))
|
||||
}
|
||||
fun constraint(id: String, args: Array<out Any>): ConjBuilder.() -> Unit = {
|
||||
fun constraint(id: String, vararg args: Any): ConjBuilder.() -> Unit = {
|
||||
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))
|
||||
fun expression(body: () -> Boolean): ConjBuilder.() -> Unit = {
|
||||
add(TestJavaPredicate(JavaPredicateSymbol(1),body))
|
||||
}
|
||||
|
||||
class RB(tag: String) : RuleBuilder(tag) {}
|
||||
fun expression(body: (Any) -> Boolean, vararg args: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestJavaPredicate(JavaPredicateSymbol(2), body, * args))
|
||||
}
|
||||
|
||||
class ConjBuilder (val type: Class<out AndItem>) {
|
||||
fun expression(body: (Any, Any) -> Boolean, vararg args: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestJavaPredicate(JavaPredicateSymbol(3), body, * args))
|
||||
}
|
||||
|
||||
fun expression(body: (Any, Any, Any) -> Boolean, vararg args: Any): ConjBuilder.() -> Unit = {
|
||||
add(TestJavaPredicate(JavaPredicateSymbol(4), body, * args))
|
||||
}
|
||||
|
||||
class Program(val env: Environment, val rules: List<Rule>) {
|
||||
fun occurrenceFactory() : (Constraint) -> ConstraintOccurrence = { cst -> TestOccurrence(cst) }
|
||||
}
|
||||
|
||||
class Environment() {
|
||||
|
||||
val javaPredicates = HashMap<Any, TestJavaPredicate>()
|
||||
|
||||
fun expressionSolver(): Queryable = object : Queryable {
|
||||
|
||||
override fun ask(predicateSymbol: PredicateSymbol, vararg args: Any): Boolean {
|
||||
return javaPredicates[predicateSymbol]?.expr?.invoke(listOf(* args)) ?:
|
||||
ERROR("no such symbol $predicateSymbol")
|
||||
}
|
||||
|
||||
override fun tell(symbol: Symbol, vararg args: Any) {
|
||||
when (symbol) {
|
||||
is JavaPredicateSymbol -> javaPredicates[args[0]]?.expr?.invoke(listOf(* args).drop(1))
|
||||
else -> ERROR("uknown symbol $symbol")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ERROR(msg: String) : Nothing = throw IllegalArgumentException(msg)
|
||||
}
|
||||
|
||||
fun addJavaPredicate(javaPredicate: TestJavaPredicate) {
|
||||
javaPredicates[javaPredicate.args[0]] = javaPredicate
|
||||
}
|
||||
}
|
||||
|
||||
class RB(tag: String, val env: Environment?) : RuleBuilder(tag) {}
|
||||
|
||||
class ConjBuilder {
|
||||
val constraints = ArrayList<AndItem>()
|
||||
fun add(constraint: AndItem): Unit {
|
||||
if (!type.isAssignableFrom(constraint.javaClass))
|
||||
throw IllegalArgumentException("unexpected constraint class '${constraint.javaClass}'")
|
||||
constraints.add(constraint)
|
||||
val type: Class<out AndItem>
|
||||
val _env: Environment?
|
||||
val env: Environment
|
||||
get() { return _env ?: throw IllegalStateException("no enviroment") }
|
||||
|
||||
constructor(type: Class<out AndItem>, env: Environment?) {
|
||||
this.type = type
|
||||
this._env = env
|
||||
}
|
||||
|
||||
fun add(item: AndItem): Unit {
|
||||
if (!type.isAssignableFrom(item.javaClass))
|
||||
throw IllegalArgumentException("unexpected constraint class '${item.javaClass}'")
|
||||
constraints.add(item)
|
||||
if (item is TestJavaPredicate) {
|
||||
env.addJavaPredicate(item)
|
||||
}
|
||||
}
|
||||
fun <T : AndItem> toArray(): Array<T> =
|
||||
if (Constraint::class.java.isAssignableFrom(type))
|
||||
|
|
@ -79,9 +127,10 @@ class ConjBuilder (val type: Class<out AndItem>) {
|
|||
}
|
||||
|
||||
private fun buildConjunction(type: Class<out AndItem>,
|
||||
env: Environment?,
|
||||
content: Array<out ConjBuilder.() -> Unit>): ConjBuilder
|
||||
{
|
||||
var conjBuilder = ConjBuilder(type)
|
||||
var conjBuilder = ConjBuilder(type, env)
|
||||
for (c in content) {
|
||||
conjBuilder.c()
|
||||
}
|
||||
|
|
@ -116,3 +165,55 @@ data class TestConstraint(val symbol: ConstraintSymbol, val arguments: List<Any>
|
|||
override fun toString(): String = "${symbol()}(${arguments().joinToString()})"
|
||||
|
||||
}
|
||||
|
||||
interface JavaExpression {
|
||||
fun invoke(args: List<Any>): Boolean
|
||||
}
|
||||
|
||||
class JavaExpression0(val code: () -> Boolean) : JavaExpression {
|
||||
override fun invoke(args: List<Any>): Boolean {
|
||||
if (args.size != 0) throw IllegalArgumentException("arity mismatch")
|
||||
return code()
|
||||
}
|
||||
}
|
||||
|
||||
class JavaExpression1(val code: (Any) -> Boolean) : JavaExpression {
|
||||
override fun invoke(args: List<Any>): Boolean {
|
||||
if (args.size != 1) throw IllegalArgumentException("arity mismatch")
|
||||
return code(args[0])
|
||||
}
|
||||
}
|
||||
|
||||
class JavaExpression2(val code: (Any, Any) -> Boolean) : JavaExpression {
|
||||
override fun invoke(args: List<Any>): Boolean {
|
||||
if (args.size != 2) throw IllegalArgumentException("arity mismatch")
|
||||
return code(args[0], args[1])
|
||||
}
|
||||
}
|
||||
|
||||
class JavaExpression3(val code: (Any, Any, Any) -> Boolean) : JavaExpression {
|
||||
override fun invoke(args: List<Any>): Boolean {
|
||||
if (args.size != 3) throw IllegalArgumentException("arity mismatch")
|
||||
return code(args[0], args[1], args[2])
|
||||
}
|
||||
}
|
||||
|
||||
data class TestJavaPredicate(val symbol: JavaPredicateSymbol, val expr: JavaExpression, val args: List<Any>) : Predicate {
|
||||
|
||||
constructor(symbol: JavaPredicateSymbol, code: () -> Boolean, vararg args: Any) :
|
||||
this(symbol, JavaExpression0(code), listOf(code.toString()) + listOf(* args)) {}
|
||||
|
||||
constructor(symbol: JavaPredicateSymbol, code: (Any) -> Boolean, vararg args: Any) :
|
||||
this(symbol, JavaExpression1(code), listOf(code.toString()) + listOf(* args)) {}
|
||||
|
||||
constructor(symbol: JavaPredicateSymbol, code: (Any, Any) -> Boolean, vararg args: Any) :
|
||||
this(symbol, JavaExpression2(code), listOf(code.toString()) + listOf(* args)) {}
|
||||
|
||||
constructor(symbol: JavaPredicateSymbol, code: (Any, Any, Any) -> Boolean, vararg args: Any) :
|
||||
this(symbol, JavaExpression3(code), listOf(code.toString()) + listOf(* args)) {}
|
||||
|
||||
override fun arguments(): List<Any> = args
|
||||
|
||||
override fun symbol(): PredicateSymbol = symbol
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@ class TestBasicProgram {
|
|||
}
|
||||
|
||||
@Before fun beforeTest() {
|
||||
program = PlanningSession.newSession("test", ReactorSessionSolver())
|
||||
evalConfig = EvaluationSession.newSession(program)
|
||||
planningSession = PlanningSession.newSession("test", ReactorSessionSolver())
|
||||
evalConfig = EvaluationSession.newSession(planningSession)
|
||||
}
|
||||
|
||||
lateinit var program: PlanningSession
|
||||
lateinit var planningSession: PlanningSession
|
||||
lateinit var evalConfig: EvaluationSession.Config
|
||||
|
||||
@Test
|
||||
fun replace() {
|
||||
program.addRules(arrayListOf(
|
||||
program(
|
||||
rule("main",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
|
|
@ -50,12 +50,11 @@ class TestBasicProgram {
|
|||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))
|
||||
))
|
||||
assertEquals(program.rules().count(), 2)
|
||||
val session = evalConfig.start()
|
||||
|
||||
|
||||
))).run {
|
||||
|
||||
planningSession.addRules(rules)
|
||||
assertEquals(planningSession.rules().count(), 2)
|
||||
val session = evalConfig.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,18 +35,20 @@ class TestPlanningSession {
|
|||
|
||||
@Test(expected = InvalidRuleException::class)
|
||||
fun emptyBody() {
|
||||
session.addRules(arrayListOf(
|
||||
program(
|
||||
rule("foo",
|
||||
headKept(
|
||||
constraint("bar")
|
||||
))
|
||||
))
|
||||
assertEquals(session.rules().count(), 1)
|
||||
))).run {
|
||||
|
||||
session.addRules(rules)
|
||||
assertEquals(session.rules().count(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun replace() {
|
||||
session.addRules(arrayListOf(
|
||||
program(
|
||||
rule("foo",
|
||||
headReplaced(
|
||||
constraint("bar")
|
||||
|
|
@ -63,22 +65,26 @@ class TestPlanningSession {
|
|||
),
|
||||
body(
|
||||
constraint("blah")
|
||||
))
|
||||
))
|
||||
assertEquals(session.rules().count(), 2)
|
||||
))).run {
|
||||
|
||||
session.addRules(rules)
|
||||
assertEquals(session.rules().count(), 2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = InvalidConstraintException::class)
|
||||
fun fail() {
|
||||
session.addRules(arrayListOf(
|
||||
program(
|
||||
rule("foo",
|
||||
headReplaced(
|
||||
constraint("bar", 1)
|
||||
),
|
||||
body(
|
||||
constraint("bar", "1")
|
||||
))
|
||||
))
|
||||
))).run {
|
||||
|
||||
session.addRules(rules)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import jetbrains.mps.logic.reactor.constraint.Constraint
|
||||
import jetbrains.mps.logic.reactor.constraint.ConstraintOccurrence
|
||||
import jetbrains.mps.logic.reactor.constraint.JavaPredicateSymbol
|
||||
import jetbrains.mps.logic.reactor.constraint.Queryable
|
||||
import jetbrains.mps.logic.reactor.constraint.SessionSolver
|
||||
import jetbrains.mps.logic.reactor.core.RuleHandler
|
||||
import jetbrains.mps.logic.reactor.predicate.ReactorSessionSolver
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
|
|
@ -13,207 +18,245 @@ import kotlin.test.assertTrue
|
|||
|
||||
class TestRuleHandler {
|
||||
|
||||
@Test
|
||||
fun matchSingle() {
|
||||
val main = rule("main",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
))
|
||||
fun occurrence(id: String, vararg args: Any) : TestOccurrence = TestOccurrence(id, * args)
|
||||
|
||||
val handler = RuleHandler(listOf(main), factory())
|
||||
fun sessionSolver(exprSolver: Queryable) : SessionSolver =
|
||||
ReactorSessionSolver(exprSolver).apply { init(JavaPredicateSymbol.EXPRESSION0, JavaPredicateSymbol.EXPRESSION1, JavaPredicateSymbol.EXPRESSION2, JavaPredicateSymbol.EXPRESSION3) }
|
||||
|
||||
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")
|
||||
fun Program.handler(vararg occurrences: ConstraintOccurrence): RuleHandler =
|
||||
RuleHandler(sessionSolver(env.expressionSolver()), rules, occurrenceFactory(), listOf(* occurrences))
|
||||
|
||||
companion object {
|
||||
@BeforeClass @JvmStatic fun setup() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Before fun beforeTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun matchDiscardedKept() {
|
||||
val main1 = rule("main1",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
))
|
||||
val main2 = rule("main2",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))
|
||||
fun matchSingle() {
|
||||
program(
|
||||
rule("main",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
))).run {
|
||||
|
||||
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||
val main = rules.first()
|
||||
|
||||
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
|
||||
val matches = handler().lookupMatches(occurrence("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() {
|
||||
program(
|
||||
rule("main1",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
val matches = handler().lookupMatches(occurrence("main"))
|
||||
assertFalse { matches.any { m -> m.isPartial() } }
|
||||
assertEquals(rules, 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")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
headReplaced(
|
||||
constraint("secondary")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
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 })
|
||||
val matches = handler().lookupMatches(occurrence("main"))
|
||||
assertFalse { matches.any { m -> m.isPartial() } }
|
||||
assertEquals(rules.drop(1), 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")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
headReplaced(
|
||||
constraint("aux")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
val handler = RuleHandler(listOf(main1, main2), factory(), listOf(TestOccurrence("secondary")))
|
||||
val matches = handler(TestOccurrence("aux")).lookupMatches(occurrence("main"))
|
||||
|
||||
val matches = handler.lookupMatches(TestOccurrence("main"))
|
||||
assertFalse { matches.any { m -> m.isPartial() } }
|
||||
assertEquals(listOf(main1, main2), matches.map { m -> m.rule })
|
||||
assertFalse { matches.any { m -> m.isPartial() } }
|
||||
assertEquals(rules, 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")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main", "foo")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("main", "bar")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
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 })
|
||||
val matches = handler().lookupMatches(occurrence("main", "bar"))
|
||||
assertFalse { matches.any { m -> m.isPartial() } }
|
||||
assertEquals(rules.drop(1), 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")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main", "foo")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("main", "bar")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||
|
||||
val matches = handler.lookupMatches(TestOccurrence("main", "qux"))
|
||||
assertFalse(matches.any())
|
||||
val matches = handler().lookupMatches(occurrence("main", "qux"))
|
||||
assertFalse(matches.any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun processSingle() {
|
||||
val main1 = rule("main1",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
))).run {
|
||||
|
||||
val handler = RuleHandler(listOf(main1), factory())
|
||||
val rh = handler()
|
||||
val result = rh.process(occurrence("main"))
|
||||
|
||||
val result = handler.process(TestOccurrence("main"))
|
||||
|
||||
val occurrences = handler.occurrences()
|
||||
val expected = setOf(TestOccurrence("main"), TestOccurrence("foo"))
|
||||
assertEquals(expected, occurrences)
|
||||
val occurrences = rh.occurrences()
|
||||
val expected = setOf(occurrence("main"), occurrence("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")
|
||||
))
|
||||
program(
|
||||
rule("main1",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("foo")
|
||||
)),
|
||||
rule("main2",
|
||||
headKept(
|
||||
constraint("foo")
|
||||
),
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
constraint("bar")
|
||||
))).run {
|
||||
|
||||
val handler = RuleHandler(listOf(main1, main2), factory())
|
||||
val rh = handler()
|
||||
val result = rh.process(occurrence("main"))
|
||||
|
||||
val result = handler.process(TestOccurrence("main"))
|
||||
|
||||
val occurrences = handler.occurrences()
|
||||
val expected = setOf(TestOccurrence("bar"), TestOccurrence("foo"))
|
||||
assertEquals(expected, occurrences)
|
||||
val occurrences = rh.occurrences()
|
||||
val expected = setOf(occurrence("bar"), occurrence("foo"))
|
||||
assertEquals(expected, occurrences)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun basicExpression() {
|
||||
var test : String = "not initialized"
|
||||
program(
|
||||
rule("main",
|
||||
headKept(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
expression { -> test = "value"; true }
|
||||
))).run {
|
||||
|
||||
val result = handler().process(occurrence("main"))
|
||||
|
||||
assertEquals("value", test)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun factory() : (Constraint) -> ConstraintOccurrence = { cst -> TestOccurrence(cst) }
|
||||
Loading…
Reference in New Issue