From fc372c1420aef8c24873a7efdfe7f48aefb15333 Mon Sep 17 00:00:00 2001 From: Fedor Isakov Date: Wed, 9 Dec 2015 17:04:28 +0100 Subject: [PATCH] Initial support for expressions --- .../mps/logic/reactor/core/RuleHandler.kt | 24 +- .../reactor/predicate/ReactorSessionSolver.kt | 17 +- reactor/Test/test/Rules.kt | 177 +++++++-- reactor/Test/test/TestBasicProgram.kt | 19 +- reactor/Test/test/TestPlanningSession.kt | 28 +- reactor/Test/test/TestRuleHandler.kt | 357 ++++++++++-------- 6 files changed, 397 insertions(+), 225 deletions(-) diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleHandler.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleHandler.kt index 9e02fcf3..85577762 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleHandler.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleHandler.kt @@ -11,16 +11,19 @@ import java.util.* class RuleHandler { + private val sessionSolver: SessionSolver private val occurrenceFactory: (Constraint) -> ConstraintOccurrence private val rules : MutableList = ArrayList() private val stored : MutableList = ArrayList() constructor( + sessionSolver: SessionSolver, programRules: Iterable, occurrenceFactory: (Constraint) -> ConstraintOccurrence, // for testing purposes only occurrences: Iterable? = 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 { val partialMatches = rules.flatMap { r -> val matchedKept = r.headKept().filter { cst -> cst.matches(occ) } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/predicate/ReactorSessionSolver.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/predicate/ReactorSessionSolver.kt index 61e3d66f..52e3d758 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/predicate/ReactorSessionSolver.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/predicate/ReactorSessionSolver.kt @@ -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? { 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() } } diff --git a/reactor/Test/test/Rules.kt b/reactor/Test/test/Rules.kt index 75963bfe..5f6851ab 100644 --- a/reactor/Test/test/Rules.kt +++ b/reactor/Test/test/Rules.kt @@ -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() + 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): 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) { +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) { + fun occurrenceFactory() : (Constraint) -> ConstraintOccurrence = { cst -> TestOccurrence(cst) } +} + +class Environment() { + + val javaPredicates = HashMap() + + 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() - fun add(constraint: AndItem): Unit { - if (!type.isAssignableFrom(constraint.javaClass)) - throw IllegalArgumentException("unexpected constraint class '${constraint.javaClass}'") - constraints.add(constraint) + val type: Class + val _env: Environment? + val env: Environment + get() { return _env ?: throw IllegalStateException("no enviroment") } + + constructor(type: Class, 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 toArray(): Array = if (Constraint::class.java.isAssignableFrom(type)) @@ -79,9 +127,10 @@ class ConjBuilder (val type: Class) { } private fun buildConjunction(type: Class, + env: Environment?, content: Array 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 override fun toString(): String = "${symbol()}(${arguments().joinToString()})" } + +interface JavaExpression { + fun invoke(args: List): Boolean +} + +class JavaExpression0(val code: () -> Boolean) : JavaExpression { + override fun invoke(args: List): Boolean { + if (args.size != 0) throw IllegalArgumentException("arity mismatch") + return code() + } +} + +class JavaExpression1(val code: (Any) -> Boolean) : JavaExpression { + override fun invoke(args: List): 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): 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): 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) : 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 = args + + override fun symbol(): PredicateSymbol = symbol + +} diff --git a/reactor/Test/test/TestBasicProgram.kt b/reactor/Test/test/TestBasicProgram.kt index cf655289..2634fe1b 100644 --- a/reactor/Test/test/TestBasicProgram.kt +++ b/reactor/Test/test/TestBasicProgram.kt @@ -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() + } } } diff --git a/reactor/Test/test/TestPlanningSession.kt b/reactor/Test/test/TestPlanningSession.kt index a9c5b5cb..521b6624 100644 --- a/reactor/Test/test/TestPlanningSession.kt +++ b/reactor/Test/test/TestPlanningSession.kt @@ -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) + } } } diff --git a/reactor/Test/test/TestRuleHandler.kt b/reactor/Test/test/TestRuleHandler.kt index 1a7b2571..16c9cf5d 100644 --- a/reactor/Test/test/TestRuleHandler.kt +++ b/reactor/Test/test/TestRuleHandler.kt @@ -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) } \ No newline at end of file