packages feed

ptera-core-0.1.0.0: src/Language/Parser/Ptera/Machine/SRB/Builder.hs

module Language.Parser.Ptera.Machine.SRB.Builder where

import           Language.Parser.Ptera.Prelude

import qualified Data.EnumMap.Strict                        as EnumMap
import qualified Language.Parser.Ptera.Data.Alignable       as Alignable
import qualified Language.Parser.Ptera.Data.Alignable.Array as AlignableArray
import qualified Language.Parser.Ptera.Data.Alignable.Map   as AlignableMap
import qualified Language.Parser.Ptera.Machine.LAPEG        as LAPEG
import qualified Language.Parser.Ptera.Machine.PEG          as PEG
import qualified Language.Parser.Ptera.Machine.SRB          as SRB


type T start a = BuilderT start a

type BuilderT start a = StateT (Context start a)

data Context start a = Context
    {
        ctxInitials     :: EnumMap.EnumMap start SRB.StateNum,
        ctxNextStateNum :: SRB.StateNum,
        ctxStates       :: AlignableMap.T SRB.StateNum SRB.MState
    }
    deriving (Eq, Show)

type Vars varDoc = AlignableArray.T LAPEG.VarNum (PEG.Var varDoc)
type Alts altDoc a = AlignableArray.T LAPEG.AltNum (LAPEG.Alt altDoc a)

build :: Monad m
    => Vars varDoc -> Alts altDoc a -> BuilderT start a m ()
    -> m (SRB.T start varDoc altDoc a)
build vars alts builder = do
    finalCtx <- execStateT builder initialCtx
    pure do
        SRB.SRB
            { initials = ctxInitials finalCtx
            , states = AlignableArray.fromTotalMap
                do ctxNextStateNum finalCtx
                do ctxStates finalCtx
            , alts = alts
            , vars = vars
            }
    where
        initialCtx = Context
            {
                ctxInitials = EnumMap.empty,
                ctxNextStateNum = Alignable.initialAlign,
                ctxStates = AlignableMap.empty
            }

genNewStateNum :: Monad m => BuilderT start a m SRB.StateNum
genNewStateNum = do
    ctx <- get
    let sn = ctxNextStateNum ctx
    put do ctx { ctxNextStateNum = Alignable.nextAlign sn }
    pure sn

registerInitial :: Monad m => Enum start
    => start -> SRB.StateNum -> BuilderT start a m ()
registerInitial i v = modify' \ctx -> ctx
    {
        ctxInitials = EnumMap.insert i v do ctxInitials ctx
    }

addState :: Monad m => SRB.MState -> BuilderT s a m ()
addState s = modify' \ctx -> ctx
    {
        ctxStates = AlignableMap.insert
            do SRB.stateNum s
            do s
            do ctxStates ctx
    }