aeson-qq-0.6.0: src/Data/Aeson/QQ.hs
{-# LANGUAGE TemplateHaskell #-}
-- |
-- This package expose the function `aesonQQ` that compile time converts json
-- code into a `Value`. @aesonQQ@ got the signature
--
-- > aesonQQ :: QuasiQuoter
--
-- and is used like
--
-- > myCode = [aesonQQ| {age: 23, name: "John", likes: ["linux", "Haskell"]} |]
--
-- where it is important that
--
-- * you got no space in @[aesonQQ|@ and
--
-- * no additional code after @|]@.
--
-- The quasiquatation can also bind to variables like
--
-- > myCode = [aesonQQ| {age: <|age|>, name: <|name|>} |]
-- > where age = 23 :: Integer
-- > name = "John"
--
-- where the function `toJSON` will be called on @age@ and @name@ at runtime.
--
-- You can also insert Haskell code:
--
-- > myCode = [aesonQQ| {age: <|succ age|>, name: <|map toUpper name|>} |]
-- > where age = 23 :: Integer
-- > name = "John"
--
-- If you want to replace the name of the key in a hash you'll use the $-syntax:
--
-- > foo = [aesonQQ| {$bar: 42} |]
-- > bar = "age"
module Data.Aeson.QQ (aesonQQ) where
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Control.Applicative
import qualified Data.Vector as V
import qualified Data.Text as T
import Data.Aeson
import Data.JSON.QQ as QQ
aesonQQ :: QuasiQuoter
aesonQQ = QuasiQuoter {
quoteExp = jsonExp,
quotePat = const $ error "No quotePat defined for jsonQQ",
quoteType = const $ error "No quoteType defined for jsonQQ",
quoteDec = const $ error "No quoteDec defined for jsonQQ"
}
jsonExp :: String -> ExpQ
jsonExp txt =
case parsed' of
Left err -> error $ "Error in aesonExp: " ++ show err
Right val -> toExp val
where
parsed' = QQ.parsedJson txt
----
-- JSValue etc to ExpQ
---------
toExp :: QQ.JsonValue -> ExpQ
toExp (JsonString str) = [|String (T.pack str)|]
toExp (JsonNull) = [|Null|]
toExp (JsonObject objs) = [|object $jsList|]
where
jsList :: ExpQ
jsList = ListE <$> mapM objs2list (objs)
objs2list :: (HashKey, JsonValue) -> ExpQ
objs2list (key, value) = do
case key of
HashStringKey k -> [|(T.pack k, $(toExp value))|]
HashVarKey k -> [|(T.pack $(dyn k), $(toExp value))|]
toExp (JsonArray arr) = [|Array $ V.fromList $(ListE <$> mapM toExp arr)|]
toExp (JsonNumber _ rat) = [|Number (fromRational $(return $ LitE $ RationalL rat))|]
toExp (JsonIdVar v) = dyn v
toExp (JsonBool b) = [|Bool b|]
toExp (JsonCode e) = [|toJSON $(return e)|]
-- Helpers
packE :: Exp -> ExpQ
packE e = [|T.pack $(return e)|]