commonMain.agl.automaton.buildCacheInfo.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) 2021 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.automaton
import net.akehurst.language.agl.runtime.structure.*
import net.akehurst.language.api.automaton.ParseAction
internal data class LookaheadSetPart(
val includesRT: Boolean,
val includesEOT: Boolean,
val matchANY: Boolean,
val content: Set
) {
companion object {
val EMPTY = LookaheadSetPart(false, false, false, emptySet())
val RT = LookaheadSetPart(true, false, false, emptySet())
val ANY = LookaheadSetPart(false, false, true, emptySet())
val EOT = LookaheadSetPart(false, true, false, emptySet())
fun createFromRuntimeRules(fullContent: Set): LookaheadSetPart {
val includeRT = fullContent.contains(RuntimeRuleSet.USE_RUNTIME_LOOKAHEAD)
val includeEOT = fullContent.contains(RuntimeRuleSet.END_OF_TEXT)
val matchAny = fullContent.contains(RuntimeRuleSet.ANY_LOOKAHEAD)
val content = fullContent.minus(RuntimeRuleSet.USE_RUNTIME_LOOKAHEAD).minus(RuntimeRuleSet.END_OF_TEXT).minus(RuntimeRuleSet.ANY_LOOKAHEAD)
return LookaheadSetPart(includeRT, includeEOT, matchAny, content)
}
fun Collection.unionAll() = this.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
}
val regex by lazy {
val str = this.content.joinToString(prefix = "(", separator = ")|(", postfix = ")") {
when (it.rhs) {
is RuntimeRuleRhsLiteral -> "\\Q${(it.rhs as RuntimeRuleRhsLiteral).literalUnescaped}\\E"
is RuntimeRuleRhsPattern -> (it.rhs as RuntimeRuleRhsPattern).patternUnescaped
else -> error("Internal Error: rhs not a literal that can be joined to a regex")
}
}
Regex(str)
}
val fullContent: Set
get() {
val cont = mutableSetOf()
if (this.includesRT) cont.add(RuntimeRuleSet.USE_RUNTIME_LOOKAHEAD)
if (this.includesEOT) cont.add(RuntimeRuleSet.END_OF_TEXT)
if (this.matchANY) cont.add(RuntimeRuleSet.ANY_LOOKAHEAD)
cont.addAll(this.content)
return cont
}
val isEmpty: Boolean get() = !this.includesRT && !this.includesEOT && !this.matchANY && this.content.isEmpty()
val isNotEmpty: Boolean get() = !this.isEmpty
fun resolve(eotLookahead: LookaheadSetPart, runtimeLookahead: LookaheadSetPart): LookaheadSetPart {
return when {
eotLookahead.includesRT -> error("EOT lookahead must be real lookahead values") //TODO: could remove this for speed, it should never happen
runtimeLookahead.includesRT -> error("EOT lookahead must be real lookahead values") //TODO: could remove this for speed, it should never happen
this.matchANY || (this.includesEOT && eotLookahead.matchANY) || (this.includesRT && runtimeLookahead.matchANY) -> LookaheadSetPart(false, false, true, emptySet())
else -> when {
this.includesEOT && this.includesRT -> {
val resolvedContent = this.content.union(runtimeLookahead.content).union(eotLookahead.content)
val eot = eotLookahead.includesEOT || runtimeLookahead.includesEOT
LookaheadSetPart(false, eot, false, resolvedContent)
}
this.includesEOT -> {
val resolvedContent = this.content.union(eotLookahead.content)
val eot = eotLookahead.includesEOT
LookaheadSetPart(false, eot, false, resolvedContent)
}
this.includesRT -> {
val resolvedContent = this.content.union(runtimeLookahead.content)
val eot = runtimeLookahead.includesEOT
LookaheadSetPart(false, eot, false, resolvedContent)
}
else -> {
LookaheadSetPart(false, false, false, this.content)
}
}
}
}
fun intersect(lookahead: LookaheadSetPart): LookaheadSetPart {
val rt = this.includesRT && lookahead.includesRT
val eot = this.includesEOT && lookahead.includesEOT
val ma = this.matchANY && lookahead.matchANY
return LookaheadSetPart(rt, eot, ma, this.content.intersect(lookahead.content))
}
fun union(lhs: LookaheadSetPart) = when {
this.matchANY -> ANY
lhs.matchANY -> ANY
else -> LookaheadSetPart(
this.includesRT || lhs.includesRT,
this.includesEOT || lhs.includesEOT,
false,
this.content.union(lhs.content)
)
}
fun unionContent(additionalContent: Set): LookaheadSetPart {
val rt = this.includesRT
val eot = this.includesEOT
val ma = this.matchANY
return LookaheadSetPart(rt, eot, ma, this.content.union(additionalContent))
}
fun containsAll(other: LookaheadSetPart): Boolean = when {
this.matchANY -> true
this.includesEOT.not() && other.includesEOT -> false
this.includesRT.not() && other.includesRT -> false
else -> this.fullContent.containsAll(other.fullContent)
}
override fun toString(): String = "LHS(${this.fullContent.sortedBy { it.tag }.joinToString { it.tag }})"
}
internal data class LookaheadInfoPart(
val guard: LookaheadSetPart,
val up: LookaheadSetPart
) {
companion object {
val EMPTY = LookaheadInfoPart(LookaheadSetPart.EMPTY, LookaheadSetPart.EMPTY)
fun merge(initial: Set): Set = merge2(initial)
fun merge1(initial: Set): Set {
return when (initial.size) {
1 -> initial
else -> {
val merged = initial
.groupBy { it.up }
.map { me2 ->
val up = me2.key
val guard = me2.value.map { it.guard }.reduce { acc, l -> acc.union(l) }
LookaheadInfoPart(guard, up)
}.toSet()
.groupBy { it.guard }
.map { me ->
val guard = me.key
val up = me.value.map { it.up }.reduce { acc, l -> acc.union(l) }
LookaheadInfoPart(guard, up)
}.toSet()
when (merged.size) {
1 -> merged
else -> {
val sortedMerged = merged.sortedByDescending { it.guard.fullContent.size }
val result = mutableSetOf()
val mergedIntoOther = mutableSetOf()
for (i in sortedMerged.indices) {
var lh1 = sortedMerged[i]
if (mergedIntoOther.contains(lh1)) {
//do nothing
} else {
for (j in i + 1 until sortedMerged.size) {
val lh2 = sortedMerged[j]
if (lh1.guard.containsAll(lh2.guard)) {
lh1 = LookaheadInfoPart(lh1.guard, lh1.up.union(lh2.up))
mergedIntoOther.add(lh2)
} else {
//result.add(lh2)
}
}
result.add(lh1)
}
}
result
}
}
}
}
}
fun merge2(initial: Set): Set {
var r = LookaheadInfoPart(LookaheadSetPart.EMPTY, LookaheadSetPart.EMPTY)
initial.forEach { lh ->
val g = r.guard.union(lh.guard)
val u = r.up.union(lh.up)
r = LookaheadInfoPart(g, u)
}
return setOf(r)
}
}
}
internal data class TransInfo(
val prevPrev: Set>,
val prev: Set>,
val action: ParseAction,
val to: Set,
val lookahead: Set
)
internal data class StateInfo(
val rulePositions: Set
) {
var possibleTrans: Set = emptySet()
val possiblePrev: Set> get() = possibleTrans.flatMap { it.prev }.toSet()
}
internal data class WidthInfo(
val action: ParseAction,
val to: RulePosition,
val lookaheadSet: LookaheadSetPart
)
internal data class HeightGraftInfo(
val action: ParseAction,
val parentNext: List, // to state
val lhs: Set
) {
override fun toString(): String {
val lhsStr = lhs.joinToString(separator = "|") { "[${it.guard.fullContent.joinToString { it.tag }}](${it.up.fullContent.joinToString { it.tag }})" }
return "HeightGraftInfo(action=$action, parentNext=$parentNext, lhs=$lhsStr)"
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy