Handlers to have multiple primary constraints. RuleIndex to select handlers with matching primary symbol, if a handler has one. Only "accept-all" handlers process non-primary constraints.

This commit is contained in:
Fedor Isakov 2016-12-28 12:54:19 +01:00
parent 26f12f187d
commit 466c015263
6 changed files with 27 additions and 32 deletions

View File

@ -7,7 +7,7 @@ public abstract class Handler {
public abstract String name();
public abstract ConstraintSymbol primarySymbol();
public abstract Iterable<ConstraintSymbol> primarySymbols();
public abstract Iterable<Rule> rules();

View File

@ -33,35 +33,30 @@ class RuleIndex : Iterable<Rule> {
fun byTag(tag: String): Rule? = tag2rule[tag]
fun forOccurrence(occ: ConstraintOccurrence): Iterable<Rule> {
val primary = primarySymbol2valueIndex.get(occ.constraint().symbol())?.select(occ) ?: emptyList()
val all = allSymbol2valueIndex.get(occ.constraint().symbol())?.select(occ) ?: emptyList()
return primary + all
}
fun forOccurrence(occ: ConstraintOccurrence): Iterable<Rule> =
primarySymbol2valueIndex.get(occ.constraint().symbol())?.select(occ) ?:
(allSymbol2valueIndex.get(occ.constraint().symbol())?.select(occ) ?: emptyList())
override fun iterator(): Iterator<Rule> = tag2rule.values.iterator()
private fun buildIndex(handlers: Iterable<Handler>) {
// first, init the primary symbols value index
handlers
.flatMap { h -> h.primarySymbols() }
.forEach { symbol -> primarySymbol2valueIndex.getOrPut(symbol) { ValueIndex(symbol) } }
for (h in handlers) {
val primaryValueIdx = h.primarySymbol()?.let { symbol ->
allSymbol2valueIndex.getOrPut(symbol) { ValueIndex(symbol) }
}
val hPrimSyms = h.primarySymbols().toSet()
for (r in h.rules()) {
for (c in r.headKept()) {
if (c.symbol() == h.primarySymbol()) {
primaryValueIdx?.update(r, c)
} else if (h.primarySymbol() == null) {
allSymbol2valueIndex.getOrPut(c.symbol()) { ValueIndex(c.symbol()) }.update(r, c)
for (c in (r.headKept() + r.headReplaced())) {
val symbol = c.symbol()
if (symbol in hPrimSyms) {
primarySymbol2valueIndex[symbol]?.update(r, c)
}
}
for (c in r.headReplaced()) {
if (c.symbol() == h.primarySymbol()) {
primaryValueIdx?.update(r, c)
} else if (h.primarySymbol() == null) {
allSymbol2valueIndex.getOrPut(c.symbol()) { ValueIndex(c.symbol()) }.update(r, c)
else if (hPrimSyms.isEmpty()) {
allSymbol2valueIndex.getOrPut(symbol) { ValueIndex(symbol) }.update(r, c)
}
// else ignore the constraint -- it's not meant to be processed by this handler, as it is not a primary
}
}
}

View File

@ -27,7 +27,7 @@ class ProgramBuilder(val registry: ConstraintRegistry) {
}
open class HandlerBuilder(val name: String, val primary: ConstraintSymbol?) {
open class HandlerBuilder(val name: String, val primary: Iterable<ConstraintSymbol>) {
val rules = ArrayList<Rule>()
fun appendRule(rule: Rule) {
@ -61,12 +61,12 @@ open class RuleBuilder(val tag: String) {
class MockHandler(
val name: String,
val primary: ConstraintSymbol?,
val primary: Iterable<ConstraintSymbol>,
val rules: List<Rule>) : Handler() {
override fun name(): String = name
override fun primarySymbol(): ConstraintSymbol? = primary
override fun primarySymbols(): Iterable<ConstraintSymbol> = primary
override fun rules(): Iterable<Rule> = rules
}

View File

@ -34,7 +34,7 @@ fun programWithRules(pb: ProgramBuilder, vararg ruleBuilders : Environment.() ->
}
private fun programWithRules(env: Environment, ruleBuilders: Array<out Environment.() -> Rule>): Builder {
return builder(env, arrayOf(handler("test", null, * ruleBuilders)))
return builder(env, arrayOf(handler("test", emptyList(), * ruleBuilders)))
}
fun programWithHandlers(vararg handlerBuilders : Environment.() -> Handler): Builder {
@ -51,7 +51,7 @@ private fun builder(env: Environment, handlerBlocks: Array<out Environment.() ->
return Builder(env, handlers)
}
fun handler(name: String, primary: ConstraintSymbol?, vararg ruleBlocks: Environment.() -> Rule): Environment.() -> Handler = {
fun handler(name: String, primary: Iterable<ConstraintSymbol>, vararg ruleBlocks: Environment.() -> Rule): Environment.() -> Handler = {
val hb = HandlerBuilder(name, primary)
for (block in ruleBlocks) {
hb.appendRule(this.block())

View File

@ -184,13 +184,13 @@ class TestMatcher {
@Test
fun multipleHandlers() {
programWithHandlers(
handler("handler1", ConstraintSymbol("foo", 0),
handler("handler1", listOf(ConstraintSymbol("foo", 0)),
rule("main1",
headKept(
constraint("foo")
))
),
handler("handler2", ConstraintSymbol("bar", 0),
handler("handler2", listOf(ConstraintSymbol("bar", 0)),
rule("main2",
headKept(
constraint("bar")

View File

@ -39,7 +39,7 @@ class TestProgramBuilder {
constraint("bar")
))).run {
programBuilder.addHandler(MockHandler("test", null, rules))
programBuilder.addHandler(MockHandler("test", emptyList(), rules))
assertEquals(programBuilder.program("test").rules().count(), 1)
assertEquals(programBuilder.program("test").rules().count(), 1)
}
@ -66,7 +66,7 @@ class TestProgramBuilder {
constraint("blah")
))).run {
programBuilder.addHandler(MockHandler("test", null, rules))
programBuilder.addHandler(MockHandler("test", emptyList(), rules))
assertEquals(programBuilder.program("test").rules().count(), 2)
}
}
@ -82,7 +82,7 @@ class TestProgramBuilder {
constraint("bar", "1")
))).run {
programBuilder.addHandler(MockHandler("test", null, rules))
programBuilder.addHandler(MockHandler("test", emptyList(), rules))
}
}
}