{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
module Data.Svfactor.Syntax.Field (
Field (Unquoted, Quoted)
, SpacedField
, Spaced (Spaced)
, HasFields (fields)
, AsField (_Field, _Unquoted, _Quoted)
, unescapedField
, foldField
, fieldContents
) where
import Control.Applicative ((<$>))
import Control.DeepSeq (NFData)
import Control.Lens (Lens, Prism', Traversal, lens, prism)
import Data.Foldable (Foldable (foldMap))
import Data.Functor (Functor (fmap))
import Data.Traversable (Traversable (traverse))
import GHC.Generics (Generic)
import Data.Svfactor.Text.Escape (Unescaped (Unescaped, getRawUnescaped))
import Data.Svfactor.Text.Quote (Quote)
import Data.Svfactor.Text.Space (Spaced (Spaced))
data Field s =
Unquoted s
| Quoted Quote (Unescaped s)
deriving (Eq, Ord, Show, Generic)
instance NFData s => NFData (Field s)
instance Functor Field where
fmap f fi = case fi of
Unquoted s -> Unquoted (f s)
Quoted q v -> Quoted q (fmap f v)
instance Foldable Field where
foldMap f fi = case fi of
Unquoted s -> f s
Quoted _ v -> foldMap f v
instance Traversable Field where
traverse f fi = case fi of
Unquoted s -> Unquoted <$> f s
Quoted q v -> Quoted q <$> traverse f v
type SpacedField a = Spaced (Field a)
class (HasFields s s a a) => AsField s a | s -> a where
_Field :: Prism' s (Field a)
_Unquoted :: Prism' s a
_Quoted :: Prism' s (Quote, Unescaped a)
_Unquoted = _Field . _Unquoted
{-# INLINE _Unquoted #-}
_Quoted = _Field . _Quoted
{-# INLINE _Quoted #-}
instance AsField (Field a) a where
_Field = id
{-# INLINE _Field #-}
_Unquoted = prism Unquoted
(\x -> case x of
Unquoted y -> Right y
_ -> Left x
)
{-# INLINE _Unquoted #-}
_Quoted = prism (uncurry Quoted)
(\x -> case x of
Quoted y z -> Right (y,z)
_ -> Left x
)
{-# INLINE _Quoted #-}
class HasFields c d s t | c -> s, d -> t, c t -> d, d s -> c where
fields :: Traversal c d (Field s) (Field t)
instance HasFields (Field s) (Field t) s t where
fields = id
{-# INLINE fields #-}
unescapedField :: Quote -> s -> Field s
unescapedField q s = Quoted q (Unescaped s)
foldField :: (s -> b) -> (Quote -> Unescaped s -> b) -> Field s -> b
foldField u q fi = case fi of
Unquoted s -> u s
Quoted a b -> q a b
fieldContents :: Lens (Field s) (Field t) s t
fieldContents =
lens (foldField id (const getRawUnescaped)) $ \f b -> case f of
Unquoted _ -> Unquoted b
Quoted q _ -> Quoted q (Unescaped b)