{-# LANGUAGE InstanceSigs #-} module Text.Lexer.Inchworm.Scanner ( Scanner (..) , scanSourceToList) where import Text.Lexer.Inchworm.Source -- | Scanner of input tokens that produces a result value -- of type @a@ when successful. data Scanner m loc input a = Scanner { runScanner :: Source m loc input -> m (Maybe a) } instance Monad m => Functor (Scanner m loc input) where fmap f (Scanner load) = Scanner $ \source -> do r <- load source case r of Nothing -> return Nothing Just x -> return $ Just $ f x {-# INLINE fmap #-} instance Monad m => Applicative (Scanner m loc input) where pure x = Scanner $ \_ -> return (Just x) (<*>) (Scanner loadF) (Scanner loadX) = Scanner $ \ss -> do mf <- loadF ss case mf of Nothing -> return Nothing Just f -> do mx <- loadX ss case mx of Nothing -> return Nothing Just x -> return $ Just (f x) instance Monad m => Monad (Scanner m loc input) where return x = Scanner $ \_ -> return (Just x) (>>=) (Scanner loadX) f = Scanner $ \ss -> do mx <- loadX ss case mx of Nothing -> return Nothing Just x -> runScanner (f x) ss -- | Apply a scanner to a source of input tokens, -- where the tokens are represented as a lazy list. -- -- The result values are also produced in a lazy list. -- scanSourceToList :: Monad m => Source m loc [i] -> Scanner m loc [i] a -> m ([a], loc, [i]) scanSourceToList ss (Scanner load) = go [] where go acc = load ss >>= \result -> case result of Just x -> go (x : acc) Nothing -> do (loc, src') <- sourceRemaining ss return (reverse acc, loc, src') {-# SPECIALIZE INLINE scanSourceToList :: Source IO Location [Char] -> Scanner IO Location [Char] a -> IO ([a], Location, [Char]) #-}