<commit_before>{-# LANGUAGE NoImplicitPrelude, TemplateHaskell #-}

{-|
Module:      Data.Aeson.TH
License:     Apache
Stability:   experimental
Portability: portable

Functions to mechanically derive 'ToJSON' and 'FromJSON' instances. Note that
you need to enable the @TemplateHaskell@ language extension in order to use this
module.

An example shows how instances are generated for arbitrary data types. First we
define a data type:

@
data D a = Nullary
         | Unary Int
         | Product String Char a
         | Record { testOne   :: Double
                  , testTwo   :: Bool
                  , testThree :: D a
                  } deriving Eq
@

Next we derive the necessary instances. Note that we make use of the feature to
change record field names. In this case we drop the first 4 characters of every
field name.

@
$('deriveJSON' ('drop' 4) ''D)
@

This will result in the following (simplified) code to be spliced in your program:

@
import Control.Applicative
import Control.Monad
import Data.Aeson
import Data.Aeson.TH
import qualified Data.Map    as M
import qualified Data.Text   as T
import qualified Data.Vector as V

instance 'ToJSON' a => 'ToJSON' (D a) where
    'toJSON' =
      \value ->
        case value of
          Nullary ->
              'object' ['T.pack' \"Nullary\" .= 'toJSON' ([] :: [()])]
          Unary arg1 ->
              'object' ['T.pack' \"Unary\" .= 'toJSON' arg1]
          Product arg1 arg2 arg3 ->
              'object' [ 'T.pack' \"Product\"
                       .= 'toJSON' [ 'toJSON' arg1
                                 , 'toJSON' arg2
                                 , 'toJSON' arg3
                                 ]
                     ]
          Record arg1 arg2 arg3 ->
              'object' [ 'T.pack' \"Record\"
                       .= 'object' [ 'T.pack' \"One\"   '.=' arg1
                                 , 'T.pack' \"Two\"   '.=' arg2
                                 , 'T.pack' \"Three\" '.=' arg3
                                 ]
                     ]
@

@
instance 'FromJSON' a => 'FromJSON' (D a) where
    'parseJSON' =
      \value ->
        case value of
          'Object' obj ->
            case 'M.toList' obj of
              [(conKey, conVal)] ->
                  case conKey of
                    _ | (conKey '==' 'T.pack' \"Nullary\") ->
                          case conVal of
                            'Array' arr | 'V.null' arr -> 'pure' Nullary
                            _ -> 'mzero'
                      | (conKey '==' 'T.pack' \"Unary\") ->
                          case conVal of
                            arg -> Unary '<$>' 'parseJSON' arg
                      | (conKey '==' 'T.pack' \"Product\") ->
                          case conVal of
                            'Array' arr | 'V.length' arr '==' 3 ->
                              'Product' '<$>' 'parseJSON' (arr 'V.!' 0)
                                      '<*>' 'parseJSON' (arr 'V.!' 1)
                                      '<*>' 'parseJSON' (arr 'V.!' 2)
                            _ -> 'mzero'
                      | (conKey '==' 'T.pack' \"Record\") ->
                          case conVal of
                            'Object' obj ->
                              Record '<$>' (obj '.:' 'T.pack' \"One\")
                                     '<*>' (obj '.:' 'T.pack' \"Two\")
                                     '<*>' (obj '.:' 'T.pack' \"Three\")
                            _ -> 'mzero'
                     | 'otherwise' -> 'mzero'
              _ -> 'mzero'
          _ -> 'mzero'
@

Now we can use the newly created instances.

@
d :: D 'Int'
d = Record { testOne = 3.14159
           , testTwo = 'True'
           , testThree = Product \"test\" \'A\' 123
           }
@

>>> fromJSON (toJSON d) == Success d
> True

-}

module Data.Aeson.TH
    ( deriveJSON

    , deriveToJSON
    , deriveFromJSON

    , mkToJSON
    , mkParseJSON
    ) where

--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------

-- from aeson:
import Data.Aeson ( toJSON, object, (.=), (.:)
                  , ToJSON, toJSON
                  , FromJSON, parseJSON
                  )
import Data.Aeson.Types ( Value(..) )
-- from base:
import Control.Applicative ( pure, (<$>), (<*>) )
import Control.Monad       ( return, mapM, mzero, liftM2 )
import Data.Bool           ( otherwise )
import GHC.Base            ( String )
import Data.Eq             ( (==) )
import Data.Function       ( ($), (.), id )
import Data.Functor        ( fmap )
import Data.List           ( (++), foldl', map, zip, genericLength )
import Prelude             ( (-), Integer, error )
import Text.Show           ( show )
-- from containers:
import qualified Data.Map as M ( toList )
-- from template-haskell:
import Language.Haskell.TH
-- from text:
import qualified Data.Text as T ( pack )
-- from vector:
import qualified Data.Vector as V ( (!), null, length )



--------------------------------------------------------------------------------
-- Convenience
--------------------------------------------------------------------------------

-- | Generates both 'ToJSON' and 'FromJSON' instance declarations for the given<commit_msg>Get the TH stuff building under GHC 6.12<commit_after>{-# LANGUAGE NoImplicitPrelude, TemplateHaskell #-}

{-|
Module:      Data.Aeson.TH
License:     Apache
Stability:   experimental
Portability: portable

Functions to mechanically derive 'ToJSON' and 'FromJSON' instances. Note that
you need to enable the @TemplateHaskell@ language extension in order to use this
module.

An example shows how instances are generated for arbitrary data types. First we
define a data type:

@
data D a = Nullary
         | Unary Int
         | Product String Char a
         | Record { testOne   :: Double
                  , testTwo   :: Bool
                  , testThree :: D a
                  } deriving Eq
@

Next we derive the necessary instances. Note that we make use of the feature to
change record field names. In this case we drop the first 4 characters of every
field name.

@
$('deriveJSON' ('drop' 4) ''D)
@

This will result in the following (simplified) code to be spliced in your program:

@
import Control.Applicative
import Control.Monad
import Data.Aeson
import Data.Aeson.TH
import qualified Data.Map    as M
import qualified Data.Text   as T
import qualified Data.Vector as V

instance 'ToJSON' a => 'ToJSON' (D a) where
    'toJSON' =
      \value ->
        case value of
          Nullary ->
              'object' ['T.pack' \"Nullary\" .= 'toJSON' ([] :: [()])]
          Unary arg1 ->
              'object' ['T.pack' \"Unary\" .= 'toJSON' arg1]
          Product arg1 arg2 arg3 ->
              'object' [ 'T.pack' \"Product\"
                       .= 'toJSON' [ 'toJSON' arg1
                                 , 'toJSON' arg2
                                 , 'toJSON' arg3
                                 ]
                     ]
          Record arg1 arg2 arg3 ->
              'object' [ 'T.pack' \"Record\"
                       .= 'object' [ 'T.pack' \"One\"   '.=' arg1
                                 , 'T.pack' \"Two\"   '.=' arg2
                                 , 'T.pack' \"Three\" '.=' arg3
                                 ]
                     ]
@

@
instance 'FromJSON' a => 'FromJSON' (D a) where
    'parseJSON' =
      \value ->
        case value of
          'Object' obj ->
            case 'M.toList' obj of
              [(conKey, conVal)] ->
                  case conKey of
                    _ | (conKey '==' 'T.pack' \"Nullary\") ->
                          case conVal of
                            'Array' arr | 'V.null' arr -> 'pure' Nullary
                            _ -> 'mzero'
                      | (conKey '==' 'T.pack' \"Unary\") ->
                          case conVal of
                            arg -> Unary '<$>' 'parseJSON' arg
                      | (conKey '==' 'T.pack' \"Product\") ->
                          case conVal of
                            'Array' arr | 'V.length' arr '==' 3 ->
                              'Product' '<$>' 'parseJSON' (arr 'V.!' 0)
                                      '<*>' 'parseJSON' (arr 'V.!' 1)
                                      '<*>' 'parseJSON' (arr 'V.!' 2)
                            _ -> 'mzero'
                      | (conKey '==' 'T.pack' \"Record\") ->
                          case conVal of
                            'Object' obj ->
                              Record '<$>' (obj '.:' 'T.pack' \"One\")
                                     '<*>' (obj '.:' 'T.pack' \"Two\")
                                     '<*>' (obj '.:' 'T.pack' \"Three\")
                            _ -> 'mzero'
                     | 'otherwise' -> 'mzero'
              _ -> 'mzero'
          _ -> 'mzero'
@

Now we can use the newly created instances.

@
d :: D 'Int'
d = Record { testOne = 3.14159
           , testTwo = 'True'
           , testThree = Product \"test\" \'A\' 123
           }
@

>>> fromJSON (toJSON d) == Success d
> True

-}

module Data.Aeson.TH
    ( deriveJSON

    , deriveToJSON
    , deriveFromJSON

    , mkToJSON
    , mkParseJSON
    ) where

--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------

-- from aeson:
import Data.Aeson ( toJSON, object, (.=), (.:)
                  , ToJSON, toJSON
                  , FromJSON, parseJSON
                  )
import Data.Aeson.Types ( Value(..) )
-- from base:
import Control.Applicative ( pure, (<$>), (<*>) )
import Control.Monad       ( return, mapM, mzero, liftM2 )
import Data.Bool           ( otherwise )
import GHC.Base            ( Monad(..), String )
import Data.Eq             ( (==) )
import Data.Function       ( ($), (.), id )
import Data.Functor        ( fmap )
import Data.List           ( (++), foldl', map, zip, genericLength )
import Prelude             ( (-), Integer, fromInteger, error )
import Text.Show           ( show )
-- from containers:
import qualified Data.Map as M ( toList )
-- from template-haskell:
import Language.Haskell.TH
-- from text:
import qualified Data.Text as T ( pack )
-- from vector:
import qualified Data.Vector as V ( (!), null, length )



--------------------------------------------------------------------------------
-- Convenience
--------------------------------------------------------------------------------

-- | Generates both 'ToJSON' and 'FromJSON' instance declarations for the given
{'fraction_non_alphanumeric': 0.18255977496483825, 'fraction_numerical': 0.00590717299578059, 'mean_word_length': 1.1242780322644892, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2920763', 'n_tokens_mistral': 2941, 'n_tokens_neox': 2818, 'n_words': 854}