All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.agl.automaton.BuildCacheLC1.kt Maven / Gradle / Ivy

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.agl.automaton.FirstOf
import net.akehurst.language.agl.automaton.LookaheadSetPart.Companion.unionAll
import net.akehurst.language.agl.runtime.structure.RulePosition
import net.akehurst.language.agl.runtime.structure.RuntimeRule
import net.akehurst.language.agl.util.Debug
import net.akehurst.language.api.automaton.ParseAction
import net.akehurst.language.collections.lazyMutableMapNonNull

internal class BuildCacheLC1(
    stateSet: ParserStateSet
) : BuildCacheAbstract(stateSet) {

    private companion object {
        class ClosureItemLC1(
            val parentItem: ClosureItemLC1?, //needed for height/graft
            val rulePosition: RulePosition,
            val next: RulePosition?,
            val lookaheadSet: LookaheadSetPart
        ) {
            val allPrev: Set by lazy { if (null == parentItem) mutableSetOf() else parentItem.allPrev + parentItem }

            val allRulePositionsButTop: List by lazy {
                if (null == parentItem) {
                    mutableListOf()
                } else {
                    parentItem.allRulePositionsButTop + rulePosition
                }
            }

            fun equivalentOf(other: ClosureItemLC1): Boolean {
                return this.rulePosition == other.rulePosition &&
                        this.lookaheadSet == other.lookaheadSet &&
                        this.parentItem?.lookaheadSet == other.parentItem?.lookaheadSet

            }

            private fun chain(): String {
                val p = if (null == parentItem) {
                    ""
                } else {
                    "${parentItem.chain()}->"
                }
                return "$p$rulePosition"
            }

            private val _hashCode = listOf(this.parentItem?.lookaheadSet, this.rulePosition, this.next, this.lookaheadSet).hashCode()
            override fun hashCode(): Int = _hashCode

            override fun equals(other: Any?): Boolean = when (other) {
                is ClosureItemLC1 -> other.rulePosition == this.rulePosition &&
                        other.next == this.next &&
                        other.lookaheadSet == this.lookaheadSet &&
                        other.parentItem?.lookaheadSet == this.parentItem?.lookaheadSet
                        && other.allPrev == this.allPrev

                else -> false
            }

            override fun toString(): String {
                return "${chain()}[${lookaheadSet.fullContent.joinToString { it.tag }}]"
            }
        }

        data class PossibleTransInfo(
            val prev: RulePosition,
            val parent: PossibleState?,
            val parentFirstOfNext: LookaheadSetPart,
            val action: ParseAction,
            val firstOf: LookaheadSetPart,
            val firstOfNext: LookaheadSetPart
        ) {
            val to: List
                get() = when (this.action) {
                    ParseAction.WIDTH, ParseAction.EMBED -> this.firstOf.fullContent.map { RulePosition(it, 0, RulePosition.END_OF_RULE) }
                    ParseAction.HEIGHT, ParseAction.GRAFT -> this.parent?.rulePosition?.next()?.toList() ?: emptyList()
                    ParseAction.GOAL -> listOf(prev.atEnd())
                }
        }

        class PossibleState(
            val firstOfCache: Map>,
            val rulePosition: RulePosition
        ) {
            val isAtStart: Boolean get() = this.rulePosition.isAtStart
            val isAtEnd: Boolean get() = this.rulePosition.isAtEnd
            val isGoalStart: Boolean get() = this.rulePosition.isGoal && this.isAtStart
            val isGoalEnd: Boolean get() = this.rulePosition.isGoal && this.isAtEnd

            val outTransInfo = mutableMapOf>()

            /*
                        val mergedTransInfo: Set by lazy {
                            val tis = this.outTransInfo.values.flatten().toSet()
                            val tisAtEnd = tis.filter { it.to.first().isAtEnd }
                            //TODO: need to split things at end!
                            val mergedAtEnd = tisAtEnd.map {
                                val lhs = when (it.action) {
                                    ParseAction.GOAL -> LookaheadSetPart.EOT
                                    ParseAction.WIDTH, ParseAction.EMBED -> {
                                        it.to.map { tgt ->
                                            if (tgt.rule == RuntimeRuleSet.USE_RUNTIME_LOOKAHEAD) {
                                                LookaheadSetPart.EMPTY
                                            } else {
                                                this.firstOfCache[tgt]!![this.rulePosition]!!
                                            }
                                        }.reduce { acc, l -> acc.union(l) }
                                    }

                                    ParseAction.HEIGHT, ParseAction.GRAFT -> it.firstOfNext
                                }
                                TransInfo(setOf(setOf(it.prevPrev)), setOf(setOf(it.prev)), it.action, it.to.toSet(), setOf(LookaheadInfoPart(lhs, LookaheadSetPart.EMPTY)))
                            }
                            val tisNotAtEnd = tis - tisAtEnd
                            val groupNotAtEnd = tisNotAtEnd.groupBy { Pair(it.action, it.to) }
                            val mergedNotAtEnd = groupNotAtEnd.map { me ->
                                val prev = me.value.map { it.prev.let { setOf(it) } }.toSet()
                                val parentFirstOfNext = me.value.map { tr ->
                                    //tr.parent?.rulePosition?.next()?.map { this.firstOfNext(tr.prev) } ?: emptyList()
                                    tr.parentFirstOfNext
                                }
                                val action = me.key.first
                                val to = me.key.second
                                val lookaheadSet = when (action) {
                                    ParseAction.GOAL -> LookaheadSetPart.EOT
                                    ParseAction.WIDTH, ParseAction.EMBED -> me.value.map { tr ->
                                        val p = when {
                                            this.isAtStart -> tr.prev ?: this.rulePosition
                                            else -> this.rulePosition
                                        }
                                        this.firstOfCache[tr.to.first()]!!.get(this.rulePosition)!!
                                    }.reduce { acc, it -> acc.union(it) }

                                    ParseAction.HEIGHT, ParseAction.GRAFT -> me.value.map { tr -> tr.firstOfNext }.reduce { acc, it -> acc.union(it) }
                                }
                                val lhInfo = parentFirstOfNext.map { LookaheadInfoPart(lookaheadSet, it) }.toSet()
                                TransInfo(prev, action, to.toSet(), lhInfo)
                            }.toSet()
                            mergedNotAtEnd + mergedAtEnd
                        }
            */

            val allPrev get() = outTransInfo.values.flatMap { it.map { it.prev } }.toSet().toList()

            fun setTransInfo(prev: RulePosition, parent: PossibleState?, parentFirstOfNext: LookaheadSetPart, firstOf: LookaheadSetPart, firstOfNext: LookaheadSetPart) {
                val action = when {
                    rulePosition.isGoal -> when {
                        rulePosition.isAtEnd -> ParseAction.GOAL    // RP(G,0,EOR)
                        rulePosition.isAtStart -> ParseAction.WIDTH // RP(G,0,SOR)
                        else -> error("should not happen")
                    }

                    this.rulePosition.isAtEnd -> when {
                        null == parent -> error("should not happen")
                        parent.isGoalStart -> ParseAction.GRAFT
                        parent.isAtStart -> ParseAction.HEIGHT
                        parent.isAtEnd -> error("should not happen")
                        else -> ParseAction.GRAFT
                    }

                    else -> ParseAction.WIDTH
                }
                var set = outTransInfo[prev]
                if (null == set) {
                    set = mutableSetOf()
                    outTransInfo[prev] = set
                }
                set.add(PossibleTransInfo(prev, parent, parentFirstOfNext, action, firstOf, firstOfNext))
            }

            fun firstOfNext(prev: RulePosition?): LookaheadSetPart = this.firstOfCache[this.rulePosition]!!.get(prev)!!

            override fun hashCode(): Int = this.rulePosition.hashCode()
            override fun equals(other: Any?): Boolean = when (other) {
                !is PossibleState -> false
                else -> this.rulePosition == other.rulePosition
            }

            override fun toString(): String = "${this.rulePosition}{${outTransInfo.entries.joinToString { "${it.key}" }}}"
        }

        val StateInfo.isAtEnd: Boolean get() = this.rulePositions.any { it.isAtEnd }
        val StateInfo.isGoal: Boolean get() = this.rulePositions.any { it.isGoal }

        /*        val StateInfo.mergedTransInfo: Set
                    get() {
                        val tis = this.possibleTrans
                        val groupedTis = tis.groupBy { Pair(it.action, it.to) }
                        val mergedTis = groupedTis.map { me ->
                            val prev = me.value.flatMap { it.prev }.toSet()
                            val action = me.key.first
                            val to = me.key.second
                            val lhInfo = me.value.flatMap { it.lookahead }.toSet()
                            TransInfo(prev, action, to, lhInfo)
                        }.toSet()
                        return mergedTis
                    }*/

        val RulePosition.canMergeState: Boolean get() = this.isAtEnd.not()// && this.next().all { it.isAtEnd.not() }
        val RulePosition.cannotMergeState: Boolean get() = this.isAtEnd //|| this.next().any { it.isAtEnd }

    }

    private val _calcClosureLR0 = mutableMapOf>()
    private val _closureItems = mutableMapOf, List>()


    private val _mergedStates = mutableMapOf()

    // Pair( listOf(RulePositions-of-previous-state), listOf(RuntimeRules-of-fromState) ) -> mapOf
    //    to-state-rule-positions -> HeightGraftInfo
    private val _heightOrGraftInto = mutableMapOf, List, List>, MutableMap, TransInfo>>()

    private val _allRulePositionsForStates: List
        get() = this.stateSet.usedNonTerminalRules
            .flatMap { it.rulePositionsNotAtStart } +
                this.stateSet.usedTerminalRules.map { it.asTerminalRulePosition }

    init {
        this._mergedStates[stateSet.startRulePosition] = StateInfo(setOf(stateSet.startRulePosition))
    }

    override fun clearAndOff() {
        //TODO
        _calcClosureLR0.clear()
        _closureItems.clear()
        _cacheOff = true
    }

    override fun mergedStateInfoFor(rulePositions: List): StateInfo {
        val sis = rulePositions.mapNotNull { _mergedStates[it] }.toSet()
        if (Debug.CHECK) check(1 == sis.size)
        return sis.first()
    }

    override fun stateInfo(): Set = this.stateInfo4()

    /*
        private fun mergeStates(unmerged: Map): Set {
            // merge states with transitions to the same (next) state with same action
            val statesAtEnd = unmerged.filter { it.key.isAtEnd || it.key.isGoal }
            val statesAtEndMapped = statesAtEnd.values.map { state ->
                val rulePositions = listOf(state.rulePosition)
                val possibleTrans = state.mergedTransInfo
                StateInfo(rulePositions, possibleTrans)
            }
            val statesNotAtEnd = unmerged.filter { it.key.isAtEnd.not() && it.key.isGoal.not() }
            val groupedByOutgoing = statesNotAtEnd.values.groupBy { it.mergedTransInfo.map { ti -> Pair(ti.action, ti.to) } }
            val mergedPossibleStates = groupedByOutgoing.map { me ->
                val rulePositions = me.value.map { it.rulePosition }
                val possibleTrans = me.value.flatMap { it.mergedTransInfo }.toSet()
                StateInfo(rulePositions, possibleTrans)
            }.union(statesAtEndMapped).associateBy { it.rulePositions }
            val updatedMergedStates = mergedPossibleStates.values.map { state ->
                val rulePositions = state.rulePositions
                val possibleTrans = state.possibleTrans.map { tr ->
                    val prev = tr.prev.map { p ->
                        when {
                            p.isEmpty() -> p
                            p.any { it.isAtStart } -> p
                            else -> mergedPossibleStates.keys.firstOrNull { it.containsAll(p) }?.toSet() ?: p
                        }
                    }.toSet()
                    val to = mergedPossibleStates.keys.firstOrNull { it.containsAll(tr.to) }?.toSet() ?: tr.to
                    TransInfo(prev, tr.action, to, tr.lookahead)
                }.toSet()
                StateInfo(rulePositions, possibleTrans)
            }

            var originalNumStates = unmerged.size
            var mergedNum = updatedMergedStates.size
            var updMergedStates = updatedMergedStates
            while (mergedNum != originalNumStates) {
                val atEnd = updMergedStates.filter { it.isAtEnd || it.isGoal }
                val nonAtEnd = updMergedStates.filter { it.isAtEnd.not() && it.isGoal.not() }
                val grpdByOutgoing = nonAtEnd.groupBy { it.mergedTransInfo.map { ti -> Pair(ti.action, ti.to) } }
                val mgdPossibleStates = grpdByOutgoing.map { me ->
                    val rulePositions = me.value.flatMap { it.rulePositions }
                    val possibleTrans = me.value.flatMap { it.mergedTransInfo }.toSet()
                    StateInfo(rulePositions, possibleTrans)
                }.union(atEnd).associateBy { it.rulePositions }
                updMergedStates = mgdPossibleStates.values.map { state ->
                    val rulePositions = state.rulePositions
                    val possibleTrans = state.possibleTrans.map { tr ->
                        val prev = tr.prev.map { p ->
                            when {
                                p.isEmpty() -> p
                                p.any { it.isAtStart } -> p
                                else -> mgdPossibleStates.keys.firstOrNull { it.containsAll(p) }?.toSet() ?: p
                            }
                        }.toSet()
                        val to = mgdPossibleStates.keys.firstOrNull { it.containsAll(tr.to) }?.toSet() ?: tr.to
                        TransInfo(prev, tr.action, to, tr.lookahead)
                    }.toSet()
                    StateInfo(rulePositions, possibleTrans)
                }
                originalNumStates = mergedNum
                mergedNum = updMergedStates.size
            }

            return updMergedStates.toSet()//mergedStateInfo
        }
    */
    /*
    internal fun stateInfo2(): Set {
        data class L1Trans(
            val parent: RulePosition?,
            val action: ParseAction,
            val to: RulePosition,
            val guard: LookaheadSetPart,
            val up: LookaheadSetPart
        )

        class L1State(
            var parent: L1State?,
            val rulePosition: RulePosition, // position in rule (no need for position 0)
            val followAtEnd: LookaheadSetPart, // terminals expected at the end of the rule (same for all RPs for this rule)
        ) {
            val prev: RulePosition = when {
                null == parent -> rulePosition // RP(G,0,0)
                parent!!.rulePosition.isAtStart -> parent!!.prev
                else -> parent!!.rulePosition
            }
            val prevState: L1State
                get() = when {
                    null == parent -> this // RP(G,0,0)
                    parent!!.rulePosition.isAtStart -> parent!!.prevState
                    else -> parent!!
                }
            private val parentNextNotAtEnd: Set
                get() = when (parent) {
                    null -> emptySet()
                    else -> parent!!.nextNotAtEnd
                }
            val nextNotAtEnd: Set
                get() = when {
                    rulePosition.isAtEnd -> parentNextNotAtEnd
                    else -> rulePosition.next().flatMap { nxRp ->
                        when {
                            nxRp.isAtEnd -> parentNextNotAtEnd
                            else -> listOf(nxRp)
                        }
                    }.toSet()
                }

            val parentFollowAtEnd = this.parent?.followAtEnd ?: LookaheadSetPart.EOT //parent is null for G & UP comes after (G,0,-1)
            val expectedAt = when {
                rulePosition.isAtEnd -> followAtEnd
                rulePosition.isGoal -> LookaheadSetPart.EOT // follow of (G,0,0) is UP
                else -> rulePosition.next().map { nx ->
                    when {
                        nx.isAtEnd -> followAtEnd
                        nx.isGoal -> LookaheadSetPart.EOT
                        else -> stateSet.firstOf.expectedAt(nx, followAtEnd)
                    }
                }.reduce { acc, l -> acc.union(l) }
            }

            fun outTransitions(parentOf: Map, Set>): Set {
                return when {
                    null == parent && rulePosition.isAtEnd -> emptySet() // G,0,EOR
                    rulePosition.isAtEnd -> {
                        val action = when {
                            parent!!.rulePosition.isGoal -> ParseAction.GOAL
                            parent!!.rulePosition.isAtStart -> ParseAction.HEIGHT
                            else -> ParseAction.GRAFT
                        }
                        val targets = parent!!.rulePosition.next()
                        val to = targets.map { tgt ->
                            // expectedAt(tgt) - follow(parent) if atEnd
                            val grd = stateSet.firstOf.expectedAt(tgt, parentFollowAtEnd)
                            val up = when (action) {
                                ParseAction.HEIGHT -> parentFollowAtEnd
                                ParseAction.EMBED,
                                ParseAction.WIDTH,
                                ParseAction.GRAFT,
                                ParseAction.GOAL -> LookaheadSetPart.EMPTY
                            }
                            Triple(tgt, grd, up)
                        }
                        to.map { p -> L1Trans(parent!!.rulePosition, action, p.first, p.second, p.third) }.toSet()
                    }

                    else -> {
                        val action = ParseAction.WIDTH
                        val tgts = pFirstTerm(this.rulePosition)
                        val to = tgts.flatMap { t ->
                            val pr = this.rulePosition
                            // tgt is an RP so we don;t have its follow,
                            // we can find parentOf(tgt) and follow(tgt)==follow(parentOf(tgt))
                            val tParent = parentOf[Pair(pr, t)]
                            val ls = tParent!!.map { tp -> tp.expectedAt }
                            ls.map { Pair(t.asTerminalRulePosition, it) }
                        }
                        val up = LookaheadSetPart.EMPTY
                        to.map { p -> L1Trans(parent?.rulePosition, action, p.first, p.second, up) }.toSet()
                    }
                }
            }

            private val id = arrayOf(parent?.rulePosition, prev, rulePosition, followAtEnd, parentFollowAtEnd)
            override fun hashCode(): Int = id.contentDeepHashCode()
            override fun equals(other: Any?): Boolean = when (other) {
                !is L1State -> false
                else -> this.id.contentDeepEquals(other.id)
            }

            override fun toString(): String = when (parent) {
                this -> "State{$rulePosition[$followAtEnd]}"
                else -> "State{$rulePosition[$followAtEnd]}-->$parent"
            }
        }

        data class L0L1Trans(
            val prev: Set>,
            val parent: Set,
            val to: Set,
            val action: ParseAction,
            val lookahead: Set
        )

        class L0State(
            val rulePosition: Set,
            val outTransitions: Set
        ) {
            override fun hashCode(): Int = rulePosition.hashCode()
            override fun equals(other: Any?): Boolean = when (other) {
                !is L0State -> false
                else -> this.rulePosition == other.rulePosition
            }

            override fun toString(): String = "State{$rulePosition}"
        }

        val startRP = this.stateSet.startRulePosition
        // G ends at G = S . but we have an implied UP after that, so followAtEnd of G is UP
        val startState = L1State(null, startRP, LookaheadSetPart.EOT)
        val finishRP = this.stateSet.finishRulePosition
        val finishState = L1State(null, finishRP, LookaheadSetPart.EOT)

        val parentOf = lazyMutableMapNonNull, MutableSet> { mutableSetOf() }
        val l1States = mutableSetOf(startState, finishState)
        val todo = mutableStackOf(startState)
        while (todo.isNotEmpty) {
            val state = todo.pop()
            val rp = state.rulePosition
            when {
                rp.isAtEnd -> l1States.add(state)
                else -> {
                    val rps = rp.items.flatMap { it.rulePositions }
                    for (childRP in rps) {
                        val childLhs = state.expectedAt
                        val childState = L1State(state, childRP, childLhs)
                        if (l1States.contains(childState).not()) {
                            l1States.add(childState)
                            val pr = childState.prev
                            parentOf[Pair(pr, childRP.rule)].add(state)
                            todo.push(childState)
                        } else {
                            // already done
                        }
                    }
                }
            }
        }

        if (Debug.OUTPUT_SM_BUILD) {
            println("LR1 states: ${l1States.size}")
            println("LR1 transitions: ${l1States.flatMap { it.outTransitions(parentOf) }.size}")
            for (state in l1States) {
                if (state.rulePosition.isGoal || state.rulePosition.isAtStart.not()) {
                    val trs = state.outTransitions(parentOf)
                    if (Debug.CHECK) check(trs.isNotEmpty() || state.rulePosition.isGoal) { "No outTransitions for $state" }
                    trs.forEach { tr ->
                        val prevStr = "{${state.prev}[${state.prevState.followAtEnd.fullContent.joinToString { it.tag }}]}"
                        val fromStr = "${state.rulePosition}[${state.followAtEnd.fullContent.joinToString { it.tag }}]"
                        val lh = "${tr.action}[${tr.guard.fullContent.joinToString { it.tag }}](${tr.up.fullContent.joinToString { it.tag }})"
                        println("$prevStr $fromStr -- $lh --> ${tr.to}")
                    }
                }
            }
        }

        val l0States = mutableMapOf()
        for (state in l1States) {
            if (state.rulePosition.isGoal || state.rulePosition.isAtStart.not()) {
                val trs = state.outTransitions(parentOf)
                val trans = trs.map { t ->
                    val parent = t.parent?.let { setOf(it) } ?: emptySet()
                    val action = t.action
                    val to = t.to
                    val grd = t.guard
                    val up = t.up
                    L0L1Trans(setOf(setOf(state.prev)), parent, setOf(to), action, setOf(LookaheadInfoPart(grd, up)))
                }.toSet()
                val groupTrans = trans.groupBy { tr -> Triple(tr.prev, tr.action, tr.to) }
                val mergeTrans = groupTrans.map { me ->
                    val prev = me.key.first
                    val action = me.key.second
                    val to = me.key.third
                    val parent = me.value.flatMap { it.parent }.toSet()
                    val lh = me.value.flatMap { it.lookahead }.toSet()
                    val mergedLh = LookaheadInfoPart.merge(lh)
                    L0L1Trans(prev, parent, to, action, mergedLh)
                }.toSet()
                val existing = l0States[state.rulePosition]
                if (null == existing) {
                    val st = L0State(setOf(state.rulePosition), mergeTrans)
                    l0States[state.rulePosition] = st
                } else {
                    val st = L0State(existing.rulePosition + setOf(state.rulePosition), existing.outTransitions + mergeTrans)
                    l0States[state.rulePosition] = st
                }
            }
        }

        if (Debug.OUTPUT_SM_BUILD) {
            println("")
            println("LR0 states")
            for (s in l0States.values) {
                for (t in s.outTransitions) {
                    println("${t.prev} $s -- ${t.action}${t.lookahead.joinToString { "[${it.guard}](${it.up})" }} --> ${t.to}")
                }
            }
        }

        val atEnd = l0States.values.filter { it.rulePosition.first().isAtEnd || it.rulePosition.first().isGoal }
        val notAtEnd = l0States.values.filter { it.rulePosition.first().isAtEnd.not() && it.rulePosition.first().isGoal.not() }

        val mergeAtEnd = atEnd.map { st ->
            val rp = st.rulePosition
            val trans = st.outTransitions
            val groupTrans = trans.groupBy { tr -> Triple(tr.prev, tr.action, tr.to) }
            val mergeTrans = groupTrans.map { me ->
                val prev = me.key.first
                val action = me.key.second
                val to = me.key.third
                val parent = me.value.flatMap { it.parent }.toSet()
                val lh = me.value.flatMap { it.lookahead }.toSet()
                val mergedLh = LookaheadInfoPart.merge(lh)
                L0L1Trans(prev, parent, to, action, mergedLh)
            }.toSet()
            L0State(rp, mergeTrans)
        }

        val mergeAtEnd = atEnd.map { st ->
            val rp = st.rulePosition
            val trans = st.outTransitions
            val groupTrans = trans.groupBy { tr -> Pair(tr.action, tr.to) }
            val mergeTrans = groupTrans.map { me ->
                val prev = me.value.flatMap { it.prev }.toSet()
                val action = me.key.first
                val to = me.key.second
                val parent = me.value.flatMap { it.parent }.toSet()
                val lh = me.value.flatMap { it.lookahead }.toSet()
                val mergedLh = LookaheadInfoPart.merge(lh)
                L0L1Trans(prev, parent, to, action, mergedLh)
            }.toSet()
            L0State(rp, mergeTrans)
        }

        val groupNotAtEnd = notAtEnd.groupBy { st ->
            st.outTransitions.map { tr -> Triple(tr.action, tr.to,tr.parent.map { it.runtimeRule }) }.toSet()
        }
        val mergeNotAtEnd = groupNotAtEnd.map {
            val rp = it.value.flatMap { it.rulePosition }.toSet()
            val trans = it.value.flatMap { it.outTransitions }.toSet()
            val groupTrans = trans.groupBy { tr -> Triple(tr.prev, tr.action, tr.to) }
            val mergeTrans = groupTrans.map { me ->
                val prev = me.key.first
                val action = me.key.second
                val to = me.key.third
                val parent = me.value.flatMap { it.parent }.toSet()
                val lhs = me.value.flatMap { it.lookahead }.toSet()
                    .groupBy { it.up }
                    .map {
                        val up = it.key
                        val guard = it.value.map { it.guard }.reduce { acc, l -> acc.union(l) }
                        L0L1Lookahead(guard, up)
                    }.toSet()
                L0L1Trans(prev, parent, to, action, lhs)
            }.toSet()
            L0State(rp, mergeTrans)
        }

        val mergeNotAtEnd = notAtEnd.map { st ->
            val rp = st.rulePosition
            val trans = st.outTransitions
            val groupTrans = trans.groupBy { tr -> Triple(tr.prev, tr.action, tr.to) }
            val mergeTrans = groupTrans.map { me ->
                val prev = me.key.first
                val action = me.key.second
                val to = me.key.third
                val parent = me.value.flatMap { it.parent }.toSet()
                val lh = me.value.flatMap { it.lookahead }.toSet()
                val mergedLh = LookaheadInfoPart.merge(lh)
                L0L1Trans(prev, parent, to, action, mergedLh)
            }.toSet()
            L0State(rp, mergeTrans)
        }
        val merged = mergeAtEnd + mergeNotAtEnd

        if (Debug.OUTPUT_SM_BUILD) {
            println("")
            println("merged LR0 states")
            for (s in merged) {
                for (t in s.outTransitions) {
                    println("${t.prev} $s -- ${t.action}${t.lookahead.joinToString { "[${it.guard}](${it.up})" }} --> ${t.to}")
                }
            }
        }

        val stateInfo = merged.map { st ->
            val rp = st.rulePosition//.toList()
            val trans = st.outTransitions.map { tr ->
                val prev = tr.prev.map { pr -> merged.first { it.rulePosition.containsAll(pr) }.rulePosition }.toSet()
                val action = tr.action
                val to = merged.first { it.rulePosition.containsAll(tr.to) }
                val lh = tr.lookahead.map { LookaheadInfoPart(it.guard, it.up) }.toSet()
                TransInfo(prev, action, to.rulePosition, lh)
            }.toSet()

            val grouped = trans.groupBy { tr -> Triple(tr.prev, tr.action, tr.to) }
            val merged2 = grouped.map{ me->
                val prev = me.key.first
                val action = me.key.second
                val to = me.key.third
                val parent = me.value.flatMap { it.parent }.toSet()
                val lhs = me.value.flatMap { it.lookahead }.toSet()
                    .groupBy { it.guard }
                    .map {
                        val guard = it.key
                        val up = it.value.map { it.up }.reduce { acc, l -> acc.union(l) }
                        LookaheadInfoPart(guard, up)
                    }.toSet()
                TransInfo(prev, parent, action, to, lhs)
            }.toSet()
//
            StateInfo(rp).also { it.possibleTrans = it.possibleTrans + trans }
        }.toSet()
        return stateInfo
    }
*/
    /*
        private fun stateInfo3(): Set {
            val stateRps = this.stateSet.usedNonTerminalRules.flatMap { it.rulePositionsNotAtStart } +
                    this.stateSet.usedTerminalRules.map { it.asTerminalRulePosition }
            val rulePosition = this.stateSet.startRulePosition
            val context = rulePosition
            val parentNextFollow = LookaheadSetPart.EOT
            val parentParentNextFollow = LookaheadSetPart.EOT
            firstFollowCache.processAllClosures(context, rulePosition, parentNextFollow)
            val stateInfo = mutableMapOf()
            val transInfoBySrc = mutableMapOf>()
            for (srcRp in stateRps) {
                var transInfo = emptySet()
                for (ctx in firstFollowCache.possibleContextsFor(srcRp)) {
                    val tis = when {
                        srcRp.isAtEnd -> {
                            val hgtis = mutableSetOf()
                            for (ctxCtx in firstFollowCache.possibleContextsFor(ctx)) {
                                val pns = this.firstFollowCache.parentInContext(ctxCtx, ctx, srcRp.rule)
                                val hgInfo = pns.map { parentNext ->
                                    val action = when {
                                        parentNext.rulePosition.isGoal -> ParseAction.GOAL
                                        parentNext.firstPosition -> ParseAction.HEIGHT
                                        else -> ParseAction.GRAFT
                                    }
                                    val tgt = parentNext.rulePosition
                                    val follow = parentNext.expectedAt
                                    val grd = follow
                                    val up = when (action) {
                                        ParseAction.HEIGHT -> parentNext.parentExpectedAt
                                        ParseAction.EMBED,
                                        ParseAction.WIDTH,
                                        ParseAction.GRAFT,
                                        ParseAction.GOAL -> LookaheadSetPart.EMPTY
                                    }
                                    TransInfo(setOf(setOf(ctx)), action, setOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                                    //HeightGraftInfo(action, listOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                                }.toSet()
                                val merged = mergeTransInfo(transInfo, hgInfo)
                                hgtis.addAll(merged)
                            }
                            transInfo = mergeTransInfo(transInfo, hgtis)
                        }

                        else -> {
                            val parentFollow = when {
                                srcRp.isGoal -> LookaheadSetPart.EOT
                                else -> {
                                    val ctxCtxs = this.firstFollowCache.possibleContextsFor(ctx)
                                    val x = ctxCtxs.flatMap { cc ->
                                        this.firstFollowCache.parentInContext(cc, ctx, srcRp.rule)
                                    }.toSet()
                                    x.map { it.expectedAt }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
                                }
                            }
                            val ftis = this.firstFollowCache.firstTerminalInContext(ctx, srcRp, parentFollow) //emptySet(),  parentFollow)
                            val wis = ftis.map { firstTermInfo ->
                                val action = when {
                                    firstTermInfo.terminalRule.isEmbedded -> ParseAction.EMBED
                                    else -> ParseAction.WIDTH
                                }
                                val trp = firstTermInfo.terminalRule.asTerminalRulePosition
                                val lhs = firstTermInfo.parentExpectedAt
                                TransInfo(setOf(setOf(ctx)), action, setOf(trp), setOf(LookaheadInfoPart(lhs, LookaheadSetPart.EMPTY)))
                                //WidthInfo(action, trp, lhs)
                            }
                            transInfo = mergeTransInfo(transInfo, wis.toSet())
                        }
                    }
                }
                val mergedTrans = mergeTransInfo(transInfoBySrc[srcRp], transInfo)
                transInfoBySrc[srcRp] = mergedTrans

                //transInfoBySrc[srcRp].addAll(transInfo)
                transInfo.forEach { ti ->
                    val si = StateInfo(ti.to)
                    ti.to.forEach {
                        val existing = stateInfo[it]
                        when {
                            (null == existing) -> stateInfo[it] = si
                            existing.rulePositions == si.rulePositions -> Unit //OK same state
                            else -> {
                                val mergedState = StateInfo(existing.rulePositions + si.rulePositions)
                                mergedState.possibleTrans = mergeTransInfo(existing.possibleTrans, si.possibleTrans)
                                mergedState.rulePositions.forEach {
                                    stateInfo[it] = mergedState
                                }
                            }
                        }
                    }
                }
            }
            stateInfo[rulePosition] = StateInfo(setOf(rulePosition))
            for ((srcRp, outTrans) in transInfoBySrc) {
                stateInfo[srcRp]!!.possibleTrans = outTrans
            }

            val transInfoBySrc2 = mutableMapOf>()
            val stateInfo2 = mutableMapOf()
            for ((srcRp, outTrans) in transInfoBySrc) {
                val srcStateInfo = stateInfo[srcRp]!!
                val mergedTrans = mergeTransInfo(srcStateInfo.possibleTrans, outTrans)
                transInfoBySrc2[srcRp] = mergedTrans
                srcStateInfo.possibleTrans = mergedTrans
                mergedTrans.forEach { ti ->
                    val si = StateInfo(ti.to)
                    ti.to.forEach {
                        val existing = stateInfo2[it]
                        when {
                            (null == existing) -> stateInfo2[it] = si
                            existing.rulePositions == si.rulePositions -> Unit //OK same state
                            else -> {
                                val mergedState = StateInfo(existing.rulePositions + si.rulePositions)
                                mergedState.rulePositions.forEach {
                                    stateInfo2[it] = mergedState
                                }
                            }
                        }
                    }
                }
            }

            stateInfo2[rulePosition] = StateInfo(setOf(rulePosition))
            for ((srcRp, outTrans) in transInfoBySrc) {
                stateInfo2[srcRp]!!.possibleTrans = outTrans
            }
            return stateInfo2.values.toSet()
        }
    */

    private fun stateInfo4(): Set {
        val startRulePosition = this.stateSet.startRulePosition
        val context = startRulePosition
        val parentNextFollow = LookaheadSetPart.EOT
        firstFollowCache.processAllClosures(context, startRulePosition, parentNextFollow)

        val mergedStateInfos = calcStateInfos()
        for (stateInfo in mergedStateInfos) {
            val transInfo = mutableSetOf()
            for (srcRp in stateInfo.rulePositions) {
                this._mergedStates[srcRp] = stateInfo
                val ti = when {
                    srcRp.isAtEnd -> calcTransInfoForComplete(srcRp)
                    else -> calcTransInfoForIncomplete(srcRp)
                }
                transInfo.addAll(ti)
            }
            val merged = mergeTransInfo(transInfo, emptySet())
            stateInfo.possibleTrans = merged
        }
        //val mergedStatesByTransition = mergeStatesByTransition(mergedStateInfos)
        return mergedStateInfos
    }

    //private fun mergeStates(rulePositions: Iterable): Set = mergeStates1(rulePositions)
    private fun mergeStates(rulePositions: Iterable): Set = noMergeStates(rulePositions)

    private fun noMergeStates(rulePositions: Iterable): Set {
        return rulePositions.map { StateInfo(setOf(it)) }.toSet()
    }

    private fun mergeStates1(rulePositions: Iterable): Set {
        val stateRpBefore = rulePositions.flatMap { s -> s.next().map { n -> Pair(n, s) } }.toSet()
        val before = lazyMutableMapNonNull> { mutableSetOf() }
        stateRpBefore.forEach { before[it.first].add(it.second) }

        val stateRpsCanMerge = rulePositions.filter { it.canMergeState }
        val stateRpsNotToMerge = rulePositions.filter { it.cannotMergeState }
        val groupedStateRpsNotAtEnd = stateRpsCanMerge.groupBy { srcRp ->
            Pair(before[srcRp].flatMap { it.items }, srcRp.items)
        }
        val mergedSateInfoNotAtEnd = groupedStateRpsNotAtEnd.flatMap { me ->
            when {
                //me.key.second.isEmpty() -> me.value.map { StateInfo(setOf(it)) }
                else -> listOf(StateInfo(me.value.toSet()))
            }
        }
        val stateInfoAtEnd = stateRpsNotToMerge.map { StateInfo(setOf(it)) }
        return mergedSateInfoNotAtEnd.toSet() + stateInfoAtEnd.toSet()
    }

    private fun mergeStates2(rulePositions: Iterable): Set {
        val stateRpBefore = rulePositions.flatMap { rp -> rp.next().map { n -> Pair(rp, n) } }.toSet()
        val before = lazyMutableMapNonNull> { mutableSetOf() }
        stateRpBefore.forEach { before[it.second].add(it.first) }

        val stateRpsCanMerge = rulePositions.filter { it.canMergeState }
        val stateRpsNotToMerge = rulePositions.filter { it.cannotMergeState }
        val expectedAt = mutableMapOf()
        val expectedAtInv = lazyMutableMapNonNull>() { mutableSetOf() }
        for (rp in stateRpsCanMerge) {
            val ea = FirstOf().expectedAt(rp, LookaheadSetPart.RT)
            expectedAt[rp] = ea
            expectedAtInv[ea].add(rp)
        }
        for (k1 in expectedAt.values) {
            for (k2 in expectedAt.values) {
                when {
                    (k1 === k2) -> Unit
                    k1.containsAll(k2) -> {
                        expectedAtInv[k1].addAll(expectedAtInv[k2])
                    }
                }
            }
        }
        val pairs = expectedAtInv.entries.flatMap { me ->
            val ea = me.key
            me.value.map {
                val x = before[it].map { expectedAt[it]!! }.unionAll()
                Pair(x, ea)
            }
        }.toSet()

        val groupedStateRpsCanMerge = stateRpsCanMerge.groupBy { srcRp ->
            val y = expectedAt[srcRp]
            val x = before[srcRp].map { expectedAt[it]!! }.unionAll()
            Pair(x, y)
        }
        val mergedSateInfoCanMerge = groupedStateRpsCanMerge.flatMap { me ->
            when {
                //me.key.second.isEmpty() -> me.value.map { StateInfo(setOf(it)) }
                else -> listOf(StateInfo(me.value.toSet()))
            }
        }
        val stateInfoNotMerged = stateRpsNotToMerge.map { StateInfo(setOf(it)) }
        return mergedSateInfoCanMerge.toSet() + stateInfoNotMerged.toSet()
    }

    private fun calcStateInfos(): Set {
        val stateRps = this._allRulePositionsForStates
        val merged = mergeStates(stateRps)
        return merged
    }

    private fun calcTransInfoForComplete(srcRp: RulePosition): Set {
        if (Debug.CHECK) check(srcRp.isAtEnd)
        val transInfo = mutableSetOf()
        val contexts = firstFollowCache.possibleContextsFor(srcRp)
        for (ctx in contexts) {
            val hgtis = mutableSetOf()
            val contextContexts = firstFollowCache.possibleContextsFor(ctx)
            for (ctxCtx in contextContexts) {
                val pns = this.firstFollowCache.parentInContext(ctxCtx, ctx, srcRp.rule)
                val hgInfo = pns.map { parentNext ->
                    val action = when {
                        parentNext.rulePosition.isGoal -> ParseAction.GOAL
                        parentNext.firstPosition -> ParseAction.HEIGHT
                        else -> ParseAction.GRAFT
                    }
                    val tgt = parentNext.rulePosition
                    val follow = parentNext.expectedAt
                    val grd = follow
                    val up = when (action) {
                        ParseAction.HEIGHT -> parentNext.parentExpectedAt
                        ParseAction.EMBED,
                        ParseAction.WIDTH,
                        ParseAction.GRAFT,
                        ParseAction.GOAL -> LookaheadSetPart.EMPTY
                    }
                    TransInfo(setOf(setOf(ctxCtx)), setOf(setOf(ctx)), action, setOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                    //HeightGraftInfo(action, listOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                }.toSet()
                hgtis.addAll(hgInfo)
            }
            transInfo.addAll(hgtis)
        }
        val mergedTransInfo = mergeTransInfo(transInfo, emptySet())
        return mergedTransInfo
    }

    private fun calcTransInfoForIncomplete(srcRp: RulePosition): Set {
        if (Debug.CHECK) check(srcRp.isAtEnd.not())
        val transInfo = mutableSetOf()
        val contexts = firstFollowCache.possibleContextsFor(srcRp)
        for (ctx in contexts) {
            val parentFollow = when {
                srcRp.isGoal -> LookaheadSetPart.EOT
                else -> {
                    val ctxCtxs = this.firstFollowCache.possibleContextsFor(ctx)
                    val x = ctxCtxs.flatMap { cc ->
                        this.firstFollowCache.parentInContext(cc, ctx, srcRp.rule)
                    }.toSet()
                    x.map { it.expectedAt }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
                }
            }
            val ftis = this.firstFollowCache.firstTerminalInContext(ctx, srcRp, parentFollow) //emptySet(),  parentFollow)
            val wis = ftis.map { firstTermInfo ->
                val action = when {
                    firstTermInfo.terminalRule.isEmbedded -> ParseAction.EMBED
                    else -> ParseAction.WIDTH
                }
                val trp = firstTermInfo.terminalRule.asTerminalRulePosition
                val lhs = firstTermInfo.parentExpectedAt
                TransInfo(setOf(emptySet()), setOf(setOf(ctx)), action, setOf(trp), setOf(LookaheadInfoPart(lhs, LookaheadSetPart.EMPTY)))
            }
            transInfo.addAll(wis.toSet())
        }
        val mergedTransInfo = mergeTransInfo(transInfo, emptySet())
        return mergedTransInfo
    }

    private fun mergeStatesByTransition(states: Set): Set {
        val statesByRp = mutableMapOf()
        for (si in states) {
            for (rp in si.rulePositions) {
                statesByRp[rp] = si
            }
        }
        for (si in states) {
            when {
                si.rulePositions.first().isAtEnd -> statesByRp[si.rulePositions.first()] = si
                si.possibleTrans.isEmpty() -> statesByRp[si.rulePositions.first()] = si
                else -> {
                    for (ti in si.possibleTrans) {
                        for (rp in ti.to) {
                            val existing = statesByRp[rp]
                            when {
                                (null == existing) -> error("??")
                                existing.rulePositions == si.rulePositions -> Unit //OK same state
                                else -> {
                                    val mergedState = StateInfo(existing.rulePositions + si.rulePositions)
                                    mergedState.rulePositions.forEach {
                                        statesByRp[it] = mergedState
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return statesByRp.values.toSet()
    }

    private fun mergeTransInfo(ti1: Set?, ti2: Set): Set {
        val total = if (null == ti1) ti2 else ti1 + ti2
        val embed = mutableSetOf()
        val width = mutableSetOf()
        val heightComplete = mutableSetOf()
        val graftComplete = mutableSetOf()
        val heightIncomplete = mutableSetOf()
        val graftIncomplete = mutableSetOf()
        val goals = mutableSetOf()

        for (ti in total) {
            when (ti.action) {
                ParseAction.GOAL -> goals.add(ti)
                ParseAction.EMBED -> embed.add(ti)
                ParseAction.WIDTH -> width.add(ti)
                ParseAction.GRAFT -> when {
                    ti.to.first().isAtEnd -> graftComplete.add(ti)
                    else -> graftIncomplete.add(ti)
                }

                ParseAction.HEIGHT -> when {
                    ti.to.first().isAtEnd -> heightComplete.add(ti)
                    else -> heightIncomplete.add(ti)
                }

            }
        }

        val mw = mergeWidth(width)
        val mhc = mergeHeightComplete(heightComplete)
        val mhi = mergeHeightIncomplete(heightIncomplete)
        val mgc = mergeGraftComplete(graftComplete)
        val mgi = mergeGraftIncomplete(graftIncomplete)
        val res = mw + mhc + mhi + mgc + mgi + goals + embed
        return res
    }

    private fun mergeWidth(transInfo: Set): Set {
        return when {
            transInfo.isEmpty() -> transInfo
            else -> {
                val grouped = transInfo.groupBy { it.to }
                val merged = grouped.map { me ->
                    val prevPrev = me.value.flatMap { it.prevPrev }.toSet()
                    val prev = me.value.flatMap { it.prev }.toSet()
                    val action = ParseAction.WIDTH
                    val to = me.value.flatMap { it.to }.toSet()
                    val grd = me.value.flatMap { it.lookahead.map { it.guard } }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
                    val lhs = setOf(LookaheadInfoPart(grd, LookaheadSetPart.EMPTY))
                    TransInfo(prevPrev, prev, action, to, lhs)
                }.toSet()
                merged
            }
        }
    }

    private fun mergeHeightComplete(transInfo: Set): Set {
        return when {
            transInfo.isEmpty() -> transInfo
            else -> {
                val grouped = transInfo.groupBy { it.to }
                val merged = grouped.map { me ->
                    val prevPrev = me.value.flatMap { it.prevPrev }.toSet()
                    val prev = me.value.flatMap { it.prev }.toSet()
                    val action = ParseAction.HEIGHT
                    val to = me.key
                    val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lookahead }.toSet())
                    TransInfo(prevPrev, prev, action, to, lhs)
                }.toSet()
                merged
            }
        }
    }

    private fun mergeHeightIncomplete(transInfo: Set): Set {
        return when {
            transInfo.isEmpty() -> transInfo
            else -> {
                //val grouped = transInfo.groupBy { Pair(it.to, it.lookahead) }
                val grouped = transInfo.groupBy { it.to }
                val merged = grouped.map { me ->
                    val prevPrev = me.value.flatMap { it.prevPrev }.toSet()
                    val prev = me.value.flatMap { it.prev }.toSet()
                    val action = ParseAction.HEIGHT
                    val to = me.key
                    //val lhs = me.key.second
                    val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lookahead }.toSet())
                    TransInfo(prevPrev, prev, action, to, lhs)
                }.toSet()
                merged
            }
        }
    }

    private fun mergeGraftComplete(transInfo: Set): Set {
        return when {
            transInfo.isEmpty() -> transInfo
            else -> {
                val grouped = transInfo.groupBy { it.to }
                val merged = grouped.map { me ->
                    val prevPrev = me.value.flatMap { it.prevPrev }.toSet()
                    val prev = me.value.flatMap { it.prev }.toSet()
                    val action = ParseAction.GRAFT
                    val to = me.key
                    val grd = me.value.flatMap { it.lookahead.map { it.guard } }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
                    val lhs = setOf(LookaheadInfoPart(grd, LookaheadSetPart.EMPTY))
                    TransInfo(prevPrev, prev, action, to, lhs)
                }.toSet()
                merged
            }
        }
    }

    private fun mergeGraftIncomplete(transInfo: Set): Set {
        return when {
            transInfo.isEmpty() -> transInfo
            else -> {
                val grouped = transInfo.groupBy { it.to }
                val merged = grouped.map { me ->
                    val prevPrev = me.value.flatMap { it.prevPrev }.toSet()
                    val prev = me.value.flatMap { it.prev }.toSet()
                    val action = ParseAction.GRAFT
                    val to = me.key
                    val grd = me.value.flatMap { it.lookahead.map { it.guard } }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
                    val lhs = setOf(LookaheadInfoPart(grd, LookaheadSetPart.EMPTY))
                    TransInfo(prevPrev, prev, action, to, lhs)
                }.toSet()
                merged
            }
        }
    }

    override fun widthInto(prevState: ParserState, fromState: ParserState): Set {
        // the 'to' state is the first Terminal the fromState.rulePosition
        // if there are multiple fromState.rulePositions then they should have same firstOf or they would not be merged.
        // after a WIDTH, fromState becomes the prevState, therefore
        // the lookahead is the firstOf the parent.next of the 'to' state, in the context of the fromStateRulePositions
        if (Debug.OUTPUT_SM_BUILD) Debug.debug(Debug.IndentDelta.INC_AFTER) { "START calcWidthInfo($prevState, $fromState) - ${fromState.rulePositions.map { it.rule.tag }}" }
        this.firstFollowCache.clear()
        //FirstFollow3
        val firstTerminals = prevState.rulePositions.flatMap { prev ->
            fromState.rulePositions.flatMap { from ->
                //TODO: can we do better thn parentFollow == RT here ?
                val parentFollow = when {
                    fromState.isGoal -> LookaheadSetPart.EOT
                    else -> LookaheadSetPart.RT
                }
                this.firstFollowCache.firstTerminalInContext(prev, from, parentFollow) //emptySet(),  parentFollow)
            }
        }.toSet()
        val wis = firstTerminals.map { firstTermInfo ->
            val action = when {
                firstTermInfo.terminalRule.isEmbedded -> ParseAction.EMBED
                else -> ParseAction.WIDTH
            }
            val rp = firstTermInfo.terminalRule.asTerminalRulePosition
            val lhs = firstTermInfo.parentExpectedAt
            WidthInfo(action, rp, lhs)
        }
        val wisMerged = wis.groupBy { Pair(it.to, it.action) }
            .map { me ->
                val rp = me.key.first
                val action = me.key.second
                val lhs = me.value.map { it.lookaheadSet }.reduce { a, e -> a.union(e) }
                WidthInfo(action, rp, lhs)
            }
        if (Debug.OUTPUT_SM_BUILD) Debug.debug(Debug.IndentDelta.DEC_BEFORE) { "FINISH calcWidthInfo($prevState, $fromState)" }
        wisMerged.forEach { wi ->
            this._mergedStates[wi.to] = StateInfo(setOf(wi.to))
        }
        return wisMerged.toSet()
    }

    override fun heightOrGraftInto(prevPrev: ParserState, prevState: ParserState, fromState: ParserState): Set {
        val calc = calcAndCacheHeightOrGraftInto(prevPrev, prevState, fromState)//, upCls)
        return calc
    }

    private fun calcAndCacheHeightOrGraftInto(
        prevPrev: ParserState,
        prev: ParserState,
        from: ParserState
    ): Set {//, upCls: Set): Set {
        val hgi = calcHeightOrGraftInto(prevPrev, prev, from)//, upCls)
        cacheHeightOrGraftInto(prevPrev, prev, from, hgi)
        return hgi
    }

    private fun cacheHeightOrGraftInto(prevPrev: ParserState, prev: ParserState, from: ParserState, hgis: Set) {
        val key = Triple(prevPrev.rulePositions, prev.rulePositions, from.runtimeRules)
        val map = this._heightOrGraftInto[key] ?: run {
            val x = mutableMapOf, TransInfo>()
            this._heightOrGraftInto[key] = x
            x
        }
        for (hg in hgis) {
            val existing = map[hg.to]
            if (null == existing) {
                map[hg.to] = hg
            } else {
                val lhs = hg.lookahead.union(existing.lookahead)
                map[hg.to] = TransInfo(existing.prevPrev, existing.prev, hg.action, hg.to, lhs)
            }
        }
    }

    //for graft, previous must match prevGuard, for height must not match
    private fun calcHeightOrGraftInto(prevPrev: ParserState, prev: ParserState, from: ParserState): Set {//, upCls: Set): Set {
        //FirstFollow3
        val rls = mutableSetOf()
        val hgInfo = prevPrev.rulePositions.flatMap { contextContext ->
            prev.rulePositions.flatMap { context ->
                val parentsOfFrom = from.runtimeRules.flatMap { fr ->
                    this.firstFollowCache.parentInContext(contextContext, context, fr)
                }.toSet()
                parentsOfFrom.map { parentNext ->
                    val action = when {
                        parentNext.rulePosition.isGoal -> ParseAction.GOAL
                        parentNext.firstPosition -> ParseAction.HEIGHT
                        else -> ParseAction.GRAFT
                    }
                    val tgt = parentNext.rulePosition
                    val grd = parentNext.expectedAt
                    val up = parentNext.parentExpectedAt
                    rls.add(tgt.rule)
                    TransInfo(setOf(setOf(contextContext)), setOf(setOf(context)), action, setOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                    //HeightGraftInfo(action, listOf(tgt), setOf(LookaheadInfoPart(grd, up)))
                }
            }
        }.toSet()
        val merged = mergeTransInfo(hgInfo, emptySet())

        //val rpsNotMerge = rps.filter { it.cannotMergeState }
        val rps = rls.flatMap { it.rulePositionsNotAtStart }
        val mergedSateInfoNotAtEnd = mergeStates(rps)
        mergedSateInfoNotAtEnd.forEach { si ->
            si.rulePositions.forEach {
                this._mergedStates[it] = si
            }
        }
        //rpsNotMerge.forEach { this._mergedStates[it] = StateInfo(setOf(it)) }
        return merged
    }

    private fun mergeHeightGraft(hgInfo: Set) = mergeHeightGraft1(hgInfo)

    private fun mergeHeightGraft1(hgInfo: Set): Set {
        val infoAtEnd = hgInfo.filter { it.parentNext.first().isAtEnd }
        val infoNotAtEnd = hgInfo.filter { it.parentNext.first().isAtEnd.not() }
        val infoAtEndMerged = infoAtEnd.groupBy { Pair(it.action, it.parentNext) }
            .map { me ->
                val action = me.key.first
                val parentNext = me.key.second
                //val lhs = me.value.map { it.lhs }.toSet().reduce { acc, e -> acc.union(e) }
                val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lhs }.toSet())
                //val upLhs = me.value.flatMap { it.upLhs }.toSet().fold(setOf()) { acc, e -> if (acc.any { it.containsAll(e) }) acc else acc + e }
                HeightGraftInfo(action, parentNext, lhs)
            }
        val infoToMerge = infoNotAtEnd.groupBy { Pair(it.action, it.parentNext) }
        val mergedInfo = infoToMerge.map { me ->
            val action = me.key.first
            val parentNext = me.key.second
            //val lhs = me.value.map { it.lhs }.toSet().reduce { acc, e -> acc.union(e) }
            val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lhs }.toSet())
            //val upLhs = me.value.flatMap { it.upLhs }.toSet().fold(setOf()) { acc, e -> if (acc.any { it.containsAll(e) }) acc else acc + e }
            HeightGraftInfo(action, parentNext, lhs)
        }.toSet()
        val r = (infoAtEndMerged + mergedInfo).toSet()
        return r
    }

    private fun mergeHeightGraft2(hgInfo: Set): Set {
        val infoAtEnd = hgInfo.filter { it.parentNext.first().isAtEnd }
        val infoNotAtEnd = hgInfo.filter { it.parentNext.first().isAtEnd.not() }
        val infoAtEndMerged = infoAtEnd.groupBy { Pair(it.action, it.parentNext) }
            .map { me ->
                val action = me.key.first
                val parentNext = me.key.second
                //val lhs = me.value.map { it.lhs }.toSet().reduce { acc, e -> acc.union(e) }
                val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lhs }.toSet())
                //val upLhs = me.value.flatMap { it.upLhs }.toSet().fold(setOf()) { acc, e -> if (acc.any { it.containsAll(e) }) acc else acc + e }
                HeightGraftInfo(action, parentNext, lhs)
            }
        val infoNotAtEndHeight = infoNotAtEnd.filter { it.action == ParseAction.HEIGHT }
        val infoNotAtEndGraft = infoNotAtEnd.filter { it.action == ParseAction.GRAFT }
        val infoNotAtEndHeightGrouped = infoNotAtEndHeight.groupBy { it.parentNext }
        val infoNotAtEndGraftGrouped = infoNotAtEndGraft.groupBy { it.lhs }
        val mergedHeightInfo = infoNotAtEndHeightGrouped.map { me ->
            val action = ParseAction.HEIGHT
            val parentNext = me.key
            val lhs = LookaheadInfoPart.merge(me.value.flatMap { it.lhs }.toSet())
            HeightGraftInfo(action, parentNext, lhs)
        }.toSet()
        val mergedGraftInfo = infoNotAtEndGraftGrouped.map { me ->
            val action = ParseAction.GRAFT
            val grd = me.value.flatMap { it.lhs.map { it.guard } }.fold(LookaheadSetPart.EMPTY) { acc, it -> acc.union(it) }
            val lhs = setOf(LookaheadInfoPart(grd, LookaheadSetPart.EMPTY))
            val parentNext = me.value.flatMap { it.parentNext }.toSet().toList()
            HeightGraftInfo(action, parentNext, lhs)
        }.toSet()
        val r = (infoAtEndMerged + mergedHeightInfo + mergedGraftInfo).toSet()
        return r
    }

    private fun pFirstTerm(rp: RulePosition, done: MutableSet = mutableSetOf()): Set {
        return if (done.contains(rp)) {
            emptySet()
        } else {
            when {
                rp.isTerminal -> setOf(rp.rule as RuntimeRule)
                //rp.item!!.isTerminal -> rp.items
                else -> {
                    done.add(rp)
                    rp.items.flatMap { it.rulePositionsAtStart.flatMap { pFirstTerm(it, done) } }.toSet()
                    //rp.item!!.rulePositionsAt[0].flatMap { pFirstTerm(it, done) }.toSet()
                }
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy