1 {-# LANGUAGE GeneralisedNewtypeDeriving #-}
2 {-# LANGUAGE UndecidableInstances #-}
4 module Webc.Decoder where
6 import Control.Applicative (Applicative (..))
7 import Control.Monad (Monad (..))
8 import Control.Monad.Trans.Class qualified as MT
9 import Control.Monad.Trans.Except qualified as MT
10 import Control.Monad.Trans.Reader qualified as MT
11 import Control.Monad.Trans.State qualified as MT
12 import Data.Bifunctor (first)
14 import Data.ByteString.Lazy qualified as BSL
15 import Data.Either (Either (..))
16 import Data.Eq (Eq (..))
17 import Data.Foldable (null)
18 import Data.Function (($), (.))
19 import Data.Functor (Functor, (<$>))
20 import Data.List qualified as List
21 import Data.Maybe (Maybe (..))
23 import Data.Semigroup (Semigroup (..))
25 import Data.Set qualified as Set
26 import Data.Text qualified as Text
27 import Network.URI.Slug
28 import Symantic.Classes (Iso (..), IsoFunctor ((<%>)), Optionable (..), ProductFunctor (..), SumFunctor ((<+>)))
30 import Text.Show (Show)
32 -- import Prelude (undefined)
36 -- * The 'Decoder' interpreter
38 -- | A very very basic parser.
39 newtype Decoder err a = Decoder
41 MT.ReaderT [Slug] (MT.StateT [Slug] (MT.ExceptT (DecoderError err) IO)) a
43 deriving (Functor, Applicative, Monad)
45 decode :: Decoder err a -> [Slug] -> IO (Either (DecoderError err) a)
46 decode (Decoder dec) slugs =
47 MT.runExceptT (MT.runStateT (MT.runReaderT dec []) slugs) >>= \case
48 Left err -> return $ Left err
50 | null st -> return $ Right a
51 | otherwise -> return $ Left $ DecoderErrorLeftover st
54 = DecoderErrorMismatch
55 { expectedSlugs :: Set Slug
59 | DecoderErrorLeftover [Slug]
60 | DecoderErrorParser err
61 deriving (Eq, Ord, Show)
63 instance IsoFunctor (Decoder err) where
64 (<%>) Iso{..} = (a2b <$>)
65 instance ProductFunctor (Decoder err) where
69 instance SumFunctor (Decoder err) where
70 Decoder x <+> Decoder y = Decoder $
71 MT.ReaderT $ \env -> MT.StateT $ \st -> do
72 MT.lift (MT.runExceptT (MT.runStateT (MT.runReaderT x env) st)) >>= \case
73 Right (a, st') -> return (Left a, st')
75 -- TODO: better error merging
76 MT.lift (MT.runExceptT (MT.runStateT (MT.runReaderT y env) st)) >>= \case
77 Right (b, st') -> return (Right b, st')
78 Left err -> MT.throwE err
79 instance Endable (Decoder err) where
81 MT.lift MT.get >>= \case
83 lo -> MT.lift $ MT.lift $ MT.throwE $ DecoderErrorLeftover lo
84 instance Repeatable (Decoder err) where
85 many0 (Decoder x) = Decoder (MT.ReaderT (MT.StateT . go))
88 MT.lift (MT.runExceptT (MT.runStateT (MT.runReaderT x env) st)) >>= \case
89 Left _err -> return ([], st) -- always backtrack
90 Right (a, st') -> first (a :) <$> go env st'
91 many1 x = (:) <$> x <*> many0 x
92 instance Optionable (Decoder err) where
93 optional (Decoder x) = Decoder $
94 MT.ReaderT $ \env -> MT.StateT $ \st -> do
95 MT.lift (MT.runExceptT (MT.runStateT (MT.runReaderT x env) st)) >>= \case
96 Left{} -> return (Nothing, st)
97 Right (a, st') -> return (Just a, st')
98 instance Slugable (Decoder err) where
99 literalSlug expectedSlug = Decoder $ do
100 slugs <- MT.lift MT.get
102 [] -> MT.lift $ MT.lift $ MT.throwE DecoderErrorMissing
104 | expectedSlug /= gotSlug ->
105 MT.lift $ MT.lift $ MT.throwE DecoderErrorMismatch{expectedSlugs = Set.singleton expectedSlug, ..}
107 MT.local (<> [gotSlug]) $
108 MT.lift $ MT.put nextSlugs
109 chooseSlug expectedSlugs = Decoder $ do
110 slugs <- MT.lift MT.get
112 [] -> MT.lift $ MT.lift $ MT.throwE DecoderErrorMissing
114 | gotSlug `Set.notMember` expectedSlugs ->
115 MT.lift $ MT.lift $ MT.throwE DecoderErrorMismatch{expectedSlugs, ..}
117 MT.local (<> [gotSlug]) $
118 MT.lift $ MT.put nextSlugs
121 -- chooseSlugs = undefined
122 -- chooseSlugs expectedSlugs = Decoder $ do
123 -- slugs <- MT.lift MT.get
125 -- [] -> MT.lift $ MT.lift $ MT.throwE DecoderErrorMissing
126 -- gotSlug : nextSlugs
127 -- | gotSlug `Set.member` expectedSlugs ->
128 -- MT.lift $ MT.lift $ MT.throwE $ DecoderErrorMismatch{expectedSlugs, ..}
130 -- MT.local (<> [gotSlug]) $
131 -- MT.lift $ MT.put nextSlugs
133 instance Capturable (Decoder err) where
134 captureSlug _name = Decoder $ do
135 slugs <- MT.lift MT.get
137 [] -> MT.lift $ MT.lift $ MT.throwE DecoderErrorMissing
138 gotSlug : nextSlugs ->
139 MT.local (<> [gotSlug]) do
140 MT.lift $ MT.put nextSlugs
143 --chooseSlug expectedSlugs = Decoder $ do
144 -- slugs <- MT.lift MT.get
146 -- [] -> MT.lift $ MT.lift $ MT.throwE DecoderErrorMissing
147 -- gotSlug : nextSlugs
148 -- | gotSlug `Set.member` expectedSlugs ->
149 -- MT.lift $ MT.lift $ MT.throwE $ DecoderErrorMismatch{..}
151 -- MT.local (<> [gotSlug]) $
152 -- MT.lift $ MT.put nextSlugs
155 instance Selectable (Decoder err) where
158 case Map.lookup a a2bs of
160 Decoder $ MT.lift $ MT.lift $ MT.throwE
161 DecoderErrorMissing -- FIXME
164 MT.lift $ MT.lift $ MT.throwE
165 DecoderErrorMissing -- FIXME
166 go a ((ca, x):xs) = Decoder $
167 MT.ReaderT $ \env -> MT.StateT $ \st -> do
168 MT.lift (MT.runExceptT (MT.runStateT (MT.runReaderT (unDecoder x) env) st)) >>= \case
171 MT.runStateT (MT.runReaderT (unDecoder (choose ra xs)) env) st
173 instance Fileable (Decoder err) where
174 type FileableConstraint (Decoder err) = Parsable err
184 List.intercalate "/" $
185 Text.unpack . encodeSlug <$> path
186 case parse content of
188 Left err -> MT.lift $ MT.lift $ MT.throwE $ DecoderErrorParser err
190 -- * Class 'Parsable'
191 class Parsable err a where
192 parse :: BSL.ByteString -> Either err a