183 lines
5.7 KiB
Kotlin
183 lines
5.7 KiB
Kotlin
/**
|
|
* @author Fedor Isakov
|
|
*/
|
|
|
|
import jetbrains.mps.logic.reactor.evaluation.Queryable
|
|
import jetbrains.mps.logic.reactor.evaluation.SessionSolver
|
|
import jetbrains.mps.logic.reactor.logical.LogicalContext
|
|
import jetbrains.mps.logic.reactor.logical.MetaLogical
|
|
import jetbrains.mps.logic.reactor.program.*
|
|
import org.omg.CORBA.Environment
|
|
import program.MockConstraint
|
|
import java.util.*
|
|
import java.util.Collections.*
|
|
|
|
class ProgramBuilder(val registry: MockConstraintRegistry) {
|
|
|
|
private val handlers = ArrayList<Handler>()
|
|
|
|
fun addHandler(handler: Handler) {
|
|
for (r in handler.rules()) {
|
|
registry.update(r)
|
|
}
|
|
handlers.add(handler)
|
|
}
|
|
|
|
fun constraint(symbol: ConstraintSymbol, vararg args: Any): Constraint = MockConstraint(symbol, listOf(* args))
|
|
|
|
fun program(name: String): Program = MockProgram(name, handlers, registry)
|
|
|
|
}
|
|
|
|
open class HandlerBuilder(val name: String, val primary: Iterable<ConstraintSymbol>) {
|
|
val rules = ArrayList<Rule>()
|
|
|
|
fun appendRule(rule: Rule) {
|
|
rules.add(rule)
|
|
}
|
|
|
|
fun toHandler(): Handler = MockHandler(name, primary, rules)
|
|
}
|
|
|
|
open class RuleBuilder(val tag: String) {
|
|
val kept = ArrayList<Constraint>()
|
|
val replaced = ArrayList<Constraint>()
|
|
val guard = ArrayList<Predicate>()
|
|
val body = ArrayList<ArrayList<AndItem>>()
|
|
|
|
fun appendHeadKept(vararg cst: Constraint) {
|
|
kept.addAll(cst)
|
|
}
|
|
fun appendHeadReplaced(vararg cst: Constraint) {
|
|
replaced.addAll(cst)
|
|
}
|
|
fun appendGuard(vararg prd: Predicate) {
|
|
guard.addAll(prd)
|
|
}
|
|
fun appendBody(alt: Boolean, vararg andItem: AndItem) {
|
|
if (alt || body.isEmpty()) body.add(ArrayList<AndItem>())
|
|
body.last().addAll(andItem)
|
|
}
|
|
fun toRule(): Rule = MockRule(tag, kept, replaced, guard, body)
|
|
}
|
|
|
|
class MockHandler(
|
|
val name: String,
|
|
val primary: Iterable<ConstraintSymbol>,
|
|
val rules: List<Rule>) : Handler() {
|
|
|
|
override fun name(): String = name
|
|
|
|
override fun primarySymbols(): Iterable<ConstraintSymbol> = primary
|
|
|
|
override fun rules(): Iterable<Rule> = rules
|
|
}
|
|
|
|
class MockRule(
|
|
val tag: String,
|
|
val kept: Collection<Constraint>,
|
|
val replaced: Collection<Constraint>,
|
|
val guard: Collection<Predicate>,
|
|
val body: Collection<Collection<AndItem>>) : Rule() {
|
|
|
|
override fun kind(): Kind = TODO()
|
|
|
|
override fun tag(): String = tag
|
|
|
|
override fun headKept(): Iterable<Constraint> = kept
|
|
|
|
override fun headReplaced(): Iterable<Constraint> = replaced
|
|
|
|
override fun guard(): Iterable<Predicate> = guard
|
|
|
|
override fun body(): Iterable<AndItem> = body.first()
|
|
|
|
override fun bodyAlternation(): Iterable<Iterable<AndItem>> = body
|
|
|
|
override fun all(): Iterable<AndItem> =
|
|
if (body.isEmpty()) throw InvalidRuleException("no body")
|
|
else (kept + replaced).map { it as AndItem } + guard + body.flatten()
|
|
}
|
|
|
|
class MockProgram(val name: String, val handlers: List<Handler>, val registry: MockConstraintRegistry) : Program() {
|
|
|
|
override fun name(): String = name
|
|
|
|
override fun constraintSymbols(): Iterable<ConstraintSymbol> =
|
|
registry.constraintSymbols()
|
|
|
|
override fun constraintArgumentTypes(constraintSymbol: ConstraintSymbol): List<Class<*>> =
|
|
registry.constraintArgTypes(constraintSymbol)
|
|
|
|
override fun predicateSymbols(): Iterable<PredicateSymbol> =
|
|
registry.predicateSymbols()
|
|
|
|
override fun occurrenceArguments(constraint: Constraint, logicalContext: LogicalContext): List<*> =
|
|
constraint.arguments().map { a ->
|
|
if (a is MetaLogical<*>) logicalContext.variable(a)
|
|
else a
|
|
}
|
|
|
|
override fun rules(): Iterable<Rule> = handlers.flatMap { it.rules() }
|
|
|
|
override fun handlers(): Iterable<Handler> = unmodifiableCollection(handlers)
|
|
}
|
|
|
|
|
|
class MockConstraintRegistry(val sessionSolver: SessionSolver) {
|
|
|
|
private val myConstraintArgTypes = HashMap<ConstraintSymbol, List<Class<*>>>().withDefault { Collections.emptyList() }
|
|
|
|
private val myPredicateSymbols = HashSet<PredicateSymbol>()
|
|
|
|
fun update(rule: Rule) {
|
|
for(item in rule.all()) {
|
|
checkValid(item)
|
|
introduce(item)
|
|
}
|
|
}
|
|
|
|
fun checkValid(item: AndItem) {
|
|
if (item.symbol().arity() != item.arguments().size) {
|
|
throw InvalidConstraintException("arity mismatch: ${item.symbol()}")
|
|
}
|
|
for (arg in item.arguments()) {
|
|
if (arg == null) {
|
|
throw InvalidConstraintException("argument is null: ${item.symbol()}")
|
|
}
|
|
}
|
|
when(item) {
|
|
is Constraint -> {
|
|
if (myConstraintArgTypes.containsKey(item.symbol())) {
|
|
if (!item.argumentTypes().equals(myConstraintArgTypes.get(item.symbol()))) {
|
|
throw InvalidConstraintException("argument types mismatch: ${item.symbol()}")
|
|
}
|
|
}
|
|
}
|
|
is Predicate -> {
|
|
// nothing
|
|
}
|
|
else -> throw InvalidConstraintException("unknown item: ${item}")
|
|
}
|
|
}
|
|
|
|
fun introduce(item: AndItem) {
|
|
when(item) {
|
|
is Constraint -> myConstraintArgTypes.put(item.symbol(), item.argumentTypes())
|
|
is Predicate -> myPredicateSymbols.add(item.symbol())
|
|
else -> throw InvalidConstraintException("unknown item: ${item}")
|
|
}
|
|
}
|
|
|
|
fun constraintSymbols(): Iterable<ConstraintSymbol> =
|
|
unmodifiableSet(myConstraintArgTypes.keys)
|
|
|
|
fun constraintArgTypes(symbol: ConstraintSymbol): List<Class<*>> =
|
|
unmodifiableList(myConstraintArgTypes.getOrPut(symbol, { emptyList() }))
|
|
|
|
fun predicateSymbols(): Iterable<PredicateSymbol> =
|
|
unmodifiableSet(myPredicateSymbols)
|
|
|
|
}
|
|
|