{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.JsonSpec.Elm (
elmDefs,
Definitions,
HasType(..),
Named,
) where
import Bound (Scope(Scope), Var(B), abstract1, closed, toScope)
import Control.Monad.Writer (MonadTrans(lift), MonadWriter(tell),
Writer, execWriter)
import Data.JsonSpec (FieldSpec(Optional, Required),
Specification(JsonArray, JsonBool, JsonDateTime, JsonEither, JsonInt,
JsonLet, JsonNullable, JsonNum, JsonObject, JsonRef, JsonString,
JsonTag))
import Data.Proxy (Proxy(Proxy))
import Data.Set (Set)
import Data.String (IsString(fromString))
import Data.Text (Text)
import Data.Void (Void, absurd)
import GHC.TypeLits (ErrorMessage((:$$:), (:<>:)), KnownSymbol, Symbol,
TypeError, symbolVal)
import Language.Elm.Definition (Definition)
import Language.Elm.Expression ((|>), Expression, if_)
import Language.Elm.Name (Constructor, Qualified)
import Language.Elm.Type (Type)
import Prelude (Applicative(pure), Bool(False, True), Foldable(foldl,
foldr), Functor(fmap), Maybe(Just, Nothing), Monad((>>)),
Semigroup((<>)), Show(show), ($), (++), (.), (<$>), Int, error, zip)
import qualified Data.Char as Char
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified GHC.TypeLits as Lits
import qualified Language.Elm.Definition as Def
import qualified Language.Elm.Expression as Expr
import qualified Language.Elm.Name as Name
import qualified Language.Elm.Pattern as Pat
import qualified Language.Elm.Type as Type
elmDefs
:: forall spec. (HasType spec)
=> Proxy (spec :: Specification)
-> Set Definition
elmDefs :: forall (spec :: Specification).
HasType spec =>
Proxy spec -> Set Definition
elmDefs Proxy spec
_ =
Writer (Set Definition) (Expression Void) -> Set Definition
forall w a. Writer w a -> w
execWriter (Writer (Set Definition) (Expression Void) -> Set Definition)
-> Writer (Set Definition) (Expression Void) -> Set Definition
forall a b. (a -> b) -> a -> b
$ forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec Definitions (Type Any)
-> Writer (Set Definition) (Expression Void)
-> Writer (Set Definition) (Expression Void)
forall a b.
WriterT (Set Definition) Identity a
-> WriterT (Set Definition) Identity b
-> WriterT (Set Definition) Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
data FieldEncoding = FieldEncoding
{ FieldEncoding -> Bool
required :: Bool
, FieldEncoding -> Text
jsonField :: Text
, FieldEncoding -> Field
elmField :: Name.Field
, FieldEncoding -> Expression Void
encoderFun :: Expression Void
}
data FieldDecoding = FieldDecoding
{ FieldDecoding -> Text
jsonField :: Text
, FieldDecoding -> Expression Void
decoder :: Expression Void
}
class Record (spec :: [FieldSpec]) where
recordDefs :: forall v. Definitions [(Name.Field, Type v)]
recordEncoders :: Definitions [FieldEncoding]
recordDecoders :: Definitions [FieldDecoding]
instance Record '[] where
recordDefs :: forall v. Definitions [(Field, Type v)]
recordDefs = [(Field, Type v)]
-> WriterT (Set Definition) Identity [(Field, Type v)]
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
recordEncoders :: Definitions [FieldEncoding]
recordEncoders = [FieldEncoding] -> Definitions [FieldEncoding]
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
recordDecoders :: Definitions [FieldDecoding]
recordDecoders = [FieldDecoding] -> Definitions [FieldDecoding]
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
instance
( HasType spec
, KnownSymbol name
, Record more
)
=>
Record ( Required name spec : more )
where
recordDefs :: forall v. Definitions [(Field, Type v)]
recordDefs = do
type_ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
moreFields <- recordDefs @more
pure $ (fieldName (sym @name), type_) : moreFields
recordEncoders :: Definitions [FieldEncoding]
recordEncoders = do
encoder <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @spec
moreFields <- recordEncoders @more
pure $
FieldEncoding
{ required = True
, jsonField = sym @name
, elmField = fieldName (sym @name)
, encoderFun = encoder
}
: moreFields
recordDecoders :: Definitions [FieldDecoding]
recordDecoders = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
more <- recordDecoders @more
pure $
FieldDecoding
{ jsonField = sym @name
, decoder = "Json.Decode.field" `a` Expr.String (sym @name) `a` dec
}
: more
instance
( HasType spec
, KnownSymbol name
, Record more
)
=>
Record ( Optional name spec : more )
where
recordDefs :: forall v. Definitions [(Field, Type v)]
recordDefs = do
type_ <- Type v -> Type v -> Type v
forall v. Type v -> Type v -> Type v
ta Type v
"Maybe.Maybe" (Type v -> Type v)
-> WriterT (Set Definition) Identity (Type v)
-> WriterT (Set Definition) Identity (Type v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
moreFields <- recordDefs @more
pure $ (fieldName (sym @name), type_) : moreFields
recordEncoders :: Definitions [FieldEncoding]
recordEncoders = do
encoder <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @spec
moreFields <- recordEncoders @more
pure $
FieldEncoding
{ required = False
, jsonField = sym @name
, elmField = fieldName (sym @name)
, encoderFun = encoder
}
: moreFields
recordDecoders :: Definitions [FieldDecoding]
recordDecoders = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
more <- recordDecoders @more
pure $
FieldDecoding
{ jsonField = sym @name
, decoder =
"Json.Decode.maybe"
`a` ("Json.Decode.field" `a` Expr.String (sym @name) `a` dec)
}
: more
class HasType (spec :: Specification) where
typeOf :: forall v. Definitions (Type v)
decoderOf :: Definitions (Expression Void)
encoderOf :: Definitions (Expression Void)
instance HasType JsonString where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"String.String"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Decode.string"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Encode.string"
instance HasType JsonNum where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"Basics.Float"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Decode.float"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Encode.float"
instance HasType JsonInt where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"Basics.Int"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Decode.int"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Encode.int"
instance (Record fields) => HasType (JsonObject fields) where
typeOf :: forall v. Definitions (Type v)
typeOf = [(Field, Type v)] -> Type v
forall v. [(Field, Type v)] -> Type v
Type.Record ([(Field, Type v)] -> Type v)
-> WriterT (Set Definition) Identity [(Field, Type v)]
-> WriterT (Set Definition) Identity (Type v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (spec :: [FieldSpec]) v.
Record spec =>
Definitions [(Field, Type v)]
recordDefs @fields
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = do
decodings <- forall (spec :: [FieldSpec]).
Record spec =>
Definitions [FieldDecoding]
recordDecoders @fields
pure $
foldl
(\Expression Void
expr Expression Void
decoder ->
Expression Void
expr Expression Void -> Expression Void -> Expression Void
forall v. Expression v -> Expression v -> Expression v
|>
(
Expression Void
"Json.Decode.andThen" Expression Void -> Expression Void -> Expression Void
forall v. Expression v -> Expression v -> Expression v
`a`
(Expression (Var () Void) -> Expression (Var () Void))
-> Expression Void
forall a v.
(Expression (Var () a) -> Expression (Var () v)) -> Expression v
lam (\Expression (Var () Void)
var -> Expression (Var () Void)
"Json.Decode.map" Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` Expression (Var () Void)
var Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` (Void -> Var () Void
forall a. Void -> a
absurd (Void -> Var () Void)
-> Expression Void -> Expression (Var () Void)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression Void
decoder))
)
)
("Json.Decode.succeed" `a` recordConstructor ((.jsonField) <$> decodings))
((.decoder) <$> decodings)
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = do
fields <- forall (spec :: [FieldSpec]).
Record spec =>
Definitions [FieldEncoding]
recordEncoders @fields
pure $
lam (\Expression (Var () Void)
var ->
Expression (Var () Void)
"Json.Encode.object" Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a`
(
Expression (Var () Void)
"List.filterMap"
Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` Expression (Var () Void)
"Basics.identity"
Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` [Expression (Var () Void)] -> Expression (Var () Void)
forall v. [Expression v] -> Expression v
Expr.List
[ if Bool
required then
Expression (Var () Void)
"Maybe.Just" Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a`
Expression (Var () Void)
-> [Expression (Var () Void)] -> Expression (Var () Void)
forall (f :: * -> *) v.
Foldable f =>
Expression v -> f (Expression v) -> Expression v
Expr.apps Expression (Var () Void)
"Basics.,"
[
Text -> Expression (Var () Void)
forall v. Text -> Expression v
Expr.String Text
jsonField,
(Void -> Var () Void)
-> Expression Void -> Expression (Var () Void)
forall a b. (a -> b) -> Expression a -> Expression b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Void -> Var () Void
forall a. Void -> a
absurd Expression Void
encoderFun Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a`
(Field -> Expression (Var () Void)
forall v. Field -> Expression v
Expr.Proj Field
elmField Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` Expression (Var () Void)
var)
]
else
Expression (Var () Void)
"Maybe.map"
Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` (Expression (Var () (Var () Void))
-> Expression (Var () (Var () Void)))
-> Expression (Var () Void)
forall a v.
(Expression (Var () a) -> Expression (Var () v)) -> Expression v
lam (\Expression (Var () (Var () Void))
inner ->
Expression (Var () (Var () Void))
-> [Expression (Var () (Var () Void))]
-> Expression (Var () (Var () Void))
forall (f :: * -> *) v.
Foldable f =>
Expression v -> f (Expression v) -> Expression v
Expr.apps Expression (Var () (Var () Void))
"Basics.,"
[
Text -> Expression (Var () (Var () Void))
forall v. Text -> Expression v
Expr.String Text
jsonField,
(Void -> Var () (Var () Void))
-> Expression Void -> Expression (Var () (Var () Void))
forall a b. (a -> b) -> Expression a -> Expression b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Void -> Var () (Var () Void)
forall a. Void -> a
absurd Expression Void
encoderFun Expression (Var () (Var () Void))
-> Expression (Var () (Var () Void))
-> Expression (Var () (Var () Void))
forall v. Expression v -> Expression v -> Expression v
`a` Expression (Var () (Var () Void))
inner
]
)
Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` (Field -> Expression (Var () Void)
forall v. Field -> Expression v
Expr.Proj Field
elmField Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
`a` Expression (Var () Void)
var)
| FieldEncoding {Bool
required :: FieldEncoding -> Bool
required :: Bool
required, Text
jsonField :: FieldEncoding -> Text
jsonField :: Text
jsonField, Field
elmField :: FieldEncoding -> Field
elmField :: Field
elmField, Expression Void
encoderFun :: FieldEncoding -> Expression Void
encoderFun :: Expression Void
encoderFun}
<- [FieldEncoding]
fields
]
)
)
instance (HasType spec) => HasType (JsonArray spec) where
typeOf :: forall v. Definitions (Type v)
typeOf = do
elemType <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
pure $ "Basics.List" `ta` elemType
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
pure $ "Json.Decode.list" `a` dec
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = do
encoder <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @spec
pure $ "Json.Encode.list" `a` encoder
instance HasType JsonBool where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"Basics.Bool"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Decode.bool"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf =
Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Json.Encode.bool"
instance (HasType spec) => HasType (JsonNullable spec) where
typeOf :: forall v. Definitions (Type v)
typeOf = do
type_ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
pure $ "Maybe.Maybe" `ta` type_
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
pure $ a "Json.Decode.nullable" dec
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = do
encoder <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @spec
pure $
Expr.Lam . toScope $
Expr.apps
"Maybe.withDefault"
[ "Json.Encode.null"
, Expr.apps
"Maybe.map"
[ fmap absurd encoder
, Expr.Var (B ())
]
]
instance (KnownSymbol const) => HasType (JsonTag const) where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"Basics.()"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf =
Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression Void -> Writer (Set Definition) (Expression Void))
-> Expression Void -> Writer (Set Definition) (Expression Void)
forall a b. (a -> b) -> a -> b
$
Expression Void
"Json.Decode.string"
Expression Void -> Expression Void -> Expression Void
forall v. Expression v -> Expression v -> Expression v
|> Expression Void -> [Expression Void] -> Expression Void
forall (f :: * -> *) v.
Foldable f =>
Expression v -> f (Expression v) -> Expression v
Expr.apps Expression Void
"Json.Decode.andThen"
[ Scope () Expression Void -> Expression Void
forall v. Scope () Expression v -> Expression v
Expr.Lam (Scope () Expression Void -> Expression Void)
-> (Expression (Var () Void) -> Scope () Expression Void)
-> Expression (Var () Void)
-> Expression Void
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expression (Var () Void) -> Scope () Expression Void
forall (f :: * -> *) b a. Monad f => f (Var b a) -> Scope b f a
toScope (Expression (Var () Void) -> Expression Void)
-> Expression (Var () Void) -> Expression Void
forall a b. (a -> b) -> a -> b
$
Expression (Var () Void)
-> Expression (Var () Void)
-> Expression (Var () Void)
-> Expression (Var () Void)
forall v.
Expression v -> Expression v -> Expression v -> Expression v
if_
(
Expression (Var () Void)
-> [Expression (Var () Void)] -> Expression (Var () Void)
forall (f :: * -> *) v.
Foldable f =>
Expression v -> f (Expression v) -> Expression v
Expr.apps
Expression (Var () Void)
"Basics.=="
[ Var () Void -> Expression (Var () Void)
forall v. v -> Expression v
Expr.Var (() -> Var () Void
forall b a. b -> Var b a
B ())
, Text -> Expression (Var () Void)
forall v. Text -> Expression v
Expr.String (forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @const)
]
)
(Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
a Expression (Var () Void)
"Json.Decode.succeed" Expression (Var () Void)
"Basics.()")
(Expression (Var () Void)
-> Expression (Var () Void) -> Expression (Var () Void)
forall v. Expression v -> Expression v -> Expression v
a Expression (Var () Void)
"Json.Decode.fail" (Text -> Expression (Var () Void)
forall v. Text -> Expression v
Expr.String Text
"Tag mismatch"))
]
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf =
Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression Void -> Writer (Set Definition) (Expression Void))
-> Expression Void -> Writer (Set Definition) (Expression Void)
forall a b. (a -> b) -> a -> b
$
Expression Void
"Basics.always" Expression Void -> Expression Void -> Expression Void
forall v. Expression v -> Expression v -> Expression v
`a`
(Expression Void
"Json.Encode.string" Expression Void -> Expression Void -> Expression Void
forall v. Expression v -> Expression v -> Expression v
`a` Text -> Expression Void
forall v. Text -> Expression v
Expr.String (forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @const))
instance HasType JsonDateTime where
typeOf :: forall v. Definitions (Type v)
typeOf = Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type v
"Time.Posix"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Iso8601.decoder"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Expression Void
"Iso8601.encode"
instance (KnownSymbol name) => HasType (JsonRef name) where
typeOf :: forall v. Definitions (Type v)
typeOf =
Type v -> WriterT (Set Definition) Identity (Type v)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
(Type v -> WriterT (Set Definition) Identity (Type v))
-> (Text -> Type v)
-> Text
-> WriterT (Set Definition) Identity (Type v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Qualified -> Type v
forall v. Qualified -> Type v
Type.Global
(Qualified -> Type v) -> (Text -> Qualified) -> Text -> Type v
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Qualified
localName
(Text -> WriterT (Set Definition) Identity (Type v))
-> Text -> WriterT (Set Definition) Identity (Type v)
forall a b. (a -> b) -> a -> b
$ forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @name
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf =
Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression Void -> Writer (Set Definition) (Expression Void))
-> (Qualified -> Expression Void)
-> Qualified
-> Writer (Set Definition) (Expression Void)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Qualified -> Expression Void
forall v. Qualified -> Expression v
Expr.Global (Qualified -> Writer (Set Definition) (Expression Void))
-> Qualified -> Writer (Set Definition) (Expression Void)
forall a b. (a -> b) -> a -> b
$ forall (name :: Symbol). KnownSymbol name => Qualified
decoderName @name
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf =
Expression Void -> Writer (Set Definition) (Expression Void)
forall a. a -> WriterT (Set Definition) Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Expression Void -> Writer (Set Definition) (Expression Void))
-> (Qualified -> Expression Void)
-> Qualified
-> Writer (Set Definition) (Expression Void)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Qualified -> Expression Void
forall v. Qualified -> Expression v
Expr.Global (Qualified -> Writer (Set Definition) (Expression Void))
-> Qualified -> Writer (Set Definition) (Expression Void)
forall a b. (a -> b) -> a -> b
$ forall (name :: Symbol). KnownSymbol name => Qualified
encoderName @name
instance (HasType spec) => HasType (JsonLet '[] spec) where
typeOf :: forall v. Definitions (Type v)
typeOf = forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @spec
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @spec
instance
( HasDef def
, HasType (JsonLet more spec)
)
=>
HasType (JsonLet ( def : more ) spec)
where
typeOf :: forall v. Definitions (Type v)
typeOf = do
forall (def :: (Symbol, Specification)).
HasDef def =>
Definitions ()
defs @def
forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @(JsonLet more spec)
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = do
forall (def :: (Symbol, Specification)).
HasDef def =>
Definitions ()
defs @def
forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @(JsonLet more spec)
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = do
forall (def :: (Symbol, Specification)).
HasDef def =>
Definitions ()
defs @def
forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @(JsonLet more spec)
instance
(TypeError AnonSumTypeError)
=>
HasType (JsonEither left right)
where
typeOf :: forall v. Definitions (Type v)
typeOf = String -> Definitions (Type v)
forall a. HasCallStack => String -> a
error String
"undefinable"
decoderOf :: Writer (Set Definition) (Expression Void)
decoderOf = String -> Writer (Set Definition) (Expression Void)
forall a. HasCallStack => String -> a
error String
"undefinable"
encoderOf :: Writer (Set Definition) (Expression Void)
encoderOf = String -> Writer (Set Definition) (Expression Void)
forall a. HasCallStack => String -> a
error String
"undefinable"
type family LambdaDepth (record :: [k]) where
LambdaDepth '[] = Void
LambdaDepth (a : more) =
Bound.Var () (LambdaDepth more)
type family Reverse (l :: [k]) where
Reverse '[] = '[]
Reverse (a : more) = Concat (Reverse more) '[a]
type family Concat (a :: [k]) (b :: [k]) where
Concat '[] b = b
Concat (a : more) b =
a : Concat more b
class HasDef (def :: (Symbol, Specification)) where
defs :: Definitions ()
instance
( KnownSymbol name
, SumDef (JsonEither left right)
)
=>
HasDef '(name, JsonEither left right)
where
defs :: Definitions ()
defs = do
branches <- forall (spec :: Specification) v.
SumDef spec =>
Definitions [(Maybe Text, Type v)]
sumDef @(JsonEither left right)
let
constructors :: [(Constructor, [Scope Int Type Void])]
constructors =
[ ( Text -> Constructor
Name.Constructor (Maybe Text -> Int -> Text
constructorName Maybe Text
conName Int
n)
, [Type (Var Int (Type Void)) -> Scope Int Type Void
forall b (f :: * -> *) a. f (Var b (f a)) -> Scope b f a
Scope Type (Var Int (Type Void))
type_]
)
| (Int
n, (Maybe Text
conName, Type (Var Int (Type Void))
type_)) <- [Int]
-> [(Maybe Text, Type (Var Int (Type Void)))]
-> [(Int, (Maybe Text, Type (Var Int (Type Void))))]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
1..] [(Maybe Text, Type (Var Int (Type Void)))]
branches
]
decoders <- sumDecoders @(JsonEither left right)
encoders <- sumEncoders @(JsonEither left right)
tell . Set.fromList $
[ Def.Type (localName name) 0 constructors
, Def.Constant
(decoderName @name)
0
(Scope ("Json.Decode.Decoder" `ta` Type.Global (localName name)))
(
"Json.Decode.oneOf"
`a`
Expr.List
[ "Json.Decode.map"
`a` Expr.Global (localName (constructorName conName n))
`a` dec
| (n, (conName, dec)) <- zip [1..] decoders
]
)
, Def.Constant
(encoderName @name)
0
(
toScope $
Type.Fun
(Type.Global (localName name))
"Json.Encode.Value"
)
(
Expr.Lam . toScope $
Expr.Case
(Expr.Var (B ()))
[ ( Pat.Con
(localName (constructorName conName n))
[Pat.Var 0]
, toScope $
fmap absurd encoder `a`
Expr.Var (B (0 :: Int))
)
| (n, (conName, encoder)) <- zip [1..] encoders
]
)
]
where
constructorName :: Maybe Text -> Int -> Text
constructorName :: Maybe Text -> Int -> Text
constructorName = \cases
Maybe Text
Nothing Int
n -> Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a b. (Show a, IsString b) => a -> b
showt Int
n
(Just Text
consName) Int
_ -> Text
consName
name :: Text
name :: Text
name = forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @name
instance
( HasType spec
, KnownSymbol consName
, KnownSymbol name
)
=>
HasDef '(name, Named consName spec)
where
defs :: Definitions ()
defs = do
typ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
dec <- decoderOf @spec
enc <- encoderOf @spec
tell . Set.fromList $
[ Def.Type (localName (sym @name)) 0
[ ( Name.Constructor (sym @consName)
, [ lift typ ]
)
]
, Def.Constant
(decoderName @name)
0
( Scope
(
"Json.Decode.Decoder" `ta`
Type.Global (localName (sym @name))
)
)
( "Json.Decode.map"
`a` Expr.Global (localName (sym @consName))
`a` dec
)
, Def.Constant
(encoderName @name)
0
( Scope
( Type.Fun
(Type.Global $ localName (sym @name))
"Json.Encode.Value"
)
)
( lam $ \Expression (Var () Void)
var ->
Expression (Var () Void)
-> [(Pattern Int, Scope Int Expression (Var () Void))]
-> Expression (Var () Void)
forall v.
Expression v
-> [(Pattern Int, Scope Int Expression v)] -> Expression v
Expr.Case
Expression (Var () Void)
var
[ (Qualified -> [Pattern Int] -> Pattern Int
forall v. Qualified -> [Pattern v] -> Pattern v
Pat.Con
(Text -> Qualified
localName (forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @consName))
[ Int -> Pattern Int
forall v. v -> Pattern v
Pat.Var Int
0 ]
, Expression (Var Int (Var () Void))
-> Scope Int Expression (Var () Void)
forall (f :: * -> *) b a. Monad f => f (Var b a) -> Scope b f a
toScope (Expression (Var Int (Var () Void))
-> Scope Int Expression (Var () Void))
-> Expression (Var Int (Var () Void))
-> Scope Int Expression (Var () Void)
forall a b. (a -> b) -> a -> b
$
(Void -> Var Int (Var () Void)
forall a. Void -> a
absurd (Void -> Var Int (Var () Void))
-> Expression Void -> Expression (Var Int (Var () Void))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression Void
enc) Expression (Var Int (Var () Void))
-> Expression (Var Int (Var () Void))
-> Expression (Var Int (Var () Void))
forall v. Expression v -> Expression v -> Expression v
`a` Var Int (Var () Void) -> Expression (Var Int (Var () Void))
forall v. v -> Expression v
Expr.Var (Int -> Var Int (Var () Void)
forall b a. b -> Var b a
B Int
0)
)
]
)
]
instance
{-# overlaps #-} (HasType spec, KnownSymbol name)
=>
HasDef '(name, spec)
where
defs :: Definitions ()
defs = do
type_ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @spec
dec <- decoderOf @spec
enc <- encoderOf @spec
tell . Set.fromList $
[ Def.Alias
(localName (sym @name))
0
(Scope type_)
, Def.Constant
(decoderName @name)
0
( Scope
(
"Json.Decode.Decoder" `ta`
Type.Global (localName (sym @name))
)
)
dec
, Def.Constant
(encoderName @name)
0
( Scope
( Type.Fun
(Type.Global $ localName (sym @name))
"Json.Encode.Value"
)
)
enc
]
class SumDef (spec :: Specification) where
sumDef :: forall v. Definitions [(Maybe Text, Type v)]
sumDecoders :: Definitions [(Maybe Text, Expression Void)]
sumEncoders :: Definitions [(Maybe Text, Expression Void)]
instance
(SumDef left, SumDef right)
=>
SumDef (JsonEither left right)
where
sumDef :: forall v. Definitions [(Maybe Text, Type v)]
sumDef = do
left <- forall (spec :: Specification) v.
SumDef spec =>
Definitions [(Maybe Text, Type v)]
sumDef @left
right <- sumDef @right
pure $ left ++ right
sumDecoders :: Definitions [(Maybe Text, Expression Void)]
sumDecoders = do
left <- forall (spec :: Specification).
SumDef spec =>
Definitions [(Maybe Text, Expression Void)]
sumDecoders @left
right <- sumDecoders @right
pure (left ++ right)
sumEncoders :: Definitions [(Maybe Text, Expression Void)]
sumEncoders = do
left <- forall (spec :: Specification).
SumDef spec =>
Definitions [(Maybe Text, Expression Void)]
sumEncoders @left
right <- sumEncoders @right
pure (left ++ right)
instance
( HasType def
, KnownSymbol name
)
=>
SumDef (JsonLet '[ '(name, def) ] (JsonRef name))
where
sumDef :: forall v. Definitions [(Maybe Text, Type v)]
sumDef = do
typ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @def
pure [(Just (sym @name), typ)]
sumDecoders :: Definitions [(Maybe Text, Expression Void)]
sumDecoders = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @def
pure [(Just (sym @name), dec)]
sumEncoders :: Definitions [(Maybe Text, Expression Void)]
sumEncoders = do
enc <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @def
pure [(Just (sym @name), enc)]
instance {-# overlaps #-} (HasType a) => SumDef a where
sumDef :: forall v. Definitions [(Maybe Text, Type v)]
sumDef = do
typ <- forall (spec :: Specification) v.
HasType spec =>
Definitions (Type v)
typeOf @a
pure [(Nothing, typ)]
sumDecoders :: Definitions [(Maybe Text, Expression Void)]
sumDecoders = do
dec <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
decoderOf @a
pure [(Nothing, dec)]
sumEncoders :: Definitions [(Maybe Text, Expression Void)]
sumEncoders = do
enc <- forall (spec :: Specification).
HasType spec =>
Writer (Set Definition) (Expression Void)
encoderOf @a
pure [(Nothing, enc)]
localName :: Text -> Qualified
localName :: Text -> Qualified
localName =
[Text] -> Text -> Qualified
Name.Qualified [Text
"Api", Text
"Data"]
type Definitions = Writer (Set Definition)
sym :: forall a b. (KnownSymbol a, IsString b) => b
sym :: forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym = String -> b
forall a. IsString a => String -> a
fromString (String -> b) -> String -> b
forall a b. (a -> b) -> a -> b
$ Proxy a -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @a)
showt :: (Show a, IsString b) => a -> b
showt :: forall a b. (Show a, IsString b) => a -> b
showt = String -> b
forall a. IsString a => String -> a
fromString (String -> b) -> (a -> String) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show
lower :: Text -> Text
lower :: Text -> Text
lower Text
txt =
case Text -> Maybe (Char, Text)
Text.uncons Text
txt of
Maybe (Char, Text)
Nothing -> Text
txt
Just (Char
c, Text
more) -> Char -> Text -> Text
Text.cons (Char -> Char
Char.toLower Char
c) Text
more
decoderName :: forall name. (KnownSymbol name) => Qualified
decoderName :: forall (name :: Symbol). KnownSymbol name => Qualified
decoderName = Text -> Qualified
localName (Text -> Text
lower (forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @name) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Decoder")
encoderName :: forall name. (KnownSymbol name) => Qualified
encoderName :: forall (name :: Symbol). KnownSymbol name => Qualified
encoderName = Text -> Qualified
localName (Text -> Text
lower (forall (a :: Symbol) b. (KnownSymbol a, IsString b) => b
sym @name) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Encoder")
fieldName :: Text -> Name.Field
fieldName :: Text -> Field
fieldName Text
specName =
Text -> Field
Name.Field (Text -> Field) -> Text -> Field
forall a b. (a -> b) -> a -> b
$
case Text
specName of
Text
"type" -> Text
"type_"
Text
other -> HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
Text.replace Text
"-" Text
"_" Text
other
a :: Expression v -> Expression v -> Expression v
a :: forall v. Expression v -> Expression v -> Expression v
a = Expression v -> Expression v -> Expression v
forall v. Expression v -> Expression v -> Expression v
Expr.App
ta :: Type v -> Type v -> Type v
ta :: forall v. Type v -> Type v -> Type v
ta = Type v -> Type v -> Type v
forall v. Type v -> Type v -> Type v
Type.App
recordConstructor :: [Text] -> Expression v
recordConstructor :: forall v. [Text] -> Expression v
recordConstructor [Text]
records =
case
Expression Text -> Maybe (Expression v)
forall (f :: * -> *) a b. Traversable f => f a -> Maybe (f b)
closed (Expression Text -> Maybe (Expression v))
-> Expression Text -> Maybe (Expression v)
forall a b. (a -> b) -> a -> b
$
(Text -> Expression Text -> Expression Text)
-> Expression Text -> [Text] -> Expression Text
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
(\Text
field Expression Text
expr ->
Scope () Expression Text -> Expression Text
forall v. Scope () Expression v -> Expression v
Expr.Lam (Scope () Expression Text -> Expression Text)
-> Scope () Expression Text -> Expression Text
forall a b. (a -> b) -> a -> b
$ Text -> Expression Text -> Scope () Expression Text
forall (f :: * -> *) a. (Monad f, Eq a) => a -> f a -> Scope () f a
abstract1 Text
field Expression Text
expr
)
Expression Text
unboundRecord
[Text]
records
of
Maybe (Expression v)
Nothing -> String -> Expression v
forall a. HasCallStack => String -> a
error String
"can't happen"
Just Expression v
expr -> Expression v
expr
where
unboundRecord :: Expression Text
unboundRecord :: Expression Text
unboundRecord =
[(Field, Expression Text)] -> Expression Text
forall v. [(Field, Expression v)] -> Expression v
Expr.Record
[ (Text -> Field
fieldName Text
field, Text -> Expression Text
forall v. v -> Expression v
Expr.Var Text
field)
| Text
field <- [Text]
records
]
lam
:: (Expression (Var () a) -> Expression (Var () v))
-> Expression v
lam :: forall a v.
(Expression (Var () a) -> Expression (Var () v)) -> Expression v
lam Expression (Var () a) -> Expression (Var () v)
f =
Scope () Expression v -> Expression v
forall v. Scope () Expression v -> Expression v
Expr.Lam (Scope () Expression v -> Expression v)
-> (Expression (Var () v) -> Scope () Expression v)
-> Expression (Var () v)
-> Expression v
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expression (Var () v) -> Scope () Expression v
forall (f :: * -> *) b a. Monad f => f (Var b a) -> Scope b f a
toScope (Expression (Var () v) -> Expression v)
-> Expression (Var () v) -> Expression v
forall a b. (a -> b) -> a -> b
$ Expression (Var () a) -> Expression (Var () v)
f (Var () a -> Expression (Var () a)
forall v. v -> Expression v
Expr.Var (() -> Var () a
forall b a. b -> Var b a
B ()))
type Named name def = JsonLet '[ '(name, def) ] (JsonRef name)
type AnonSumTypeError =
( Lits.Text "Elm doesn't support anonymous sum types, so if you "
:<>: Lits.Text "want to use (possibly nested) `JsonEither` "
:<>: Lits.Text "you must give it a name using `JsonLet`, e.g:"
:$$: Lits.Text ""
:$$: Lits.Text "> JsonLet"
:$$: Lits.Text "> '[ '( \"MySum\""
:$$: Lits.Text "> , JsonEither"
:$$: Lits.Text "> ( JsonEither"
:$$: Lits.Text "> JsonInt"
:$$: Lits.Text "> JsonString"
:$$: Lits.Text "> )"
:$$: Lits.Text "> ( JsonEither"
:$$: Lits.Text "> JsonFloat"
:$$: Lits.Text "> JsonBool"
:$$: Lits.Text "> )"
:$$: Lits.Text "> )"
:$$: Lits.Text "> ]"
:$$: Lits.Text "> (JsonRef \"MySum\")"
:$$: Lits.Text ""
:$$: Lits.Text "This will produce the Elm type"
:$$: Lits.Text ""
:$$: Lits.Text "> type MySum"
:$$: Lits.Text "> = MySum_1 Int"
:$$: Lits.Text "> | MySum_2 String"
:$$: Lits.Text "> | MySum_3 Float"
:$$: Lits.Text "> | MySum_4 Bool"
:$$: Lits.Text ""
)