tlex-0.4.0.1: src/Language/Lexer/Tlex/Runner.hs
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.
| TlexError
-- ^ Some inputs are available, but not accepted.
| TlexAccepted mark action
-- ^ Accepted with a end position and an action.
deriving (Eq, Show)
data Runner unit action = Runner
{ tlexInitial :: Int -> Int
-- ^ StartState -> (StateNum | -1)
, tlexAccept :: Int -> Maybe action
-- ^ StateNum -> Maybe Action
, tlexTrans :: Int -> Int -> Int
-- ^ StateNum -> CodeUnit -> (StateNum | -1)
}
deriving Functor
runRunner :: Enum state => TlexContext mark unit m
=> Runner unit action -> state -> m (TlexResult mark action)
runRunner runner s0 = case tlexInitial runner do fromEnum s0 of
-1 -> error "unknown initial state"
s -> go s
where
go s = case tlexAccept runner s of
Just x -> do
acc <- buildAccepted x
mc <- tlexGetInputPart
case mc of
Nothing -> pure acc
Just c -> goTrans s c do Just acc
Nothing -> do
mc <- tlexGetInputPart
case mc of
Nothing -> pure TlexEndOfInput
Just c -> goTrans s c Nothing
goTrans s c preAccepted = case tlexTrans runner s do fromEnum c of
-1 -> goEnd preAccepted
ns -> do
nacc <- case tlexAccept runner ns of
Just x -> do
acc <- buildAccepted x
pure do Just acc
Nothing -> pure preAccepted
mc <- tlexGetInputPart
case mc of
Nothing -> goEnd nacc
Just nc -> goTrans ns nc nacc
buildAccepted x = do
m <- tlexGetMark
pure do TlexAccepted m x
goEnd preAccepted = case preAccepted of
Nothing -> pure TlexError
Just acc -> pure acc