commonMain.agl.runtime.structure.RuntimeRuleSetBuilder2.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of agl-processor-jvm8 Show documentation
Show all versions of agl-processor-jvm8 Show documentation
Dynamic, scan-on-demand, parsing; when a regular expression is just not enough
The newest version!
/**
* Copyright (C) 2018 Dr. David H. Akehurst (http://dr.david.h.akehurst.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.akehurst.language.agl.runtime.structure
import net.akehurst.language.agl.api.runtime.*
internal fun runtimeRuleSet(qualifiedName: String = "Grammar", init: RuntimeRuleSetBuilder2.() -> Unit): RuntimeRuleSet {
val b = RuntimeRuleSetBuilder2(qualifiedName)
b.init()
return b.build()
}
internal interface RuntimeRuleRhsBuilder {
fun buildRhs(rule: RuntimeRule, ruleMap: Map): RuntimeRuleRhs
}
internal data class RuntimeRuleRef(val tag: String) {
fun resolve(ruleMap: Map) = when (tag) {
RuntimeRuleSet.EMPTY_RULE_TAG -> RuntimeRuleSet.EMPTY
else -> ruleMap[tag] ?: error("Rule with tag $tag not found")
}
}
@RuntimeRuleSetDslMarker
internal class RuntimeRuleSetBuilder2(
val qualifiedName: String
) : RuleSetBuilder {
private val ruleSetNumber = RuntimeRuleSet.nextRuntimeRuleSetNumber++
private val _ruleBuilders = mutableMapOf()
private val _precedenceRuleBuilders = mutableListOf()
internal fun build(): RuntimeRuleSet {
val ruleMap = this._ruleBuilders.values.mapIndexed { ruleNumber, rb ->
val rr = rb.buildRule(ruleNumber)
Pair(rb.tag, rr)
}
.plus(Pair("", RuntimeRuleSet.EMPTY))
.plus(Pair("", RuntimeRuleSet.END_OF_TEXT))
.associate { it }
val rules = this._ruleBuilders.values.map { rb ->
rb.buildRhs(ruleMap)
rb.rule!!
}
val precRules = _precedenceRuleBuilders.map {
it.build(ruleMap)
}
return RuntimeRuleSet(ruleSetNumber, qualifiedName, rules, precRules)
}
private fun _rule(
name: String,
isSkip: Boolean,
build: (rule: RuntimeRule, ruleMap: Map) -> RuntimeRuleRhs
) {
val tag = name
val rb = RuntimeRuleBuilder(ruleSetNumber, name, tag, isSkip) { rule, ruleMap ->
build(rule, ruleMap)
}
this._ruleBuilders[name] = rb
}
fun literal(literalUnescaped: String, isSkip: Boolean = false) = literal(null, literalUnescaped, isSkip)
fun literal(name: String?, literalUnescaped: String, isSkip: Boolean = false) {
val tag = name ?: "'$literalUnescaped'"
if (this._ruleBuilders.containsKey(tag)) {
//do nothing
} else {
val rb = RuntimeRuleBuilder(ruleSetNumber, name, tag, isSkip) { rule, _ ->
RuntimeRuleRhsLiteral(rule, literalUnescaped)
}
this._ruleBuilders[tag] = rb
}
}
fun pattern(value: String, isSkip: Boolean = false) = pattern(null, value, isSkip)
fun pattern(name: String?, patternUnescaped: String, isSkip: Boolean = false) {
val tag = name ?: "\"$patternUnescaped\""
if (this._ruleBuilders.containsKey(tag)) {
//do nothing
} else {
val rb = RuntimeRuleBuilder(ruleSetNumber, name, tag, isSkip) { rule, _ ->
RuntimeRuleRhsPattern(rule, patternUnescaped)
}
this._ruleBuilders[tag] = rb
}
}
override fun choiceLongest(ruleName: String, isSkip: Boolean, init: ChoiceBuilder.() -> Unit) = choice(ruleName, RuntimeRuleChoiceKind.LONGEST_PRIORITY, isSkip, init)
override fun choicePriority(ruleName: String, isSkip: Boolean, init: ChoiceBuilder.() -> Unit) = choice(ruleName, RuntimeRuleChoiceKind.PRIORITY_LONGEST, isSkip, init)
fun choice(name: String, choiceKind: RuntimeRuleChoiceKind, isSkip: Boolean = false, init: ChoiceBuilder.() -> Unit) {
val b = RuntimeRuleChoiceBuilder(this)
b.init()
val tag = name
val rb = RuntimeRuleBuilder(ruleSetNumber, name, tag, isSkip) { rule, ruleMap ->
val options = b.choices.map { rhsB -> rhsB.buildRhs(rule, ruleMap) }
RuntimeRuleRhsChoice(rule, choiceKind, options)
}
this._ruleBuilders[name] = rb
}
override fun concatenation(ruleName: String, isSkip: Boolean, init: ConcatenationBuilder.() -> Unit) {
val b = RuntimeRuleConcatenationBuilder(this)
b.init()
_rule(ruleName, isSkip) { rule, ruleMap ->
b.buildRhs(rule, ruleMap)
}
}
fun optional(ruleName: String, itemRef: String, isSkip: Boolean = false) {
_rule(ruleName, isSkip) { rule, ruleMap ->
val item = RuntimeRuleRef(itemRef).resolve(ruleMap)
RuntimeRuleRhsOptional(rule, item)
}
}
fun multi(ruleName: String, min: Int, max: Int, itemRef: String, isSkip: Boolean = false) {
_rule(ruleName, isSkip) { rule, ruleMap ->
val item = RuntimeRuleRef(itemRef).resolve(ruleMap)
RuntimeRuleRhsListSimple(rule, min, max, item)
}
}
fun sList(ruleName: String, min: Int, max: Int, itemRef: String, sepRef: String, isSkip: Boolean = false) {
_rule(ruleName, isSkip) { rule, ruleMap ->
val item = RuntimeRuleRef(itemRef).resolve(ruleMap)
val sep = RuntimeRuleRef(sepRef).resolve(ruleMap)
RuntimeRuleRhsListSeparated(rule, min, max, item, sep)
}
}
fun embedded(ruleName: String, embeddedRuleSet: RuleSet, startRuleName: String, isSkip: Boolean = false) {
val startRule = (embeddedRuleSet as RuntimeRuleSet).findRuntimeRule(startRuleName)
val tag = ruleName
val rb = RuntimeRuleBuilder(ruleSetNumber, ruleName, tag, isSkip) { rule, _ ->
RuntimeRuleRhsEmbedded(rule, embeddedRuleSet as RuntimeRuleSet, startRule as RuntimeRule)
}
this._ruleBuilders[ruleName] = rb
}
fun preferenceFor(precedenceContextRuleName: String, init: PrecedenceRuleBuilder.() -> Unit) {
val b = PrecedenceRuleBuilder(precedenceContextRuleName)
b.init()
this._precedenceRuleBuilders.add(b)
}
}
@RuntimeRuleSetDslMarker
internal class RuntimeRuleBuilder(
val ruleSetNumber: Int,
val name: String?,
val tag: String,
val isSkip: Boolean,
val rhsBuilder: (rule: RuntimeRule, ruleMap: Map) -> RuntimeRuleRhs
) {
var rule: RuntimeRule? = null
fun buildRule(number: Int): RuntimeRule {
if (null == this.rule) {
this.rule = RuntimeRule(ruleSetNumber, number, name, isSkip)
}
return this.rule!!
}
fun buildRhs(ruleMap: Map) {
val rhs = rhsBuilder.invoke(rule!!, ruleMap)
this.rule!!.setRhs(rhs)
}
}
@RuntimeRuleSetDslMarker
internal class RuntimeRuleConcatenationBuilder(
val rrsb: RuntimeRuleSetBuilder2
) : ConcatenationBuilder, RuntimeRuleRhsBuilder {
internal val itemRefs = mutableListOf()
override fun empty() {
itemRefs.add(RuntimeRuleRef(RuntimeRuleSet.EMPTY.tag))
/* only used in testing no need to - if (Debug.CHECK) */ check(1 == itemRefs.size) { "'empty' must be the only item in a rhs" }
}
override fun literal(value: String) {
val tag = "'$value'"
this.rrsb.literal(null, value)
itemRefs.add(RuntimeRuleRef(tag))
}
override fun pattern(pattern: String) {
val tag = "\"$pattern\""
this.rrsb.pattern(null, pattern)
itemRefs.add(RuntimeRuleRef(tag))
}
override fun ref(name: String) {
val ref = RuntimeRuleRef(name)
itemRefs.add(ref)
}
override fun buildRhs(rule: RuntimeRule, ruleMap: Map): RuntimeRuleRhs {
val items = itemRefs.map { it.resolve(ruleMap) }
return RuntimeRuleRhsConcatenation(rule, items)
}
}
@RuntimeRuleSetDslMarker
internal class RuntimeRuleChoiceBuilder(
val rrsb: RuntimeRuleSetBuilder2,
) : ChoiceBuilder {
val choices = mutableListOf()
fun empty() = concatenation { empty() }
override fun literal(value: String) = concatenation { literal(value) }
override fun pattern(pattern: String) = concatenation { pattern(pattern) }
override fun ref(name: String) = concatenation { ref(name) }
override fun concatenation(init: ConcatenationBuilder.() -> Unit) = concat(init as RuntimeRuleConcatenationBuilder.() -> Unit)
private fun concat(init: RuntimeRuleConcatenationBuilder.() -> Unit) {
val b = RuntimeRuleConcatenationBuilder(rrsb)
b.init()
choices.add(b)
}
}
@RuntimeRuleSetDslMarker
internal class PrecedenceRuleBuilder(
val contextRuleName: String
) {
data class Quad(val first: A, val second: B, val third: C, val fourth: D)
private val _rules = mutableListOf, RuntimePreferenceRule.Assoc>>()
/**
* indicate that @param ruleName is left-associative
*/
fun none(ruleName: String) {
_rules.add(Quad(ruleName, 0, emptySet(), RuntimePreferenceRule.Assoc.NONE))
}
/**
* indicate that @param ruleName is left-associative
*/
fun left(ruleName: String, operatorRuleNames: Set) {
_rules.add(Quad(ruleName, 0, operatorRuleNames, RuntimePreferenceRule.Assoc.LEFT))
}
fun leftOption(ruleName: String, option: Int, operatorRuleNames: Set) {
_rules.add(Quad(ruleName, option, operatorRuleNames, RuntimePreferenceRule.Assoc.LEFT))
}
/**
* indicate that @param ruleName is right-associative
*/
fun right(ruleName: String, operatorRuleNames: Set) {
_rules.add(Quad(ruleName, 0, operatorRuleNames, RuntimePreferenceRule.Assoc.RIGHT))
}
fun rightOption(ruleName: String, option: Int, operatorRuleNames: Set) {
_rules.add(Quad(ruleName, option, operatorRuleNames, RuntimePreferenceRule.Assoc.RIGHT))
}
fun build(ruleMap: Map): RuntimePreferenceRule {
val contextRule = ruleMap[contextRuleName] ?: error("Cannot find rule named '$contextRuleName' as a context rule for precedence definitions")
val rules = _rules.mapIndexed { idx, it ->
val r = ruleMap[it.first] ?: error("Cannot find rule named '${it.first}' for target rule in precedence definitions")
val ops = it.third.map { ruleMap[it] ?: error("Cannot find rule named '${it}' for operator in precedence definitions") }
RuntimePreferenceRule.RuntimePreferenceOption(idx, r, it.second, ops.toSet(), it.fourth)
}
return RuntimePreferenceRule(contextRule, rules)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy