module Language.Lexer.Tlex.Runner (
    TlexContext (..),
    TlexResult (..),
    Runner (..),
    runRunner,
) where

import           Language.Lexer.Tlex.Prelude


class (Enum unit, Monad m) => TlexContext mark unit m | m -> mark, m -> unit where
    -- | Get a unit of current position from input, and move to next position.
    tlexGetInputPart :: m (Maybe unit)

    -- | Get a mark of current position.
    tlexGetMark :: m mark

data TlexResult mark action
    = TlexEndOfInput
    -- ^ No more inputs.
    | TlexNotAccepted
    -- ^ Some inputs are available, but not accepted.
    | TlexAccepted mark action
    -- ^ Accepted with a end position and an action.
    deriving (TlexResult mark action -> TlexResult mark action -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall mark action.
(Eq mark, Eq action) =>
TlexResult mark action -> TlexResult mark action -> Bool
/= :: TlexResult mark action -> TlexResult mark action -> Bool
$c/= :: forall mark action.
(Eq mark, Eq action) =>
TlexResult mark action -> TlexResult mark action -> Bool
== :: TlexResult mark action -> TlexResult mark action -> Bool
$c== :: forall mark action.
(Eq mark, Eq action) =>
TlexResult mark action -> TlexResult mark action -> Bool
Eq, Int -> TlexResult mark action -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall mark action.
(Show mark, Show action) =>
Int -> TlexResult mark action -> ShowS
forall mark action.
(Show mark, Show action) =>
[TlexResult mark action] -> ShowS
forall mark action.
(Show mark, Show action) =>
TlexResult mark action -> String
showList :: [TlexResult mark action] -> ShowS
$cshowList :: forall mark action.
(Show mark, Show action) =>
[TlexResult mark action] -> ShowS
show :: TlexResult mark action -> String
$cshow :: forall mark action.
(Show mark, Show action) =>
TlexResult mark action -> String
showsPrec :: Int -> TlexResult mark action -> ShowS
$cshowsPrec :: forall mark action.
(Show mark, Show action) =>
Int -> TlexResult mark action -> ShowS
Show)


data Runner unit action = Runner
    { forall {k} (unit :: k) action. Runner unit action -> Int -> Int
tlexInitial :: Int -> Int
    -- ^ StartState -> (StateNum | -1)
    , forall {k} (unit :: k) action.
Runner unit action -> Int -> Maybe action
tlexAccept  :: Int -> Maybe action
    -- ^ StateNum -> Maybe Action
    , forall {k} (unit :: k) action.
Runner unit action -> Int -> Int -> Int
tlexTrans   :: Int -> Int -> Int
    -- ^ StateNum -> CodeUnit -> (StateNum | -1)
    }
    deriving forall k (unit :: k) a b. a -> Runner unit b -> Runner unit a
forall k (unit :: k) a b.
(a -> b) -> Runner unit a -> Runner unit b
forall a b. a -> Runner unit b -> Runner unit a
forall a b. (a -> b) -> Runner unit a -> Runner unit b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Runner unit b -> Runner unit a
$c<$ :: forall k (unit :: k) a b. a -> Runner unit b -> Runner unit a
fmap :: forall a b. (a -> b) -> Runner unit a -> Runner unit b
$cfmap :: forall k (unit :: k) a b.
(a -> b) -> Runner unit a -> Runner unit b
Functor

runRunner :: Enum state => TlexContext mark unit m
    => Runner unit action -> state -> m (TlexResult mark action)
runRunner :: forall state mark unit (m :: * -> *) action.
(Enum state, TlexContext mark unit m) =>
Runner unit action -> state -> m (TlexResult mark action)
runRunner Runner unit action
runner state
s0 = case forall {k} (unit :: k) action. Runner unit action -> Int -> Int
tlexInitial Runner unit action
runner do forall a. Enum a => a -> Int
fromEnum state
s0 of
        Int
-1 -> forall a. HasCallStack => String -> a
error String
"unknown initial state"
        Int
s  -> Int -> m (TlexResult mark action)
go Int
s
    where
        go :: Int -> m (TlexResult mark action)
go Int
s = case forall {k} (unit :: k) action.
Runner unit action -> Int -> Maybe action
tlexAccept Runner unit action
runner Int
s of
            Just action
x  -> do
                TlexResult mark action
acc <- forall {m :: * -> *} {mark} {unit} {action}.
TlexContext mark unit m =>
action -> m (TlexResult mark action)
buildAccepted action
x
                Maybe unit
mc <- forall mark unit (m :: * -> *).
TlexContext mark unit m =>
m (Maybe unit)
tlexGetInputPart
                case Maybe unit
mc of
                    Maybe unit
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure TlexResult mark action
acc
                    Just unit
c  -> Int
-> unit
-> Maybe (TlexResult mark action)
-> m (TlexResult mark action)
goTrans Int
s unit
c do forall a. a -> Maybe a
Just TlexResult mark action
acc
            Maybe action
Nothing -> do
                Maybe unit
mc <- forall mark unit (m :: * -> *).
TlexContext mark unit m =>
m (Maybe unit)
tlexGetInputPart
                case Maybe unit
mc of
                    Maybe unit
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall mark action. TlexResult mark action
TlexEndOfInput
                    Just unit
c  -> Int
-> unit
-> Maybe (TlexResult mark action)
-> m (TlexResult mark action)
goTrans Int
s unit
c forall a. Maybe a
Nothing

        goTrans :: Int
-> unit
-> Maybe (TlexResult mark action)
-> m (TlexResult mark action)
goTrans Int
s unit
c Maybe (TlexResult mark action)
preAccepted = case forall {k} (unit :: k) action.
Runner unit action -> Int -> Int -> Int
tlexTrans Runner unit action
runner Int
s do forall a. Enum a => a -> Int
fromEnum unit
c of
            Int
-1 -> forall {f :: * -> *} {mark} {action}.
Applicative f =>
Maybe (TlexResult mark action) -> f (TlexResult mark action)
goEnd Maybe (TlexResult mark action)
preAccepted
            Int
ns -> do
                Maybe (TlexResult mark action)
nacc <- case forall {k} (unit :: k) action.
Runner unit action -> Int -> Maybe action
tlexAccept Runner unit action
runner Int
ns of
                    Just action
x -> do
                        TlexResult mark action
acc <- forall {m :: * -> *} {mark} {unit} {action}.
TlexContext mark unit m =>
action -> m (TlexResult mark action)
buildAccepted action
x
                        forall (f :: * -> *) a. Applicative f => a -> f a
pure do forall a. a -> Maybe a
Just TlexResult mark action
acc
                    Maybe action
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (TlexResult mark action)
preAccepted
                Maybe unit
mc <- forall mark unit (m :: * -> *).
TlexContext mark unit m =>
m (Maybe unit)
tlexGetInputPart
                case Maybe unit
mc of
                    Maybe unit
Nothing -> forall {f :: * -> *} {mark} {action}.
Applicative f =>
Maybe (TlexResult mark action) -> f (TlexResult mark action)
goEnd Maybe (TlexResult mark action)
nacc
                    Just unit
nc -> Int
-> unit
-> Maybe (TlexResult mark action)
-> m (TlexResult mark action)
goTrans Int
ns unit
nc Maybe (TlexResult mark action)
nacc

        buildAccepted :: action -> m (TlexResult mark action)
buildAccepted action
x = do
            mark
m <- forall mark unit (m :: * -> *). TlexContext mark unit m => m mark
tlexGetMark
            forall (f :: * -> *) a. Applicative f => a -> f a
pure do forall mark action. mark -> action -> TlexResult mark action
TlexAccepted mark
m action
x

        goEnd :: Maybe (TlexResult mark action) -> f (TlexResult mark action)
goEnd Maybe (TlexResult mark action)
preAccepted = case Maybe (TlexResult mark action)
preAccepted of
            Maybe (TlexResult mark action)
Nothing  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall mark action. TlexResult mark action
TlexNotAccepted
            Just TlexResult mark action
acc -> forall (f :: * -> *) a. Applicative f => a -> f a
pure TlexResult mark action
acc