module Data.InvertibleGrammar
( Grammar (..)
, iso
, embedPrism
, embedParsePrism
, push
, pushForget
, InvertibleGrammar(..)
) where
import Prelude hiding ((.), id)
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 710
import Control.Applicative
#endif
import Control.Category
import Control.Monad
#if MIN_VERSION_mtl(2, 2, 0)
import Control.Monad.Except
#else
import Control.Monad.Error
#endif
import Data.Semigroup
import Data.StackPrism
data Grammar g t t' where
GenPrism :: String -> StackPrism a b -> Grammar g a b
ParsePrism :: String -> StackPrism b a -> Grammar g a b
Iso :: (a -> b) -> (b -> a) -> Grammar g a b
(:.:) :: Grammar g b c -> Grammar g a b -> Grammar g a c
(:<>:) :: Grammar g a b -> Grammar g a b -> Grammar g a b
Inject :: g a b -> Grammar g a b
iso :: (a -> b) -> (b -> a) -> Grammar g (a :- t) (b :- t)
iso f' g' = Iso f g
where
f (a :- t) = f' a :- t
g (b :- t) = g' b :- t
embedPrism :: StackPrism a b -> Grammar g (a :- t) (b :- t)
embedPrism prism = GenPrism "custom prism" (stackPrism f g)
where
f (a :- t) = forward prism a :- t
g (b :- t) = (:- t) <$> backward prism b
embedParsePrism :: String -> StackPrism b a -> Grammar g (a :- t) (b :- t)
embedParsePrism prismName prism = ParsePrism prismName (stackPrism f g)
where
f (a :- t) = forward prism a :- t
g (b :- t) = (:- t) <$> backward prism b
push :: (Eq a) => a -> Grammar g t (a :- t)
push a = GenPrism "push" $ stackPrism g f
where
g t = a :- t
f (a' :- t) = if a == a' then Just t else Nothing
pushForget :: a -> Grammar g t (a :- t)
pushForget a = GenPrism "pushForget" $ stackPrism g f
where
g t = a :- t
f (_ :- t) = Just t
instance Category (Grammar c) where
id = Iso id id
(.) x y = x :.: y
instance Semigroup (Grammar c t1 t2) where
(<>) = (:<>:)
class InvertibleGrammar m g where
parseWithGrammar :: g a b -> (a -> m b)
genWithGrammar :: g a b -> (b -> m a)
instance
( Monad m
, MonadPlus m
, MonadError String m
, InvertibleGrammar m g
) => InvertibleGrammar m (Grammar g) where
parseWithGrammar (Iso f _) = return . f
parseWithGrammar (GenPrism _ p) = return . forward p
parseWithGrammar (ParsePrism name p) =
maybe (throwError $ "Cannot parse Sexp for: " ++ name) return . backward p
parseWithGrammar (g :.: f) = parseWithGrammar g <=< parseWithGrammar f
parseWithGrammar (f :<>: g) =
\x -> parseWithGrammar f x `mplus` parseWithGrammar g x
parseWithGrammar (Inject g) = parseWithGrammar g
genWithGrammar (Iso _ g) = return . g
genWithGrammar (GenPrism name p) =
maybe (throwError $ "Cannot generate Sexp for: " ++ name) return . backward p
genWithGrammar (ParsePrism _ p) = return . forward p
genWithGrammar (g :.: f) = genWithGrammar g >=> genWithGrammar f
genWithGrammar (f :<>: g) =
\x -> genWithGrammar f x `mplus` genWithGrammar g x
genWithGrammar (Inject g) = genWithGrammar g