mps-coderules/reactor/Test/test/Rules.kt

220 lines
7.5 KiB
Kotlin

import jetbrains.mps.logic.reactor.constraint.*
import jetbrains.mps.logic.reactor.rule.Rule
import jetbrains.mps.logic.reactor.rule.RuleBuilder
import java.util.*
/**
* @author Fedor Isakov
*/
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()
}
return rb.toRule()
}
fun headKept(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
appendHeadKept( * buildConjunction(Constraint::class.java, env, content).toArray())
}
fun headReplaced(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
appendHeadReplaced( * buildConjunction(Constraint::class.java, env, content).toArray())
}
fun guard(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
appendGuard( * buildConjunction(Predicate::class.java, env, content).toArray())
}
fun body(vararg content : ConjBuilder.() -> Unit): RB.() -> Unit = {
appendBody( * buildConjunction(AndItem::class.java, env, content).toArray())
}
fun constraint(id: String, vararg args: Any): ConjBuilder.() -> Unit = {
add(TestConstraint(ConstraintSymbol.symbol(id, args.size), * args))
}
fun expression(body: () -> Boolean): ConjBuilder.() -> Unit = {
add(TestJavaPredicate(JavaPredicateSymbol(1),body))
}
fun expression(body: (Any) -> Boolean, vararg args: Any): ConjBuilder.() -> Unit = {
add(TestJavaPredicate(JavaPredicateSymbol(2), body, * args))
}
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>()
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))
Array<Constraint>(constraints.size) {
constraints.get(it) as Constraint
} as Array<T>
else
Array<AndItem>(constraints.size) {
constraints.get(it)
} as Array<T>
}
private fun buildConjunction(type: Class<out AndItem>,
env: Environment?,
content: Array<out ConjBuilder.() -> Unit>): ConjBuilder
{
var conjBuilder = ConjBuilder(type, env)
for (c in content) {
conjBuilder.c()
}
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()})"
}
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
}