{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Waargonaut.Types.Json
(
JType (..)
, AsJType (..)
, Json (..)
, waargonautBuilder
, parseWaargonaut
, jsonTraversal
, jsonWSTraversal
, jtypeTraversal
, jtypeWSTraversal
) where
import Prelude (Eq, Show)
import Control.Applicative (pure, (<$>), (<*>), (<|>))
import Control.Category (id, (.))
import Control.Lens (Prism', Rewrapped, Traversal,
Traversal', Wrapped (..), iso,
prism, traverseOf, _Wrapped)
import Control.Monad (Monad)
import Data.Bifoldable (Bifoldable (bifoldMap))
import Data.Bifunctor (Bifunctor (bimap))
import Data.Bitraversable (Bitraversable (bitraverse))
import Data.Bool (Bool (..))
import Data.Distributive (distribute)
import Data.Either (Either (..))
import Data.Foldable (Foldable (..), asum)
import Data.Function (flip)
import Data.Functor (Functor (..))
import Data.Monoid (Monoid (..))
import Data.Semigroup ((<>))
import Data.Traversable (Traversable (..))
import Data.Tuple (uncurry)
import Data.ByteString.Builder (Builder)
import qualified Data.ByteString.Builder as BB
import Text.Parser.Char (CharParsing, text)
import Waargonaut.Types.JArray (JArray (..), jArrayBuilder,
parseJArray)
import Waargonaut.Types.JNumber (JNumber, jNumberBuilder,
parseJNumber)
import Waargonaut.Types.JObject (JObject (..), jObjectBuilder,
parseJObject)
import Waargonaut.Types.JString (JString, jStringBuilder,
parseJString)
import Waargonaut.Types.Whitespace (WS (..), parseWhitespace)
data JType ws a
= JNull ws
| JBool Bool ws
| JNum JNumber ws
| JStr JString ws
| JArr (JArray ws a) ws
| JObj (JObject ws a) ws
deriving (Eq, Show, Functor, Foldable, Traversable)
instance Bifunctor JType where
bimap f g jt = case jt of
JNull ws -> JNull (f ws)
JBool b ws -> JBool b (f ws)
JNum n ws -> JNum n (f ws)
JStr s ws -> JStr s (f ws)
JArr a ws -> JArr (bimap f g a) (f ws)
JObj o ws -> JObj (bimap f g o) (f ws)
instance Bifoldable JType where
bifoldMap f g jt = case jt of
JNull ws -> f ws
JBool _ ws -> f ws
JNum _ ws -> f ws
JStr _ ws -> f ws
JArr a ws -> bifoldMap f g a `mappend` f ws
JObj o ws -> bifoldMap f g o `mappend` f ws
instance Bitraversable JType where
bitraverse f g jt = case jt of
JNull ws -> JNull <$> f ws
JBool b ws -> JBool b <$> f ws
JNum n ws -> JNum n <$> f ws
JStr s ws -> JStr s <$> f ws
JArr a ws -> JArr <$> bitraverse f g a <*> f ws
JObj o ws -> JObj <$> bitraverse f g o <*> f ws
class AsJType r ws a | r -> ws a where
_JType :: Prism' r (JType ws a)
_JNull :: Prism' r ws
_JBool :: Prism' r (Bool, ws)
_JNum :: Prism' r (JNumber, ws)
_JStr :: Prism' r (JString, ws)
_JArr :: Prism' r (JArray ws a, ws)
_JObj :: Prism' r (JObject ws a, ws)
_JNull = _JType . _JNull
_JBool = _JType . _JBool
_JNum = _JType . _JNum
_JStr = _JType . _JStr
_JArr = _JType . _JArr
_JObj = _JType . _JObj
instance AsJType (JType ws a) ws a where
_JType = id
_JNull = prism JNull
(\ x -> case x of
JNull ws -> Right ws
_ -> Left x
)
_JBool = prism (uncurry JBool)
(\ x -> case x of
JBool j ws -> Right (j, ws)
_ -> Left x
)
_JNum = prism (uncurry JNum)
(\ x -> case x of
JNum j ws -> Right (j, ws)
_ -> Left x
)
_JStr = prism (uncurry JStr)
(\ x -> case x of
JStr j ws -> Right (j, ws)
_ -> Left x
)
_JArr = prism (uncurry JArr)
(\ x -> case x of
JArr j ws -> Right (j, ws)
_ -> Left x
)
_JObj = prism (uncurry JObj)
(\ x -> case x of
JObj j ws -> Right (j, ws)
_ -> Left x
)
newtype Json
= Json (JType WS Json)
deriving (Eq, Show)
instance Json ~ t => Rewrapped Json t
instance Wrapped Json where
type Unwrapped Json = JType WS Json
_Wrapped' = iso (\(Json x) -> x) Json
instance AsJType Json WS Json where
_JType = _Wrapped . _JType
jsonTraversal :: Traversal' Json Json
jsonTraversal = traverseOf (_Wrapped . jtypeTraversal)
jsonWSTraversal :: Traversal Json Json WS WS
jsonWSTraversal = traverseOf (_Wrapped . jtypeWSTraversal)
jtypeWSTraversal :: Traversal (JType ws a) (JType ws' a) ws ws'
jtypeWSTraversal = flip bitraverse pure
jtypeTraversal :: Traversal (JType ws a) (JType ws a') a a'
jtypeTraversal = bitraverse pure
jTypesBuilder
:: (WS -> Builder)
-> JType WS Json
-> BB.Builder
jTypesBuilder s (JNull tws) = BB.stringUtf8 "null" <> s tws
jTypesBuilder s (JBool b tws) = BB.stringUtf8 (if b then "true" else "false") <> s tws
jTypesBuilder s (JNum jn tws) = jNumberBuilder jn <> s tws
jTypesBuilder s (JStr js tws) = jStringBuilder js <> s tws
jTypesBuilder s (JArr js tws) = jArrayBuilder s waargonautBuilder js <> s tws
jTypesBuilder s (JObj jobj tws) = jObjectBuilder s waargonautBuilder jobj <> s tws
parseJNull
:: ( CharParsing f
)
=> f ws
-> f (JType ws a)
parseJNull ws = JNull
<$ text "null"
<*> ws
parseJBool
:: ( CharParsing f
)
=> f ws
-> f (JType ws a)
parseJBool ws =
let
b q t = JBool q <$ text t
in
(b False "false" <|> b True "true") <*> ws
parseJNum
:: ( Monad f
, CharParsing f
)
=> f ws
-> f (JType ws a)
parseJNum ws =
JNum <$> parseJNumber <*> ws
parseJStr
:: CharParsing f
=> f ws
-> f (JType ws a)
parseJStr ws =
JStr <$> parseJString <*> ws
parseJArr
:: ( Monad f
, CharParsing f
)
=> f ws
-> f (JType ws Json)
parseJArr ws =
JArr <$> parseJArray ws parseWaargonaut <*> ws
parseJObj
:: ( Monad f
, CharParsing f
)
=> f ws
-> f (JType ws Json)
parseJObj ws =
JObj <$> parseJObject ws parseWaargonaut <*> ws
parseJType
:: ( Monad f
, CharParsing f
)
=> f ws
-> f (JType ws Json)
parseJType =
asum . distribute
[ parseJNull
, parseJBool
, parseJNum
, parseJStr
, parseJArr
, parseJObj
]
waargonautBuilder
:: (WS -> Builder)
-> Json
-> Builder
waargonautBuilder ws (Json jt) =
jTypesBuilder ws jt
parseWaargonaut
:: ( Monad f
, CharParsing f
)
=> f Json
parseWaargonaut =
Json <$> parseJType parseWhitespace