{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE UndecidableInstances #-}
module Dhall
(
input
, inputWithSettings
, inputFile
, inputFileWithSettings
, inputExpr
, inputExprWithSettings
, rootDirectory
, sourceName
, startingContext
, substitutions
, normalizer
, defaultInputSettings
, InputSettings
, defaultEvaluateSettings
, EvaluateSettings
, HasEvaluateSettings
, detailed
, Decoder (..)
, RecordDecoder(..)
, UnionDecoder(..)
, Encoder(..)
, FromDhall(..)
, Interpret
, InvalidDecoder(..)
, ExtractErrors(..)
, ExtractError(..)
, Extractor
, MonadicExtractor
, typeError
, extractError
, toMonadic
, fromMonadic
, auto
, genericAuto
, genericAutoWith
, InterpretOptions(..)
, InputNormalizer(..)
, defaultInputNormalizer
, SingletonConstructors(..)
, defaultInterpretOptions
, bool
, natural
, integer
, scientific
, double
, lazyText
, strictText
, maybe
, sequence
, list
, vector
, function
, functionWith
, setFromDistinctList
, setIgnoringDuplicates
, hashSetFromDistinctList
, hashSetIgnoringDuplicates
, Dhall.map
, hashMap
, pairFromMapEntry
, unit
, void
, string
, pair
, record
, field
, union
, constructor
, GenericFromDhall(..)
, GenericToDhall(..)
, ToDhall(..)
, Inject
, inject
, genericToDhall
, genericToDhallWith
, RecordEncoder(..)
, encodeFieldWith
, encodeField
, recordEncoder
, UnionEncoder(..)
, encodeConstructorWith
, encodeConstructor
, unionEncoder
, (>|<)
, rawInput
, (>$<)
, (>*<)
, Natural
, Seq
, Text
, Vector
, Generic
) where
import Control.Applicative (empty, liftA2, Alternative)
import Control.Exception (Exception)
import Control.Monad.Trans.State.Strict
import Control.Monad (guard)
import Data.Coerce (coerce)
import Data.Either.Validation (Validation(..), eitherToValidation, validationToEither)
import Data.Fix (Fix(..))
import Data.Functor.Contravariant (Contravariant(..), (>$<), Op(..))
import Data.Functor.Contravariant.Divisible (Divisible(..), divided)
import Data.Hashable (Hashable)
import Data.List.NonEmpty (NonEmpty (..))
import Data.HashMap.Strict (HashMap)
import Data.Map (Map)
import Data.Monoid ((<>))
import Data.Scientific (Scientific)
import Data.Semigroup (Semigroup)
import Data.Sequence (Seq)
import Data.Text (Text)
import Data.Text.Prettyprint.Doc (Pretty)
import Data.Typeable (Typeable)
import Data.Vector (Vector)
import Data.Void (Void)
import Data.Word (Word8, Word16, Word32, Word64)
import Dhall.Syntax (Expr(..), Chunks(..), DhallDouble(..), Var(..))
import Dhall.Import (Imported(..))
import Dhall.Parser (Src(..))
import Dhall.TypeCheck (DetailedTypeError(..), TypeError)
import GHC.Generics
import Lens.Family (LensLike', view)
import Numeric.Natural (Natural)
import Prelude hiding (maybe, sequence)
import System.FilePath (takeDirectory)
import qualified Control.Applicative
import qualified Control.Exception
import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.Foldable
import qualified Data.Functor.Compose
import qualified Data.Functor.Product
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Map
import qualified Data.Maybe
import qualified Data.List
import qualified Data.List.NonEmpty
import qualified Data.Semigroup
import qualified Data.Scientific
import qualified Data.Sequence
import qualified Data.Set
import qualified Data.HashSet
import qualified Data.Text
import qualified Data.Text.IO
import qualified Data.Text.Lazy
import qualified Data.Vector
import qualified Data.Void
import qualified Dhall.Context
import qualified Dhall.Core
import qualified Dhall.Import
import qualified Dhall.Map
import qualified Dhall.Parser
import qualified Dhall.Pretty.Internal
import qualified Dhall.Substitution
import qualified Dhall.TypeCheck
import qualified Dhall.Util
import qualified Lens.Family
type Extractor s a = Validation (ExtractErrors s a)
type MonadicExtractor s a = Either (ExtractErrors s a)
typeError :: Expr s a -> Expr s a -> Extractor s a b
typeError expected actual =
Failure . ExtractErrors . pure . TypeMismatch $ InvalidDecoder expected actual
extractError :: Text -> Extractor s a b
extractError = Failure . ExtractErrors . pure . ExtractError
toMonadic :: Extractor s a b -> MonadicExtractor s a b
toMonadic = validationToEither
fromMonadic :: MonadicExtractor s a b -> Extractor s a b
fromMonadic = eitherToValidation
newtype ExtractErrors s a = ExtractErrors
{ getErrors :: NonEmpty (ExtractError s a)
} deriving Semigroup
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractErrors s a) where
show (ExtractErrors (e :| [])) = show e
show (ExtractErrors es) = prefix <> (unlines . Data.List.NonEmpty.toList . fmap show $ es)
where
prefix =
"Multiple errors were encountered during extraction: \n\
\ \n"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (ExtractErrors s a)
data ExtractError s a =
TypeMismatch (InvalidDecoder s a)
| ExtractError Text
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractError s a) where
show (TypeMismatch e) = show e
show (ExtractError es) =
_ERROR <> ": Failed extraction \n\
\ \n\
\The expression type-checked successfully but the transformation to the target \n\
\type failed with the following error: \n\
\ \n\
\" <> Data.Text.unpack es <> "\n\
\ \n"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (ExtractError s a)
data InvalidDecoder s a = InvalidDecoder
{ invalidDecoderExpected :: Expr s a
, invalidDecoderExpression :: Expr s a
}
deriving (Typeable)
instance (Pretty s, Typeable s, Pretty a, Typeable a) => Exception (InvalidDecoder s a)
_ERROR :: String
_ERROR = "\ESC[1;31mError\ESC[0m"
instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (InvalidDecoder s a) where
show InvalidDecoder { .. } =
_ERROR <> ": Invalid Dhall.Decoder \n\
\ \n\
\Every Decoder must provide an extract function that succeeds if an expression \n\
\matches the expected type. You provided a Decoder that disobeys this contract \n\
\ \n\
\The Decoder provided has the expected dhall type: \n\
\ \n\
\" <> show txt0 <> "\n\
\ \n\
\and it couldn't extract a value from the well-typed expression: \n\
\ \n\
\" <> show txt1 <> "\n\
\ \n"
where
txt0 = Dhall.Util.insert invalidDecoderExpected
txt1 = Dhall.Util.insert invalidDecoderExpression
data InputSettings = InputSettings
{ _rootDirectory :: FilePath
, _sourceName :: FilePath
, _evaluateSettings :: EvaluateSettings
}
defaultInputSettings :: InputSettings
defaultInputSettings = InputSettings
{ _rootDirectory = "."
, _sourceName = "(input)"
, _evaluateSettings = defaultEvaluateSettings
}
rootDirectory
:: (Functor f)
=> LensLike' f InputSettings FilePath
rootDirectory k s =
fmap (\x -> s { _rootDirectory = x }) (k (_rootDirectory s))
sourceName
:: (Functor f)
=> LensLike' f InputSettings FilePath
sourceName k s =
fmap (\x -> s { _sourceName = x}) (k (_sourceName s))
data EvaluateSettings = EvaluateSettings
{ _substitutions :: Dhall.Substitution.Substitutions Src Void
, _startingContext :: Dhall.Context.Context (Expr Src Void)
, _normalizer :: Maybe (Dhall.Core.ReifiedNormalizer Void)
}
defaultEvaluateSettings :: EvaluateSettings
defaultEvaluateSettings = EvaluateSettings
{ _substitutions = Dhall.Substitution.empty
, _startingContext = Dhall.Context.empty
, _normalizer = Nothing
}
startingContext
:: (Functor f, HasEvaluateSettings s)
=> LensLike' f s (Dhall.Context.Context (Expr Src Void))
startingContext = evaluateSettings . l
where
l :: (Functor f)
=> LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src Void))
l k s = fmap (\x -> s { _startingContext = x}) (k (_startingContext s))
substitutions
:: (Functor f, HasEvaluateSettings s)
=> LensLike' f s (Dhall.Substitution.Substitutions Src Void)
substitutions = evaluateSettings . l
where
l :: (Functor f)
=> LensLike' f EvaluateSettings (Dhall.Substitution.Substitutions Src Void)
l k s = fmap (\x -> s { _substitutions = x }) (k (_substitutions s))
normalizer
:: (Functor f, HasEvaluateSettings s)
=> LensLike' f s (Maybe (Dhall.Core.ReifiedNormalizer Void))
normalizer = evaluateSettings . l
where
l :: (Functor f)
=> LensLike' f EvaluateSettings (Maybe (Dhall.Core.ReifiedNormalizer Void))
l k s = fmap (\x -> s { _normalizer = x }) (k (_normalizer s))
class HasEvaluateSettings s where
evaluateSettings
:: (Functor f)
=> LensLike' f s EvaluateSettings
instance HasEvaluateSettings InputSettings where
evaluateSettings k s =
fmap (\x -> s { _evaluateSettings = x }) (k (_evaluateSettings s))
instance HasEvaluateSettings EvaluateSettings where
evaluateSettings = id
input
:: Decoder a
-> Text
-> IO a
input =
inputWithSettings defaultInputSettings
inputWithSettings
:: InputSettings
-> Decoder a
-> Text
-> IO a
inputWithSettings settings (Decoder {..}) txt = do
let suffix = Dhall.Pretty.Internal.prettyToStrictText expected
let annotate substituted = case substituted of
Note (Src begin end bytes) _ ->
Note (Src begin end bytes') (Annot substituted expected)
where
bytes' = bytes <> " : " <> suffix
_ ->
Annot substituted expected
normExpr <- inputHelper annotate settings txt
case extract normExpr of
Success x -> return x
Failure e -> Control.Exception.throwIO e
inputFile
:: Decoder a
-> FilePath
-> IO a
inputFile =
inputFileWithSettings defaultEvaluateSettings
inputFileWithSettings
:: EvaluateSettings
-> Decoder a
-> FilePath
-> IO a
inputFileWithSettings settings ty path = do
text <- Data.Text.IO.readFile path
let inputSettings = InputSettings
{ _rootDirectory = takeDirectory path
, _sourceName = path
, _evaluateSettings = settings
}
inputWithSettings inputSettings ty text
inputExpr
:: Text
-> IO (Expr Src Void)
inputExpr =
inputExprWithSettings defaultInputSettings
inputExprWithSettings
:: InputSettings
-> Text
-> IO (Expr Src Void)
inputExprWithSettings = inputHelper id
inputHelper
:: (Expr Src Void -> Expr Src Void)
-> InputSettings
-> Text
-> IO (Expr Src Void)
inputHelper annotate settings txt = do
expr <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)
let InputSettings {..} = settings
let EvaluateSettings {..} = _evaluateSettings
let transform =
Lens.Family.set Dhall.Import.substitutions _substitutions
. Lens.Family.set Dhall.Import.normalizer _normalizer
. Lens.Family.set Dhall.Import.startingContext _startingContext
let status = transform (Dhall.Import.emptyStatus _rootDirectory)
expr' <- State.evalStateT (Dhall.Import.loadWith expr) status
let substituted = Dhall.Substitution.substitute expr' $ view substitutions settings
let annot = annotate substituted
_ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)
pure (Dhall.Core.normalizeWith (view normalizer settings) substituted)
rawInput
:: Alternative f
=> Decoder a
-> Expr s Void
-> f a
rawInput (Decoder {..}) expr = do
case extract (Dhall.Core.normalize expr) of
Success x -> pure x
Failure _e -> empty
detailed :: IO a -> IO a
detailed =
Control.Exception.handle handler1 . Control.Exception.handle handler0
where
handler0 :: Imported (TypeError Src Void) -> IO a
handler0 (Imported ps e) =
Control.Exception.throwIO (Imported ps (DetailedTypeError e))
handler1 :: TypeError Src Void -> IO a
handler1 e = Control.Exception.throwIO (DetailedTypeError e)
data Decoder a = Decoder
{ extract :: Expr Src Void -> Extractor Src Void a
, expected :: Expr Src Void
}
deriving (Functor)
bool :: Decoder Bool
bool = Decoder {..}
where
extract (BoolLit b) = pure b
extract expr = typeError expected expr
expected = Bool
natural :: Decoder Natural
natural = Decoder {..}
where
extract (NaturalLit n) = pure n
extract expr = typeError Natural expr
expected = Natural
integer :: Decoder Integer
integer = Decoder {..}
where
extract (IntegerLit n) = pure n
extract expr = typeError Integer expr
expected = Integer
scientific :: Decoder Scientific
scientific = fmap Data.Scientific.fromFloatDigits double
double :: Decoder Double
double = Decoder {..}
where
extract (DoubleLit (DhallDouble n)) = pure n
extract expr = typeError Double expr
expected = Double
lazyText :: Decoder Data.Text.Lazy.Text
lazyText = fmap Data.Text.Lazy.fromStrict strictText
strictText :: Decoder Text
strictText = Decoder {..}
where
extract (TextLit (Chunks [] t)) = pure t
extract expr = typeError Text expr
expected = Text
maybe :: Decoder a -> Decoder (Maybe a)
maybe (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
where
extractOut (Some e ) = fmap Just (extractIn e)
extractOut (App None _) = pure Nothing
extractOut expr = typeError expectedOut expr
expectedOut = App Optional expectedIn
sequence :: Decoder a -> Decoder (Seq a)
sequence (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
where
extractOut (ListLit _ es) = traverse extractIn es
extractOut expr = typeError expectedOut expr
expectedOut = App List expectedIn
list :: Decoder a -> Decoder [a]
list = fmap Data.Foldable.toList . sequence
vector :: Decoder a -> Decoder (Vector a)
vector = fmap Data.Vector.fromList . list
function
:: Encoder a
-> Decoder b
-> Decoder (a -> b)
function = functionWith defaultInputNormalizer
functionWith
:: InputNormalizer
-> Encoder a
-> Decoder b
-> Decoder (a -> b)
functionWith inputNormalizer (Encoder {..}) (Decoder extractIn expectedIn) =
Decoder extractOut expectedOut
where
normalizer_ = Just (getInputNormalizer inputNormalizer)
extractOut e = pure (\i -> case extractIn (Dhall.Core.normalizeWith normalizer_ (App e (embed i))) of
Success o -> o
Failure _e -> error "FromDhall: You cannot decode a function if it does not have the correct type" )
expectedOut = Pi "_" declared expectedIn
setIgnoringDuplicates :: (Ord a) => Decoder a -> Decoder (Data.Set.Set a)
setIgnoringDuplicates = fmap Data.Set.fromList . list
hashSetIgnoringDuplicates :: (Hashable a, Ord a)
=> Decoder a
-> Decoder (Data.HashSet.HashSet a)
hashSetIgnoringDuplicates = fmap Data.HashSet.fromList . list
setFromDistinctList :: (Ord a, Show a) => Decoder a -> Decoder (Data.Set.Set a)
setFromDistinctList = setHelper Data.Set.size Data.Set.fromList
hashSetFromDistinctList :: (Hashable a, Ord a, Show a)
=> Decoder a
-> Decoder (Data.HashSet.HashSet a)
hashSetFromDistinctList = setHelper Data.HashSet.size Data.HashSet.fromList
setHelper :: (Eq a, Foldable t, Show a)
=> (t a -> Int)
-> ([a] -> t a)
-> Decoder a
-> Decoder (t a)
setHelper size toSet (Decoder extractIn expectedIn) = Decoder extractOut expectedOut
where
extractOut (ListLit _ es) = case traverse extractIn es of
Success vSeq
| sameSize -> Success vSet
| otherwise -> extractError err
where
vList = Data.Foldable.toList vSeq
vSet = toSet vList
sameSize = size vSet == Data.Sequence.length vSeq
duplicates = vList Data.List.\\ Data.Foldable.toList vSet
err | length duplicates == 1 =
"One duplicate element in the list: "
<> (Data.Text.pack $ show $ head duplicates)
| otherwise = Data.Text.pack $ unwords
[ show $ length duplicates
, "duplicates were found in the list, including"
, show $ head duplicates
]
Failure f -> Failure f
extractOut expr = typeError expectedOut expr
expectedOut = App List expectedIn
map :: Ord k => Decoder k -> Decoder v -> Decoder (Map k v)
map k v = fmap Data.Map.fromList (list (pairFromMapEntry k v))
hashMap :: (Eq k, Hashable k) => Decoder k -> Decoder v -> Decoder (HashMap k v)
hashMap k v = fmap HashMap.fromList (list (pairFromMapEntry k v))
pairFromMapEntry :: Decoder k -> Decoder v -> Decoder (k, v)
pairFromMapEntry k v = Decoder extractOut expectedOut
where
extractOut (RecordLit kvs)
| Just key <- Dhall.Map.lookup "mapKey" kvs
, Just value <- Dhall.Map.lookup "mapValue" kvs
= liftA2 (,) (extract k key) (extract v value)
extractOut expr = typeError expectedOut expr
expectedOut = Record (Dhall.Map.fromList [("mapKey", expected k), ("mapValue", expected v)])
unit :: Decoder ()
unit = Decoder extractOut expectedOut
where
extractOut (RecordLit fields)
| Data.Foldable.null fields = pure ()
extractOut expr = typeError (Record mempty) expr
expectedOut = Record mempty
void :: Decoder Void
void = union mempty
string :: Decoder String
string = Data.Text.Lazy.unpack <$> lazyText
pair :: Decoder a -> Decoder b -> Decoder (a, b)
pair l r = Decoder extractOut expectedOut
where
extractOut expr@(RecordLit fields) =
(,) <$> ( Data.Maybe.maybe (typeError expectedOut expr) (extract l) $ Dhall.Map.lookup "_1" fields)
<*> ( Data.Maybe.maybe (typeError expectedOut expr) (extract r) $ Dhall.Map.lookup "_2" fields)
extractOut expr = typeError expectedOut expr
expectedOut =
Record
(Dhall.Map.fromList
[ ("_1", expected l)
, ("_2", expected r)
]
)
class FromDhall a where
autoWith :: InputNormalizer -> Decoder a
default autoWith
:: (Generic a, GenericFromDhall (Rep a)) => InputNormalizer -> Decoder a
autoWith _ = genericAuto
type Interpret = FromDhall
instance FromDhall Void where
autoWith _ = void
instance FromDhall () where
autoWith _ = unit
instance FromDhall Bool where
autoWith _ = bool
instance FromDhall Natural where
autoWith _ = natural
instance FromDhall Integer where
autoWith _ = integer
instance FromDhall Scientific where
autoWith _ = scientific
instance FromDhall Double where
autoWith _ = double
instance {-# OVERLAPS #-} FromDhall [Char] where
autoWith _ = string
instance FromDhall Data.Text.Lazy.Text where
autoWith _ = lazyText
instance FromDhall Text where
autoWith _ = strictText
instance FromDhall a => FromDhall (Maybe a) where
autoWith opts = maybe (autoWith opts)
instance FromDhall a => FromDhall (Seq a) where
autoWith opts = sequence (autoWith opts)
instance FromDhall a => FromDhall [a] where
autoWith opts = list (autoWith opts)
instance FromDhall a => FromDhall (Vector a) where
autoWith opts = vector (autoWith opts)
instance (FromDhall a, Ord a, Show a) => FromDhall (Data.Set.Set a) where
autoWith opts = setFromDistinctList (autoWith opts)
instance (FromDhall a, Hashable a, Ord a, Show a) => FromDhall (Data.HashSet.HashSet a) where
autoWith inputNormalizer = hashSetFromDistinctList (autoWith inputNormalizer)
instance (Ord k, FromDhall k, FromDhall v) => FromDhall (Map k v) where
autoWith inputNormalizer = Dhall.map (autoWith inputNormalizer) (autoWith inputNormalizer)
instance (Eq k, Hashable k, FromDhall k, FromDhall v) => FromDhall (HashMap k v) where
autoWith inputNormalizer = Dhall.hashMap (autoWith inputNormalizer) (autoWith inputNormalizer)
instance (ToDhall a, FromDhall b) => FromDhall (a -> b) where
autoWith inputNormalizer =
functionWith inputNormalizer (injectWith inputNormalizer) (autoWith inputNormalizer)
instance (FromDhall a, FromDhall b) => FromDhall (a, b)
auto :: FromDhall a => Decoder a
auto = autoWith defaultInputNormalizer
newtype Result f = Result { _unResult :: f (Result f) }
resultToFix :: Functor f => Result f -> Fix f
resultToFix (Result x) = Fix (fmap resultToFix x)
instance FromDhall (f (Result f)) => FromDhall (Result f) where
autoWith inputNormalizer = Decoder { expected = expected_, extract = extract_ }
where
expected_ = "result"
extract_ (App _ expression) = do
fmap Result (extract (autoWith inputNormalizer) expression)
extract_ expression = do
typeError expression expected_
instance (Functor f, FromDhall (f (Result f))) => FromDhall (Fix f) where
autoWith inputNormalizer = Decoder { expected = expected_, extract = extract_ }
where
expected_ =
Pi "result" (Const Dhall.Core.Type)
(Pi "Make" (Pi "_" (expected (autoWith inputNormalizer :: Decoder (f (Result f)))) "result")
"result"
)
extract_ expression0 = extract0 expression0
where
die = typeError expected_ expression0
extract0 (Lam x _ expression) = extract1 (rename x "result" expression)
extract0 _ = die
extract1 (Lam y _ expression) = extract2 (rename y "Make" expression)
extract1 _ = die
extract2 expression = fmap resultToFix (extract (autoWith inputNormalizer) expression)
rename a b expression
| a /= b = Dhall.Core.subst (V a 0) (Var (V b 0)) (Dhall.Core.shift 1 (V b 0) expression)
| otherwise = expression
genericAuto :: (Generic a, GenericFromDhall (Rep a)) => Decoder a
genericAuto = genericAutoWith defaultInterpretOptions
genericAutoWith :: (Generic a, GenericFromDhall (Rep a)) => InterpretOptions -> Decoder a
genericAutoWith options = fmap to (evalState (genericAutoWithNormalizer defaultInputNormalizer options) 1)
data InterpretOptions = InterpretOptions
{ fieldModifier :: Text -> Text
, constructorModifier :: Text -> Text
, singletonConstructors :: SingletonConstructors
}
newtype InputNormalizer = InputNormalizer
{ getInputNormalizer :: Dhall.Core.ReifiedNormalizer Void }
defaultInputNormalizer :: InputNormalizer
defaultInputNormalizer = InputNormalizer
{ getInputNormalizer = Dhall.Core.ReifiedNormalizer (const (pure Nothing)) }
data SingletonConstructors
= Bare
| Wrapped
| Smart
defaultInterpretOptions :: InterpretOptions
defaultInterpretOptions = InterpretOptions
{ fieldModifier =
id
, constructorModifier =
id
, singletonConstructors =
Smart
}
class GenericFromDhall f where
genericAutoWithNormalizer :: InputNormalizer -> InterpretOptions -> State Int (Decoder (f a))
instance GenericFromDhall f => GenericFromDhall (M1 D d f) where
genericAutoWithNormalizer inputNormalizer options = do
res <- genericAutoWithNormalizer inputNormalizer options
pure (fmap M1 res)
instance GenericFromDhall V1 where
genericAutoWithNormalizer _ _ = pure Decoder {..}
where
extract expr = typeError expected expr
expected = Union mempty
unsafeExpectUnion
:: Text -> Expr Src Void -> Dhall.Map.Map Text (Maybe (Expr Src Void))
unsafeExpectUnion _ (Union kts) =
kts
unsafeExpectUnion name expression =
Dhall.Core.internalError
(name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectRecord
:: Text -> Expr Src Void -> Dhall.Map.Map Text (Expr Src Void)
unsafeExpectRecord _ (Record kts) =
kts
unsafeExpectRecord name expression =
Dhall.Core.internalError
(name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectUnionLit
:: Text
-> Expr Src Void
-> (Text, Maybe (Expr Src Void))
unsafeExpectUnionLit _ (Field (Union _) k) =
(k, Nothing)
unsafeExpectUnionLit _ (App (Field (Union _) k) v) =
(k, Just v)
unsafeExpectUnionLit name expression =
Dhall.Core.internalError
(name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
unsafeExpectRecordLit
:: Text -> Expr Src Void -> Dhall.Map.Map Text (Expr Src Void)
unsafeExpectRecordLit _ (RecordLit kvs) =
kvs
unsafeExpectRecordLit name expression =
Dhall.Core.internalError
(name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)
notEmptyRecordLit :: Expr s a -> Maybe (Expr s a)
notEmptyRecordLit e = case e of
RecordLit m | null m -> Nothing
_ -> Just e
notEmptyRecord :: Expr s a -> Maybe (Expr s a)
notEmptyRecord e = case e of
Record m | null m -> Nothing
_ -> Just e
extractUnionConstructor
:: Expr s a -> Maybe (Text, Expr s a, Dhall.Map.Map Text (Maybe (Expr s a)))
extractUnionConstructor (App (Field (Union kts) fld) e) =
return (fld, e, Dhall.Map.delete fld kts)
extractUnionConstructor (Field (Union kts) fld) =
return (fld, RecordLit mempty, Dhall.Map.delete fld kts)
extractUnionConstructor _ =
empty
class GenericFromDhallUnion f where
genericUnionAutoWithNormalizer :: InputNormalizer -> InterpretOptions -> UnionDecoder (f a)
instance (GenericFromDhallUnion f1, GenericFromDhallUnion f2) => GenericFromDhallUnion (f1 :+: f2) where
genericUnionAutoWithNormalizer inputNormalizer options =
(<>)
(L1 <$> genericUnionAutoWithNormalizer inputNormalizer options)
(R1 <$> genericUnionAutoWithNormalizer inputNormalizer options)
instance (Constructor c1, GenericFromDhall f1) => GenericFromDhallUnion (M1 C c1 f1) where
genericUnionAutoWithNormalizer inputNormalizer options@(InterpretOptions {..}) =
constructor name (evalState (genericAutoWithNormalizer inputNormalizer options) 1)
where
n :: M1 C c1 f1 a
n = undefined
name = constructorModifier (Data.Text.pack (conName n))
instance GenericFromDhallUnion (f :+: g) => GenericFromDhall (f :+: g) where
genericAutoWithNormalizer inputNormalizer options =
pure (union (genericUnionAutoWithNormalizer inputNormalizer options))
instance GenericFromDhall f => GenericFromDhall (M1 C c f) where
genericAutoWithNormalizer inputNormalizer options = do
res <- genericAutoWithNormalizer inputNormalizer options
pure (fmap M1 res)
instance GenericFromDhall U1 where
genericAutoWithNormalizer _ _ = pure (Decoder {..})
where
extract _ = pure U1
expected = Record (Dhall.Map.fromList [])
getSelName :: Selector s => M1 i s f a -> State Int Text
getSelName n = case selName n of
"" -> do i <- get
put (i + 1)
pure (Data.Text.pack ("_" ++ show i))
nn -> pure (Data.Text.pack nn)
instance (GenericFromDhall (f :*: g), GenericFromDhall (h :*: i)) => GenericFromDhall ((f :*: g) :*: (h :*: i)) where
genericAutoWithNormalizer inputNormalizer options = do
Decoder extractL expectedL <- genericAutoWithNormalizer inputNormalizer options
Decoder extractR expectedR <- genericAutoWithNormalizer inputNormalizer options
let ktsL = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" expectedL
let ktsR = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" expectedR
let expected = Record (Dhall.Map.union ktsL ktsR)
let extract expression =
liftA2 (:*:) (extractL expression) (extractR expression)
return (Decoder {..})
instance (GenericFromDhall (f :*: g), Selector s, FromDhall a) => GenericFromDhall ((f :*: g) :*: M1 S s (K1 i a)) where
genericAutoWithNormalizer inputNormalizer options@InterpretOptions{..} = do
let nR :: M1 S s (K1 i a) r
nR = undefined
nameR <- fmap fieldModifier (getSelName nR)
Decoder extractL expectedL <- genericAutoWithNormalizer inputNormalizer options
let Decoder extractR expectedR = autoWith inputNormalizer
let ktsL = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" expectedL
let expected = Record (Dhall.Map.insert nameR expectedR ktsL)
let extract expression = do
let die = typeError expected expression
case expression of
RecordLit kvs ->
case Dhall.Map.lookup nameR kvs of
Just expressionR ->
liftA2 (:*:)
(extractL expression)
(fmap (M1 . K1) (extractR expressionR))
_ -> die
_ -> die
return (Decoder {..})
instance (Selector s, FromDhall a, GenericFromDhall (f :*: g)) => GenericFromDhall (M1 S s (K1 i a) :*: (f :*: g)) where
genericAutoWithNormalizer inputNormalizer options@InterpretOptions{..} = do
let nL :: M1 S s (K1 i a) r
nL = undefined
nameL <- fmap fieldModifier (getSelName nL)
let Decoder extractL expectedL = autoWith inputNormalizer
Decoder extractR expectedR <- genericAutoWithNormalizer inputNormalizer options
let ktsR = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" expectedR
let expected = Record (Dhall.Map.insert nameL expectedL ktsR)
let extract expression = do
let die = typeError expected expression
case expression of
RecordLit kvs ->
case Dhall.Map.lookup nameL kvs of
Just expressionL ->
liftA2 (:*:)
(fmap (M1 . K1) (extractL expressionL))
(extractR expression)
_ -> die
_ -> die
return (Decoder {..})
instance (Selector s1, Selector s2, FromDhall a1, FromDhall a2) => GenericFromDhall (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where
genericAutoWithNormalizer inputNormalizer InterpretOptions{..} = do
let nL :: M1 S s1 (K1 i1 a1) r
nL = undefined
let nR :: M1 S s2 (K1 i2 a2) r
nR = undefined
nameL <- fmap fieldModifier (getSelName nL)
nameR <- fmap fieldModifier (getSelName nR)
let Decoder extractL expectedL = autoWith inputNormalizer
let Decoder extractR expectedR = autoWith inputNormalizer
let expected =
Record
(Dhall.Map.fromList
[ (nameL, expectedL)
, (nameR, expectedR)
]
)
let extract expression = do
let die = typeError expected expression
case expression of
RecordLit kvs -> do
case liftA2 (,) (Dhall.Map.lookup nameL kvs) (Dhall.Map.lookup nameR kvs) of
Just (expressionL, expressionR) ->
liftA2 (:*:)
(fmap (M1 . K1) (extractL expressionL))
(fmap (M1 . K1) (extractR expressionR))
Nothing -> die
_ -> die
return (Decoder {..})
instance (Selector s, FromDhall a) => GenericFromDhall (M1 S s (K1 i a)) where
genericAutoWithNormalizer inputNormalizer InterpretOptions{..} = do
let n :: M1 S s (K1 i a) r
n = undefined
name <- fmap fieldModifier (getSelName n)
let Decoder { extract = extract', expected = expected'} = autoWith inputNormalizer
let expected =
case singletonConstructors of
Bare ->
expected'
Smart | selName n == "" ->
expected'
_ ->
Record (Dhall.Map.singleton name expected')
let extract0 expression = fmap (M1 . K1) (extract' expression)
let extract1 expression = do
let die = typeError expected expression
case expression of
RecordLit kvs -> do
case Dhall.Map.lookup name kvs of
Just subExpression ->
fmap (M1 . K1) (extract' subExpression)
Nothing ->
die
_ -> do
die
let extract =
case singletonConstructors of
Bare -> extract0
Smart | selName n == "" -> extract0
_ -> extract1
return (Decoder {..})
data Encoder a = Encoder
{ embed :: a -> Expr Src Void
, declared :: Expr Src Void
}
instance Contravariant Encoder where
contramap f (Encoder embed declared) = Encoder embed' declared
where
embed' x = embed (f x)
class ToDhall a where
injectWith :: InputNormalizer -> Encoder a
default injectWith
:: (Generic a, GenericToDhall (Rep a)) => InputNormalizer -> Encoder a
injectWith _ = genericToDhall
type Inject = ToDhall
inject :: ToDhall a => Encoder a
inject = injectWith defaultInputNormalizer
genericToDhall
:: (Generic a, GenericToDhall (Rep a)) => Encoder a
genericToDhall
= genericToDhallWith defaultInterpretOptions
genericToDhallWith
:: (Generic a, GenericToDhall (Rep a)) => InterpretOptions -> Encoder a
genericToDhallWith options
= contramap GHC.Generics.from (evalState (genericToDhallWithNormalizer defaultInputNormalizer options) 1)
instance ToDhall Void where
injectWith _ = Encoder {..}
where
embed = Data.Void.absurd
declared = Union mempty
instance ToDhall Bool where
injectWith _ = Encoder {..}
where
embed = BoolLit
declared = Bool
instance ToDhall Data.Text.Lazy.Text where
injectWith _ = Encoder {..}
where
embed text =
TextLit (Chunks [] (Data.Text.Lazy.toStrict text))
declared = Text
instance ToDhall Text where
injectWith _ = Encoder {..}
where
embed text = TextLit (Chunks [] text)
declared = Text
instance {-# OVERLAPS #-} ToDhall String where
injectWith inputNormalizer =
contramap Data.Text.pack (injectWith inputNormalizer :: Encoder Text)
instance ToDhall Natural where
injectWith _ = Encoder {..}
where
embed = NaturalLit
declared = Natural
instance ToDhall Integer where
injectWith _ = Encoder {..}
where
embed = IntegerLit
declared = Integer
instance ToDhall Int where
injectWith _ = Encoder {..}
where
embed = IntegerLit . toInteger
declared = Integer
instance ToDhall Word where
injectWith _ = Encoder {..}
where
embed = NaturalLit . fromIntegral
declared = Natural
instance ToDhall Word8 where
injectWith _ = Encoder {..}
where
embed = NaturalLit . fromIntegral
declared = Natural
instance ToDhall Word16 where
injectWith _ = Encoder {..}
where
embed = NaturalLit . fromIntegral
declared = Natural
instance ToDhall Word32 where
injectWith _ = Encoder {..}
where
embed = NaturalLit . fromIntegral
declared = Natural
instance ToDhall Word64 where
injectWith _ = Encoder {..}
where
embed = NaturalLit . fromIntegral
declared = Natural
instance ToDhall Double where
injectWith _ = Encoder {..}
where
embed = DoubleLit . DhallDouble
declared = Double
instance ToDhall Scientific where
injectWith inputNormalizer =
contramap Data.Scientific.toRealFloat (injectWith inputNormalizer :: Encoder Double)
instance ToDhall () where
injectWith _ = Encoder {..}
where
embed = const (RecordLit mempty)
declared = Record mempty
instance ToDhall a => ToDhall (Maybe a) where
injectWith inputNormalizer = Encoder embedOut declaredOut
where
embedOut (Just x ) = Some (embedIn x)
embedOut Nothing = App None declaredIn
Encoder embedIn declaredIn = injectWith inputNormalizer
declaredOut = App Optional declaredIn
instance ToDhall a => ToDhall (Seq a) where
injectWith inputNormalizer = Encoder embedOut declaredOut
where
embedOut xs = ListLit listType (fmap embedIn xs)
where
listType
| null xs = Just (App List declaredIn)
| otherwise = Nothing
declaredOut = App List declaredIn
Encoder embedIn declaredIn = injectWith inputNormalizer
instance ToDhall a => ToDhall [a] where
injectWith = fmap (contramap Data.Sequence.fromList) injectWith
instance ToDhall a => ToDhall (Vector a) where
injectWith = fmap (contramap Data.Vector.toList) injectWith
instance ToDhall a => ToDhall (Data.Set.Set a) where
injectWith = fmap (contramap Data.Set.toAscList) injectWith
instance ToDhall a => ToDhall (Data.HashSet.HashSet a) where
injectWith = fmap (contramap Data.HashSet.toList) injectWith
instance (ToDhall a, ToDhall b) => ToDhall (a, b)
instance (ToDhall k, ToDhall v) => ToDhall (Data.Map.Map k v) where
injectWith inputNormalizer = Encoder embedOut declaredOut
where
embedOut m = ListLit listType (mapEntries m)
where
listType
| Data.Map.null m = Just declaredOut
| otherwise = Nothing
declaredOut = App List (Record (Dhall.Map.fromList
[("mapKey", declaredK), ("mapValue", declaredV)]))
mapEntries = Data.Sequence.fromList . fmap recordPair . Data.Map.toList
recordPair (k, v) = RecordLit (Dhall.Map.fromList
[("mapKey", embedK k), ("mapValue", embedV v)])
Encoder embedK declaredK = injectWith inputNormalizer
Encoder embedV declaredV = injectWith inputNormalizer
instance (ToDhall k, ToDhall v) => ToDhall (HashMap k v) where
injectWith inputNormalizer = Encoder embedOut declaredOut
where
embedOut m = ListLit listType (mapEntries m)
where
listType
| HashMap.null m = Just declaredOut
| otherwise = Nothing
declaredOut = App List (Record (Dhall.Map.fromList
[("mapKey", declaredK), ("mapValue", declaredV)]))
mapEntries = Data.Sequence.fromList . fmap recordPair . HashMap.toList
recordPair (k, v) = RecordLit (Dhall.Map.fromList
[("mapKey", embedK k), ("mapValue", embedV v)])
Encoder embedK declaredK = injectWith inputNormalizer
Encoder embedV declaredV = injectWith inputNormalizer
class GenericToDhall f where
genericToDhallWithNormalizer :: InputNormalizer -> InterpretOptions -> State Int (Encoder (f a))
instance GenericToDhall f => GenericToDhall (M1 D d f) where
genericToDhallWithNormalizer inputNormalizer options = do
res <- genericToDhallWithNormalizer inputNormalizer options
pure (contramap unM1 res)
instance GenericToDhall f => GenericToDhall (M1 C c f) where
genericToDhallWithNormalizer inputNormalizer options = do
res <- genericToDhallWithNormalizer inputNormalizer options
pure (contramap unM1 res)
instance (Selector s, ToDhall a) => GenericToDhall (M1 S s (K1 i a)) where
genericToDhallWithNormalizer inputNormalizer InterpretOptions{..} = do
let Encoder { embed = embed', declared = declared' } =
injectWith inputNormalizer
let n :: M1 S s (K1 i a) r
n = undefined
name <- fieldModifier <$> getSelName n
let embed0 (M1 (K1 x)) = embed' x
let embed1 (M1 (K1 x)) =
RecordLit (Dhall.Map.singleton name (embed' x))
let embed =
case singletonConstructors of
Bare -> embed0
Smart | selName n == "" -> embed0
_ -> embed1
let declared =
case singletonConstructors of
Bare ->
declared'
Smart | selName n == "" ->
declared'
_ ->
Record (Dhall.Map.singleton name declared')
return (Encoder {..})
instance (Constructor c1, Constructor c2, GenericToDhall f1, GenericToDhall f2) => GenericToDhall (M1 C c1 f1 :+: M1 C c2 f2) where
genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})
where
embed (L1 (M1 l)) =
case notEmptyRecordLit (embedL l) of
Nothing ->
Field declared keyL
Just valL ->
App (Field declared keyL) valL
embed (R1 (M1 r)) =
case notEmptyRecordLit (embedR r) of
Nothing ->
Field declared keyR
Just valR ->
App (Field declared keyR) valR
declared =
Union
(Dhall.Map.fromList
[ (keyL, notEmptyRecord declaredL)
, (keyR, notEmptyRecord declaredR)
]
)
nL :: M1 i c1 f1 a
nL = undefined
nR :: M1 i c2 f2 a
nR = undefined
keyL = constructorModifier (Data.Text.pack (conName nL))
keyR = constructorModifier (Data.Text.pack (conName nR))
Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
instance (Constructor c, GenericToDhall (f :+: g), GenericToDhall h) => GenericToDhall ((f :+: g) :+: M1 C c h) where
genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})
where
embed (L1 l) =
case maybeValL of
Nothing -> Field declared keyL
Just valL -> App (Field declared keyL) valL
where
(keyL, maybeValL) =
unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedL l)
embed (R1 (M1 r)) =
case notEmptyRecordLit (embedR r) of
Nothing -> Field declared keyR
Just valR -> App (Field declared keyR) valR
nR :: M1 i c h a
nR = undefined
keyR = constructorModifier (Data.Text.pack (conName nR))
declared = Union (Dhall.Map.insert keyR (notEmptyRecord declaredR) ktsL)
Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
ktsL = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredL
instance (Constructor c, GenericToDhall f, GenericToDhall (g :+: h)) => GenericToDhall (M1 C c f :+: (g :+: h)) where
genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})
where
embed (L1 (M1 l)) =
case notEmptyRecordLit (embedL l) of
Nothing -> Field declared keyL
Just valL -> App (Field declared keyL) valL
embed (R1 r) =
case maybeValR of
Nothing -> Field declared keyR
Just valR -> App (Field declared keyR) valR
where
(keyR, maybeValR) =
unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedR r)
nL :: M1 i c f a
nL = undefined
keyL = constructorModifier (Data.Text.pack (conName nL))
declared = Union (Dhall.Map.insert keyL (notEmptyRecord declaredL) ktsR)
Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
ktsR = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredR
instance (GenericToDhall (f :+: g), GenericToDhall (h :+: i)) => GenericToDhall ((f :+: g) :+: (h :+: i)) where
genericToDhallWithNormalizer inputNormalizer options = pure (Encoder {..})
where
embed (L1 l) =
case maybeValL of
Nothing -> Field declared keyL
Just valL -> App (Field declared keyL) valL
where
(keyL, maybeValL) =
unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedL l)
embed (R1 r) =
case maybeValR of
Nothing -> Field declared keyR
Just valR -> App (Field declared keyR) valR
where
(keyR, maybeValR) =
unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedR r)
declared = Union (Dhall.Map.union ktsL ktsR)
Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1
ktsL = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredL
ktsR = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredR
instance (GenericToDhall (f :*: g), GenericToDhall (h :*: i)) => GenericToDhall ((f :*: g) :*: (h :*: i)) where
genericToDhallWithNormalizer inputNormalizer options = do
Encoder embedL declaredL <- genericToDhallWithNormalizer inputNormalizer options
Encoder embedR declaredR <- genericToDhallWithNormalizer inputNormalizer options
let embed (l :*: r) =
RecordLit (Dhall.Map.union mapL mapR)
where
mapL =
unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedL l)
mapR =
unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedR r)
let declared = Record (Dhall.Map.union mapL mapR)
where
mapL = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredL
mapR = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredR
pure (Encoder {..})
instance (GenericToDhall (f :*: g), Selector s, ToDhall a) => GenericToDhall ((f :*: g) :*: M1 S s (K1 i a)) where
genericToDhallWithNormalizer inputNormalizer options@InterpretOptions{..} = do
let nR :: M1 S s (K1 i a) r
nR = undefined
nameR <- fmap fieldModifier (getSelName nR)
Encoder embedL declaredL <- genericToDhallWithNormalizer inputNormalizer options
let Encoder embedR declaredR = injectWith inputNormalizer
let embed (l :*: M1 (K1 r)) =
RecordLit (Dhall.Map.insert nameR (embedR r) mapL)
where
mapL =
unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedL l)
let declared = Record (Dhall.Map.insert nameR declaredR mapL)
where
mapL = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredL
return (Encoder {..})
instance (Selector s, ToDhall a, GenericToDhall (f :*: g)) => GenericToDhall (M1 S s (K1 i a) :*: (f :*: g)) where
genericToDhallWithNormalizer inputNormalizer options@InterpretOptions{..} = do
let nL :: M1 S s (K1 i a) r
nL = undefined
nameL <- fmap fieldModifier (getSelName nL)
let Encoder embedL declaredL = injectWith inputNormalizer
Encoder embedR declaredR <- genericToDhallWithNormalizer inputNormalizer options
let embed (M1 (K1 l) :*: r) =
RecordLit (Dhall.Map.insert nameL (embedL l) mapR)
where
mapR =
unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedR r)
let declared = Record (Dhall.Map.insert nameL declaredL mapR)
where
mapR = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredR
return (Encoder {..})
instance (Selector s1, Selector s2, ToDhall a1, ToDhall a2) => GenericToDhall (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where
genericToDhallWithNormalizer inputNormalizer InterpretOptions{..} = do
let nL :: M1 S s1 (K1 i1 a1) r
nL = undefined
let nR :: M1 S s2 (K1 i2 a2) r
nR = undefined
nameL <- fmap fieldModifier (getSelName nL)
nameR <- fmap fieldModifier (getSelName nR)
let Encoder embedL declaredL = injectWith inputNormalizer
let Encoder embedR declaredR = injectWith inputNormalizer
let embed (M1 (K1 l) :*: M1 (K1 r)) =
RecordLit
(Dhall.Map.fromList
[ (nameL, embedL l), (nameR, embedR r) ]
)
let declared =
Record
(Dhall.Map.fromList
[ (nameL, declaredL), (nameR, declaredR) ]
)
return (Encoder {..})
instance GenericToDhall U1 where
genericToDhallWithNormalizer _ _ = pure (Encoder {..})
where
embed _ = RecordLit mempty
declared = Record mempty
newtype RecordDecoder a =
RecordDecoder
( Data.Functor.Product.Product
( Control.Applicative.Const
( Dhall.Map.Map
Text
( Expr Src Void )
)
)
( Data.Functor.Compose.Compose
( (->) ( Expr Src Void ) )
(Extractor Src Void)
)
a
)
deriving (Functor, Applicative)
record :: RecordDecoder a -> Dhall.Decoder a
record ( RecordDecoder ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Data.Functor.Compose.Compose extractF ) ) ) =
Decoder
{ extract =
extractF
, expected =
Record fields
}
field :: Text -> Decoder a -> RecordDecoder a
field key valueDecoder@(Decoder extract expected) =
let
extractBody expr@(RecordLit fields) = case Dhall.Map.lookup key fields of
Just v -> extract v
_ -> typeError expected expr
extractBody expr = typeError expected expr
in
RecordDecoder
( Data.Functor.Product.Pair
( Control.Applicative.Const
( Dhall.Map.singleton
key
( Dhall.expected valueDecoder )
)
)
( Data.Functor.Compose.Compose extractBody )
)
newtype UnionDecoder a =
UnionDecoder
( Data.Functor.Compose.Compose (Dhall.Map.Map Text) Decoder a )
deriving (Functor)
instance Data.Semigroup.Semigroup (UnionDecoder a) where
(<>) = coerce ((<>) :: Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a))
instance Monoid (UnionDecoder a) where
mempty = coerce (mempty :: Dhall.Map.Map Text (Decoder a))
mappend = (Data.Semigroup.<>)
union :: UnionDecoder a -> Decoder a
union (UnionDecoder (Data.Functor.Compose.Compose mp)) = Decoder
{ extract = extractF
, expected = Union expect
}
where
expect = (notEmptyRecord . Dhall.expected) <$> mp
extractF e0 =
let result = do
(fld, e1, rest) <- extractUnionConstructor e0
t <- Dhall.Map.lookup fld mp
guard $ Dhall.Core.Union rest `Dhall.Core.judgmentallyEqual`
Dhall.Core.Union (Dhall.Map.delete fld expect)
pure (t, e1)
in Data.Maybe.maybe (typeError (Union expect) e0) (uncurry extract) result
constructor :: Text -> Decoder a -> UnionDecoder a
constructor key valueDecoder = UnionDecoder
( Data.Functor.Compose.Compose (Dhall.Map.singleton key valueDecoder) )
(>*<) :: Divisible f => f a -> f b -> f (a, b)
(>*<) = divided
infixr 5 >*<
newtype RecordEncoder a
= RecordEncoder (Dhall.Map.Map Text (Encoder a))
instance Contravariant RecordEncoder where
contramap f (RecordEncoder encodeTypeRecord) = RecordEncoder $ contramap f <$> encodeTypeRecord
instance Divisible RecordEncoder where
divide f (RecordEncoder bEncoderRecord) (RecordEncoder cEncoderRecord) =
RecordEncoder
$ Dhall.Map.union
((contramap $ fst . f) <$> bEncoderRecord)
((contramap $ snd . f) <$> cEncoderRecord)
conquer = RecordEncoder mempty
encodeFieldWith :: Text -> Encoder a -> RecordEncoder a
encodeFieldWith name encodeType = RecordEncoder $ Dhall.Map.singleton name encodeType
encodeField :: ToDhall a => Text -> RecordEncoder a
encodeField name = encodeFieldWith name inject
recordEncoder :: RecordEncoder a -> Encoder a
recordEncoder (RecordEncoder encodeTypeRecord) = Encoder makeRecordLit recordType
where
recordType = Record $ declared <$> encodeTypeRecord
makeRecordLit x = RecordLit $ (($ x) . embed) <$> encodeTypeRecord
newtype UnionEncoder a =
UnionEncoder
( Data.Functor.Product.Product
( Control.Applicative.Const
( Dhall.Map.Map
Text
( Expr Src Void )
)
)
( Op (Text, Expr Src Void) )
a
)
deriving (Contravariant)
(>|<) :: UnionEncoder a -> UnionEncoder b -> UnionEncoder (Either a b)
UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const mx) (Op fx))
>|< UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const my) (Op fy)) =
UnionEncoder
( Data.Functor.Product.Pair
( Control.Applicative.Const (mx <> my) )
( Op (either fx fy) )
)
infixr 5 >|<
unionEncoder :: UnionEncoder a -> Encoder a
unionEncoder ( UnionEncoder ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Op embedF ) ) ) =
Encoder
{ embed = \x ->
let (name, y) = embedF x
in case notEmptyRecordLit y of
Nothing -> Field (Union fields') name
Just val -> App (Field (Union fields') name) val
, declared =
Union fields'
}
where
fields' = fmap notEmptyRecord fields
encodeConstructorWith
:: Text
-> Encoder a
-> UnionEncoder a
encodeConstructorWith name encodeType = UnionEncoder $
Data.Functor.Product.Pair
( Control.Applicative.Const
( Dhall.Map.singleton
name
( declared encodeType )
)
)
( Op ( (name,) . embed encodeType )
)
encodeConstructor
:: ToDhall a
=> Text
-> UnionEncoder a
encodeConstructor name = encodeConstructorWith name inject