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
    { forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
ctxStarts :: EnumMap.EnumMap start nonTerminal
    , forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
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)
    , forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
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 :: forall {k} {k} (m :: * -> *) start nonTerminal terminal (elem :: k)
       varDoc altDoc (action :: [k] -> k -> *).
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 ()
builder = do
        Context start nonTerminal terminal elem varDoc altDoc action
finalCtx <- forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT GrammarT start nonTerminal terminal elem varDoc altDoc action m ()
builder forall {k} {k} {start} {nonTerminal} {terminal} {elem :: k}
       {varDoc} {altDoc} {action :: [k] -> k -> *}.
Context start nonTerminal terminal elem varDoc altDoc action
initialCtx
        forall (f :: * -> *) a. Applicative f => a -> f a
pure do 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
            { $sel:ctxStarts:Context :: EnumMap start nonTerminal
ctxStarts = forall k a. EnumMap k a
EnumMap.empty
            , $sel:ctxRules:Context :: EnumMap
  nonTerminal (RuleExpr nonTerminal terminal elem altDoc action)
ctxRules = forall k a. EnumMap k a
EnumMap.empty
            , $sel:ctxDisplayNonTerminals:Context :: EnumMap nonTerminal varDoc
ctxDisplayNonTerminals = 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
            { $sel:grammarStarts:FixedGrammar :: EnumMap start nonTerminal
grammarStarts = forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (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 = forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (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 = forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (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
    { forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
FixedGrammar start nonTerminal terminal elem varDoc altDoc action
-> EnumMap start nonTerminal
grammarStarts :: EnumMap.EnumMap start nonTerminal
    , forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
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)
    , forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
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 :: forall {k} {k} start (m :: * -> *) nonTerminal terminal (elem :: k)
       varDoc altDoc (action :: [k] -> k -> *).
(Enum start, Monad m) =>
start
-> nonTerminal
-> GrammarT
     start nonTerminal terminal elem varDoc altDoc action m ()
initialT start
s nonTerminal
v = 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 = forall k a. Enum k => k -> a -> EnumMap k a -> EnumMap k a
EnumMap.insert start
s nonTerminal
v
            do forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (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 :: forall {k} {k} nonTerminal (m :: * -> *) varDoc terminal
       (elem :: k) altDoc (action :: [k] -> k -> *) start.
(Enum nonTerminal, Monad m) =>
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 = 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 = 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 forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (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 = forall k a. Enum k => k -> a -> EnumMap k a -> EnumMap k a
EnumMap.insert nonTerminal
v varDoc
d
        do forall {k} {k} start nonTerminal terminal (elem :: k) varDoc altDoc
       (action :: [k] -> k -> *).
Context start nonTerminal terminal elem varDoc altDoc action
-> EnumMap nonTerminal varDoc
ctxDisplayNonTerminals Context start nonTerminal terminal elem varDoc altDoc action
ctx
    }