module Language.Parser.Ptera.Syntax.Grammar (
    T,

    GrammarT,
    Context (..),
    fixGrammarT,
    FixedGrammar (..),

    Action (..),
    RuleExpr (..),
    Alt (..),
    Expr,
    Unit (..),

    initialT,
    ruleT,
) where

import           Language.Parser.Ptera.Prelude

import qualified Data.EnumMap.Strict           as EnumMap
import qualified Language.Parser.Ptera.Data.HFList as HFList


type T start nonTerminal terminal elem varDoc altDoc action =
    GrammarT start nonTerminal terminal elem varDoc altDoc action

type GrammarT start nonTerminal terminal elem varDoc altDoc action =
    StateT (Context start nonTerminal terminal elem varDoc altDoc action)

data Context start nonTerminal terminal elem varDoc altDoc action = Context
    { Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
ctxStarts :: EnumMap.EnumMap start nonTerminal
    , Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules  :: EnumMap.EnumMap nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
    , Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
ctxDisplayNonTerminals :: EnumMap.EnumMap nonTerminal varDoc
    }

fixGrammarT :: Monad m
    => GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
    -> m (FixedGrammar start nonTerminal terminal elem varDoc altDoc action)
fixGrammarT :: GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
-> m (FixedGrammar
        start nonTerminal terminal elem varDoc altDoc action)
fixGrammarT GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
builder = do
        Context start nonTerminal terminal elem varDoc altDoc action
finalCtx <- GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
-> Context start nonTerminal terminal elem varDoc altDoc action
-> m (Context start nonTerminal terminal elem varDoc altDoc action)
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
builder Context start nonTerminal terminal elem varDoc altDoc action
forall k k start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
initialCtx
        FixedGrammar start nonTerminal terminal elem varDoc altDoc action
-> m (FixedGrammar
        start nonTerminal terminal elem varDoc altDoc action)
forall (f :: * -> *) a. Applicative f => a -> f a
pure do Context start nonTerminal terminal elem varDoc altDoc action
-> FixedGrammar
     start nonTerminal terminal elem varDoc altDoc action
forall k k start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> FixedGrammar
     start nonTerminal terminal elem varDoc altDoc action
fromCtx Context start nonTerminal terminal elem varDoc altDoc action
finalCtx
    where
        initialCtx :: Context start nonTerminal terminal elem varDoc altDoc action
initialCtx = Context :: forall k k start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
EnumMap start nonTerminal
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
-> EnumMap nonTerminal varDoc
-> Context start nonTerminal terminal elem varDoc altDoc action
Context
            { $sel:ctxStarts:Context :: EnumMap start nonTerminal
ctxStarts = EnumMap start nonTerminal
forall k a. EnumMap k a
EnumMap.empty
            , $sel:ctxRules:Context :: EnumMap
  nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules = EnumMap
  nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
forall k a. EnumMap k a
EnumMap.empty
            , $sel:ctxDisplayNonTerminals:Context :: EnumMap nonTerminal varDoc
ctxDisplayNonTerminals = EnumMap nonTerminal varDoc
forall k a. EnumMap k a
EnumMap.empty
            }

        fromCtx :: Context start nonTerminal terminal elem varDoc altDoc action
-> FixedGrammar
     start nonTerminal terminal elem varDoc altDoc action
fromCtx Context start nonTerminal terminal elem varDoc altDoc action
ctx = FixedGrammar :: forall k k start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
EnumMap start nonTerminal
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
-> EnumMap nonTerminal varDoc
-> FixedGrammar
     start nonTerminal terminal elem varDoc altDoc action
FixedGrammar
            { $sel:grammarStarts:FixedGrammar :: EnumMap start nonTerminal
grammarStarts = Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
ctxStarts Context start nonTerminal terminal elem varDoc altDoc action
ctx
            , $sel:grammarRules:FixedGrammar :: EnumMap
  nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
grammarRules = Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules Context start nonTerminal terminal elem varDoc altDoc action
ctx
            , $sel:grammarDisplayNonTerminals:FixedGrammar :: EnumMap nonTerminal varDoc
grammarDisplayNonTerminals = Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
ctxDisplayNonTerminals Context start nonTerminal terminal elem varDoc altDoc action
ctx
            }

