module Language.Lexer.Tlex.Pipeline.Pattern2Nfa (
    pattern2Nfa,
) where

import           Language.Lexer.Tlex.Prelude

import qualified Data.EnumSet                        as EnumSet
import qualified Language.Lexer.Tlex.Data.SymEnumSet as SymEnumSet
import qualified Language.Lexer.Tlex.Machine.NFA     as NFA
import qualified Language.Lexer.Tlex.Machine.Pattern as Pattern
import qualified Language.Lexer.Tlex.Machine.State   as MState


pattern2Nfa
    :: Enum e
    => MState.StateNum -> MState.StateNum -> Pattern.Pattern e
    -> NFA.NFABuilder m ()
pattern2Nfa :: StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa = StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
go where
    go :: StateNum -> StateNum -> Pattern e -> NFABuilder m ()
go StateNum
b StateNum
e = \case
        Pattern e
Pattern.Epsilon -> StateNum -> StateNum -> NFABuilder m ()
forall m. StateNum -> StateNum -> NFABuilder m ()
NFA.epsilonTrans StateNum
b StateNum
e
        Pattern.Range SymEnumSet e
s -> StateNum -> NFAStateTrans -> NFABuilder m ()
forall m. StateNum -> NFAStateTrans -> NFABuilder m ()
NFA.condTrans StateNum
b
            do
                let (Bool
isStraight, EnumSet e
es) = SymEnumSet e -> (Bool, EnumSet e)
forall a. Enum a => SymEnumSet a -> (Bool, EnumSet a)
SymEnumSet.toEnumSet SymEnumSet e
s
                NFAStateTrans :: Bool -> IntSet -> StateNum -> NFAStateTrans
NFA.NFAStateTrans
                    { $sel:nstTransIsStraight:NFAStateTrans :: Bool
NFA.nstTransIsStraight = Bool
isStraight
                    , $sel:nstTransRange:NFAStateTrans :: IntSet
NFA.nstTransRange = EnumSet e -> IntSet
forall k. EnumSet k -> IntSet
EnumSet.unEnumSet EnumSet e
es
                    , $sel:nstTransNextState:NFAStateTrans :: StateNum
NFA.nstTransNextState = StateNum
e
                    }
        Pattern e
p1 Pattern.:^: Pattern e
p2 -> do
            StateNum
s <- NFABuilder m StateNum
forall m. NFABuilder m StateNum
NFA.newStateNum
            StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa StateNum
b StateNum
s Pattern e
p1
            StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa StateNum
s StateNum
e Pattern e
p2
        Pattern e
p1 Pattern.:|: Pattern e
p2 -> do
            StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa StateNum
b StateNum
e Pattern e
p1
            StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa StateNum
b StateNum
e Pattern e
p2
        Pattern.Many Pattern e
p -> do
            StateNum
s <- NFABuilder m StateNum
forall m. NFABuilder m StateNum
NFA.newStateNum
            StateNum -> StateNum -> NFABuilder m ()
forall m. StateNum -> StateNum -> NFABuilder m ()
NFA.epsilonTrans StateNum
b StateNum
s
            StateNum -> StateNum -> Pattern e -> NFABuilder m ()
forall e m.
Enum e =>
StateNum -> StateNum -> Pattern e -> NFABuilder m ()
pattern2Nfa StateNum
s StateNum
s Pattern e
p
            StateNum -> StateNum -> NFABuilder m ()
forall m. StateNum -> StateNum -> NFABuilder m ()
NFA.epsilonTrans StateNum
s StateNum
e