1 module Webc.Decoder where
3 import Control.Applicative (Applicative (..))
4 import Control.Monad (Monad (..))
5 import Control.Monad.Trans.Class qualified as MT
6 import Control.Monad.Trans.Except qualified as MT
7 import Control.Monad.Trans.State qualified as MT
9 import Data.Either (Either (..))
10 import Data.Eq (Eq (..))
11 import Data.Foldable (null)
12 import Data.Function (($))
13 import Data.Functor ((<$>))
14 import Network.URI.Slug
15 import Symantic.Classes (Iso (..), IsoFunctor ((<%>)), ProductFunctor (..), SumFunctor ((<+>)))
19 -- * The 'Decoder' interpreter
21 -- | A very very basic parser.
22 newtype Decoder a = Decoder
26 (MT.Except DecoderError)
30 decode :: Decoder a -> [Slug] -> Either DecoderError a
31 decode (Decoder dec) slugs = case MT.runExcept (MT.runStateT dec slugs) of
35 | otherwise -> Left $ DecoderErrorLeftover st
38 = DecoderErrorMismatch {expectedSlug :: Slug, gotSlug :: Slug}
40 | DecoderErrorLeftover [Slug]
42 instance IsoFunctor Decoder where
43 Iso{..} <%> Decoder x = Decoder (a2b <$> x)
44 instance ProductFunctor Decoder where
45 Decoder x <.> Decoder y = Decoder $ (,) <$> x <*> y
46 Decoder x <. Decoder y = Decoder $ x <* y
47 Decoder x .> Decoder y = Decoder $ x *> y
48 instance SumFunctor Decoder where
49 Decoder x <+> Decoder y = Decoder $
51 case MT.runExcept $ MT.runStateT x st of
52 Right (a, ss) -> return (Left a, ss)
54 -- TODO: better error merging
55 case MT.runExcept $ MT.runStateT y st of
56 Right (b, ss) -> return (Right b, ss)
57 Left err -> MT.throwE err
58 instance Slugable Decoder where
59 slug expectedSlug = Decoder $ do
62 [] -> MT.lift $ MT.throwE DecoderErrorMissing
64 | expectedSlug /= gotSlug ->
65 MT.lift $ MT.throwE $ DecoderErrorMismatch{..}
66 | otherwise -> MT.put nextSlugs