data FixedGrammar start nonTerminal terminal elem varDoc altDoc action = FixedGrammar
    { FixedGrammar start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
grammarStarts :: EnumMap.EnumMap start nonTerminal
    , FixedGrammar start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
grammarRules  :: EnumMap.EnumMap nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
    , FixedGrammar start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
grammarDisplayNonTerminals :: EnumMap.EnumMap nonTerminal varDoc
    }

data Action (action :: [Type] -> Type -> Type) where
    Action :: action us a -> Action action

data RuleExpr nonTerminal terminal elem altDoc action where
    RuleExpr
        :: [Alt nonTerminal terminal elem altDoc action a]
        -> RuleExpr nonTerminal terminal elem altDoc action

data Alt nonTerminal terminal elem altDoc action a where
    Alt :: Expr nonTerminal terminal elem us -> altDoc -> action us a
        -> Alt nonTerminal terminal elem altDoc action a

type Expr nonTerminal terminal elem = HFList.T (Unit nonTerminal terminal elem)

data Unit nonTerminal terminal elem u where
    UnitToken :: terminal -> Unit nonTerminal terminal elem elem
    UnitVar :: nonTerminal -> Unit nonTerminal terminal elem u

initialT :: Enum start => Monad m
    => start -> nonTerminal
    -> GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
initialT :: start
-> nonTerminal
-> GrammarT
     start nonTerminal terminal elem varDoc altDoc action m ()
initialT start
s nonTerminal
v = (Context start nonTerminal terminal elem varDoc altDoc action
 -> Context start nonTerminal terminal elem varDoc altDoc action)
-> GrammarT
     start nonTerminal terminal elem varDoc altDoc action m ()
forall (m :: * -> *) s. Monad m => (s -> s) -> StateT s m ()
modify' \Context start nonTerminal terminal elem varDoc altDoc action
ctx -> Context start nonTerminal terminal elem varDoc altDoc action
ctx
    {
        $sel:ctxStarts:Context :: EnumMap start nonTerminal
ctxStarts = start
-> nonTerminal
-> EnumMap start nonTerminal
-> EnumMap start nonTerminal
forall k a. Enum k => k -> a -> EnumMap k a -> EnumMap k a
EnumMap.insert start
s nonTerminal
v
            do Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
ctxStarts Context start nonTerminal terminal elem varDoc altDoc action
ctx
    }

ruleT :: Enum nonTerminal => Monad m
    => nonTerminal -> varDoc -> RuleExpr nonTerminal terminal elem altDoc action
    -> GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
ruleT :: nonTerminal
-> varDoc
-> RuleExpr nonTerminal terminal elem altDoc action
-> GrammarT
     start nonTerminal terminal elem varDoc altDoc action m ()
ruleT nonTerminal
v varDoc
d RuleExpr nonTerminal terminal elem altDoc action
e = (Context start nonTerminal terminal elem varDoc altDoc action
 -> Context start nonTerminal terminal elem varDoc altDoc action)
-> GrammarT
     start nonTerminal terminal elem varDoc altDoc action m ()
forall (m :: * -> *) s. Monad m => (s -> s) -> StateT s m ()
modify' \Context start nonTerminal terminal elem varDoc altDoc action
ctx -> Context start nonTerminal terminal elem varDoc altDoc action
ctx
    { $sel:ctxRules:Context :: EnumMap
  nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules = nonTerminal
-> RuleExpr nonTerminal terminal elem altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
forall k a. Enum k => k -> a -> EnumMap k a -> EnumMap k a
EnumMap.insert nonTerminal
v RuleExpr nonTerminal terminal elem altDoc action
e
        do Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap
     nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules Context start nonTerminal terminal elem varDoc altDoc action
ctx
    , $sel:ctxDisplayNonTerminals:Context :: EnumMap nonTerminal varDoc
ctxDisplayNonTerminals = nonTerminal
-> varDoc
-> EnumMap nonTerminal varDoc
-> EnumMap nonTerminal varDoc
forall k a. Enum k => k -> a -> EnumMap k a -> EnumMap k a
EnumMap.insert nonTerminal
v varDoc
d
        do Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
forall start nonTerminal terminal k (elem :: k) varDoc altDoc k
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
ctxDisplayNonTerminals Context start nonTerminal terminal elem varDoc altDoc action
ctx
    }