packages feed

dead-simple-json (empty) → 0.1.2

raw patch · 9 files changed

+860/−0 lines, 9 filesdep +basedep +containersdep +parsecsetup-changed

Dependencies added: base, containers, parsec, template-haskell, transformers, vector

Files

+ Example.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE Haskell2010, TemplateHaskell, QuasiQuotes #-}++module Main where+++import Text.Printf (printf)++import Text.DeadSimpleJSON+import Text.DeadSimpleJSON.TH++import Data.Ratio+++main :: IO ()+main = do+    +    let jsonData = read "{\"seven\": 7, \"nine\": [1,2,4,8,16]}"+    print $ (jsonData ? "nine[3]" :: Int)++    let jone = [json|+                    [+                        {+                            "one": 0.1,+                            "two": 123+                        },+                        {+                            "one": true,+                            "two": null,+                            "three": 23412349.24e-12+                        },+                        {+                            "one": "ONE",+                            "two": null,+                            "three": "THREE"+                        },+                        {+                            "one": false,+                            "two": 14964674393249287+                        }+                    ]+                |]+        jtwo = jone -- [jsonF|json2.txt|]+        jtri = [json| ["Naks", "Noks", "Nuks"] |]+        jfrr = jone -- read [sF|json2.txt|] :: JSON++        val1 = [jsq| jone[3].two |] :: String+        val2 = [jsq| jtwo[4] |]     :: Double+        val3 = [jsq| jtri |]        :: String++    print $ length $ show jfrr+    print $ length $ show jtwo++    print val1+    print val2+    print val3+++
+ LICENSE view
@@ -0,0 +1,18 @@+Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the "Software"),+to deal in the Software without restriction, including without limitation+the rights to use, copy, modify, merge, publish, distribute, sublicense,+and/or sell copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER+DEALINGS IN THE SOFTWARE.+
+ Setup.lhs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main = defaultMain+
+ dead-simple-json.cabal view
@@ -0,0 +1,44 @@+Name:           dead-simple-json+Version:        0.1.2+Synopsis:       Dead simple JSON parser, with some Template Haskell sugar.+Description:    This is dead simple JSON, consisting of a simple parser built with Parsec+                and some Template Haskell syntactic sugar (which you may or may not use,+                it works without).+               +License:        MIT+License-File:   LICENSE+Author:         Julian Fleischer <julian.fleischer@fu-berlin.de>+Maintainer:     Julian Fleischer <julian.fleischer@fu-berlin.de>+Build-Type:     Simple+Cabal-Version:  >= 1.6+Category:       JSON+Stability:      experimental+Homepage:       http://hub.darcs.net/scravy/dead-simple-json++Extra-Source-Files: Example.hs++Source-Repository head+    type: darcs+    location: hub.darcs.net:dead-simple-json++Source-Repository this+    type: darcs+    location: hub.darcs.net:dead-simple-json+    tag: v0.1.2++Library+    Exposed-Modules:    Text.DeadSimpleJSON,+                        Text.DeadSimpleJSON.Convert,+                        Text.DeadSimpleJSON.Query,+                        Text.DeadSimpleJSON.TH,+                        Text.DeadSimpleJSON.Types+                        +    Build-Depends:      base >= 4 && < 5,+                        transformers >= 0.3,+                        parsec >= 3.1.3,+                        vector >= 0.10,+                        containers >= 0.4.2,+                        template-haskell+    Hs-Source-Dirs:     src++
+ src/Text/DeadSimpleJSON.hs view
@@ -0,0 +1,248 @@+{-# LANGUAGE Haskell2010 #-}+{-# OPTIONS -Wall -O2+    -fno-warn-unused-do-bind+    -fno-warn-missing-signatures+    -fno-warn-name-shadowing+    -fno-warn-orphans #-}++{- |+Module      :  DeadSimpleJSON.hs+Copyright   :  (c) Julian Fleischer+License     :  MIT++Maintainer  :  Julian Fleischer <julian.fleischer@fu-berlin.de>+Stability   :  experimental+Portability :  portable++A simple approach for parsing JSON.++To read JSON data use 'read'. To print JSON data use 'show':++> let jsonData = read "[1,2,4,8,16]" :: JSON+> putStrLn $ show jsonData++You can query json data using '?'. Querying implies conversion,+therefor you may need to specify the result type:++> let jsonData = read "{\"seven\": 7, \"nine\": [1,2,4,8,16]}"+> print $ (jsonData ? "nine[3]" :: Int)++For tighter control use 'parse'. A more convenient way for+creating JSON objects in source code or querying JSON data,+is using Template Haskell. See @Text.SimpleJSON.TH@.++The recommended way for importing this module is importing+it qualified, like so:++> import qualified Text.SimpleJSON as JSON+> import Text.SimpleJSON (JSON)++-}+module Text.DeadSimpleJSON (+    -- * Parsing strings+    parse,+    parse',+    parseM,++    -- * Basic data types+    Value (..),+    JSON,++    -- ** Querying json data+    (?),+    top,++    -- ** Conversion to and from+    Convert (..)+) where+++import Prelude hiding (True, False)+import qualified Prelude++import Data.Char (isControl)++import qualified Data.Map as M+import qualified Data.Vector as V++import Text.Parsec hiding (parse)+import Control.Applicative ((*>), (<*))+import Data.Functor.Identity++import Numeric (showHex, readHex)++import Text.DeadSimpleJSON.Convert+import Text.DeadSimpleJSON.Query+import Text.DeadSimpleJSON.Types+++instance Show JSON where+    show (JSON jsonObject) = write jsonObject++instance Read JSON where+    readsPrec _ =+        either (const []) (:[]) . runIdentity . runParserT json () "-"+++parse :: String -> Either ParseError JSON+-- ^ Parse a String for JSON data or return a ParseError.+parse str = runIdentity $ runParserT json' () "-" str++parse' :: String -> Maybe Value+-- ^ Parses a top-level JSON object, returning Just a Value or Nothing.+parse' = parseM++parseM :: Monad m => String -> m Value+-- ^ Purely Monadic version of 'parse''.+parseM = either (fail . show) (return . top) . parse++top :: JSON -> Value+-- ^ Unwraps a top-level JSON object to a Value.+top (JSON v) = v+++write x = case x of+    (Number n e) -> writeNumber n e+    (String s) -> '"' : writeString s+    (Object m) -> writeObject m+    (Array v)  -> writeArray v+    True  -> "true"+    False -> "false"+    Null  -> "null"++writeNumber n 0 = show n+writeNumber n e = show n ++ "e" ++ show e++writeString (x:xs)+    | isControl x   = "\\u"  ++ showHex (fromEnum x) (writeString xs)+    | x == '\x2028' = "\\u2028"+    | x == '\x2029' = "\\u2029"+    | x == '\\'     = "\\\\" ++ writeString xs+    | x == '\"'     = "\\\"" ++ writeString xs+    | otherwise     = x : writeString xs+writeString [] = "\""++writeArray arr+    | V.null arr = "[]"+    | otherwise  = '[' : (tail $ concat $ V.foldr (\v l -> "," : write v : l) ["]"] arr)+-- note that using V.foldr' instead of V.foldr makes the SpecConstr optimizer go nuts (-fspec-constr)++writeObject obj+    | M.null obj = "{}"+    | otherwise  = '{' : (tail $ concat $ M.foldrWithKey' (\k v l -> ",\"" : writeString k : ":" : write v : l) ["}"] obj)+++json' :: Monad m => ParsecT String () m JSON+json  :: Monad m => ParsecT String () m (JSON, String)++value, jsonString, number, negativeNumber, nonNegativeNumber, object, array+    :: Monad m => ParsecT String () m Value++stringChar, escapedChar+    :: Monad m => ParsecT String () m Char++keyValue+    :: Monad m => ParsecT String () m (String, Value)++mkNumber+    :: Monad m => String -> String -> String -> ParsecT String u m Value+++json = do+    val  <- spaces *> (object <|> array)+    rest <- many anyToken+    return (JSON val, rest)++json' = do+    val <- spaces >> (object <|> array) <* spaces+    (char '\EOT' >> return ()) <|> eof+    return $ JSON val+++value = jsonString+    <|> number+    <|> object+    <|> array+    <|> (string "true"  >> return True)+    <|> (string "false" >> return False)+    <|> (string "null"  >> return Null)++jsonString = do+    char '"'+    str <- many (stringChar <|> escapedChar)+    char '"'+    return $ String str++stringChar = satisfy (\x -> not (isControl x || (elem x "\\\"")))++escapedChar = do+    char '\\'+    oneOf "\"\\/"+      <|> (oneOf "bfnrt" >>= special)+      <|> (char 'u' >> count 4 hexDigit >>= convert)+      <?> "escape sequence: one of b, f, n, r, t, or uXXXX"+        where+            special chr = return $ case chr of+                'b' -> '\b'+                'f' -> '\f'+                'n' -> '\n'+                'r' -> '\r'+                't' -> '\t'+                _   -> undefined+            convert str = do+                let [(hex, _)] = readHex str+                return $ toEnum hex++number = negativeNumber <|> nonNegativeNumber++negativeNumber = do+    char '-'+    (Number nom denom) <- nonNegativeNumber+    return $ Number (negate nom) denom++nonNegativeNumber = do+    num <- digits <|> string "0"+    mantisse <- option "" (char '.' *> many1 digit)+    exp <- option "0" exponent+    mkNumber num mantisse exp+        where+            digits = do+                first <- oneOf ['1'..'9']+                rest  <- many digit+                return $ first : rest+            exponent = do+                oneOf "eE"+                sign <- option '+' $ oneOf "+-"+                exp  <- many1 digit+                return $ sign : exp++mkNumber str1 str2 ('+':str3) = mkNumber str1 str2 str3+mkNumber str1 str2 str3 = do+    let str2' = reverse $ dropWhile (== '0') $ reverse str2+        [(nom, _)] = reads (str1 ++ str2')+        [(exp, _)] = reads (str3)+        exp'   = negate (fromIntegral (length str2') + negate exp)+        num n d+            | n == 0 = Number 0 0+            | n `rem` 10 == 0 = num (n `quot` 10) (d+1)+            | otherwise = Number n d+    return $ num nom exp'++object = do+    pairs <- between (char '{') (char '}') $ do+        spaces+        sepBy keyValue (char ',' >> spaces)+    return $ Object $ M.fromList pairs++keyValue = do+    (String key) <- jsonString <* char ':'+    val <- between spaces spaces value+    return (key, val)++array = do+    values <- between (char '[') (char ']') $ do+        spaces+        sepBy (value <* spaces) (char ',' >> spaces)+    return $ Array $ V.fromList values++
+ src/Text/DeadSimpleJSON/Convert.hs view
@@ -0,0 +1,183 @@+{-# LANGUAGE Haskell2010,+             ScopedTypeVariables,+             FlexibleInstances,+             TypeSynonymInstances,+             OverlappingInstances #-}+{-# OPTIONS -Wall -O2 #-}+++module Text.DeadSimpleJSON.Convert (+    Value (..),+    Convert (..)+) where+++import Prelude hiding (True, False)+import qualified Prelude++import Data.Int+import Data.Ratio+import Text.DeadSimpleJSON.Types++import qualified Data.Vector as V+-- import qualified Data.Map as M+++default ()+++class Convert a where+    convert :: Value -> a++    convert' :: Value -> Maybe a+    convert' n@(Number _ _) = return $ convert n+    convert' _ = fail ""++    toJSON :: a -> Value+    toJSON = undefined+++instance Convert a => Convert (Maybe a) where+    convert  = convert'+    convert' = maybe Nothing Just . convert'++    toJSON (Just a) = toJSON a+    toJSON Nothing = Null+++instance Convert Value where+    convert = id+    convert' = return++    toJSON = id+++instance Convert Bool where+    convert True  = Prelude.True+    convert (String "") = Prelude.False+    convert (String _) = Prelude.True+    convert (Number 0 _) = Prelude.False+    convert (Number _ _) = Prelude.True+    convert _ = Prelude.False++    convert' True = return Prelude.True+    convert' False = return Prelude.False+    convert' _ = fail ""++    toJSON (Prelude.True) = True+    toJSON (Prelude.False) = False+++instance Convert String where+    convert (String s) = s+    convert (Number n e)+        | e >= 10   = show e+        | otherwise = show n ++ "e" ++ show e+    convert (Array arr) = tail $ tail $ V.foldr (\v l -> ", " ++ convert v ++ l) "" arr+    convert (Object _) = "{object}"+    convert True  = "true"+    convert False = "false"+    convert Null  = "null"++    convert' (String s) = return s+    convert' _ = fail ""++    toJSON = String+++instance Convert a => Convert [a] where+    convert (Array v) = map convert $ V.toList v+    convert _ = []++    convert' arr@(Array _) = return $ convert arr+    convert' _ = fail ""++    toJSON = Array . V.fromList . map toJSON+++instance Convert Double where+    convert (Number n e)+        | e >= 0    = fromInteger (n * 10 ^ e) / 1.0+        | otherwise = fromInteger n / fromInteger (10 ^ negate e)+    convert (Object _) = 0/0+    convert (Array _) = 0/0+    convert Null = 0/0+    convert v = def v+++instance Convert Float where+    convert (Number n e)+        | e >= 0    = fromInteger (n * 10 ^ e) / 1.0+        | otherwise = fromInteger n / fromInteger (10 ^ negate e)+    convert (Object _) = 0/0+    convert (Array _) = 0/0+    convert Null = 0/0+    convert v = def v+++instance forall a. (Read a, Integral a) => Convert (Ratio a) where+    convert (Number n e)+        | e >= 0    = n' * 10 ^ e' % 1+        | otherwise = n' % 10 ^ negate e'+            where n' = fromInteger n :: a+                  e' = fromInteger e :: a+    convert v = def v % 1+++instance Convert Integer where+    convert (Number n e) = int n e+    convert v = def v++    toJSON = flip Number 1+++instance Convert Int where+    convert (Number n e) = fromInteger $ int n e+    convert v = def v++    toJSON = flip Number 1 . toInteger+++instance Convert Int8 where+    convert (Number n e) = fromInteger $ int n e+    convert v = def v++    toJSON = flip Number 1 . toInteger+++instance Convert Int16 where+    convert (Number n e) = fromInteger $ int n e+    convert v = def v++    toJSON = flip Number 1 . toInteger+++instance Convert Int32 where+    convert (Number n e) = fromInteger $ int n e+    convert v = def v++    toJSON = flip Number 1 . toInteger++    +instance Convert Int64 where+    convert (Number n e) = fromInteger $ int n e+    convert v = def v++    toJSON = flip Number 1 . toInteger+++int :: Integral a => a -> a -> a+int n e+    | e >= 0    = n * 10 ^ e+    | otherwise = n `quot` 10 ^ negate e++def :: (Read a, Num a) => Value -> a+def True  = 1+def False = 0+def Null  = 0+def (String s) = let v = reads s in case v of ((n, _):_) -> n; _ -> 0+def (Array _)  = 0+def (Object _) = 0+def _ = undefined++
+ src/Text/DeadSimpleJSON/Query.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE Haskell2010,+             DeriveDataTypeable #-}+{-# OPTIONS -Wall -O2+    -fno-warn-unused-do-bind+    -fno-warn-missing-signatures+    -fno-warn-name-shadowing #-}++module Text.DeadSimpleJSON.Query (+    query,+    query',+    queryV,+    queryV',+    Query (..),+    mkQuery,+    mkQuery',+    (?)+) where+++import Text.Parsec++import Text.DeadSimpleJSON.Convert+import Text.DeadSimpleJSON.Types++import qualified Data.Map as M+import qualified Data.Vector as V++import Data.Data+import Data.Functor.Identity+import Control.Monad+import Control.Applicative ((<*))+++data Query = Field String Query+           | Index Int Query+           | Read+    deriving (Show, Data, Typeable)+++query :: Convert a => Query -> JSON -> a+query q (JSON v) = queryV q v++query' :: Convert a => Query -> JSON -> Maybe a+query' q (JSON v) = queryV' q v+++queryV :: Convert a => Query -> Value -> a+queryV (Field f q) (Object m) = maybe (convert Null) (queryV q) (M.lookup f m)+queryV (Index i q) (Array a)  = maybe (convert Null) (queryV q) (a V.!? i)+queryV Read v = convert v++queryV _ _ = convert Null+++queryV' :: Convert a => Query -> Value -> Maybe a+queryV' (Field f q) (Object m) = maybe Nothing (queryV' q) (M.lookup f m)+queryV' (Index i q) (Array a)  = maybe Nothing (queryV' q) (a V.!? i)+queryV' Read v = convert' v++queryV' _ _ = Nothing+++json ? q = query (mkQuery q) json+++type Parser a = ParsecT String () Identity a++ident :: Parser String+ident = liftM2 (:) (letter <|> char '_') (many (alphaNum <|> char '_'))++index :: Parser Int+index = liftM read $ between (char '[') (char ']') (many1 digit)++path :: Parser [Either String Int]+path = liftM concat $ sepBy element (char '.')++element :: Parser [Either String Int]+element = liftM2 (:) (ident >>= return . Left) (many index >>= return . map Right)++mkPath :: String -> [Either String Int]+mkPath = either (const []) id . parse path "-"++mkQuery :: String -> Query+mkQuery = buildQuery . mkPath++mkQuery' :: String -> Either ParseError Query+mkQuery' = either Left (Right . buildQuery) . parse (path <* eof) "JSON Query"++buildQuery = foldr (\x p -> either (\s -> Field s p) (\i -> Index i p) x) Read++
+ src/Text/DeadSimpleJSON/TH.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE Haskell2010,+             TemplateHaskell #-}+{-# OPTIONS -Wall -O2 -fno-warn-name-shadowing #-}++-- | Template Haskell syntax sugar for working with 'JSON' data.+-- +-- For using this module, you need to declare a LANGUAGE+-- pragma like the following:+-- +-- > {-# LANGUAGE Haskell2010, TemplateHaskell, QuasiQuotes #-}+module Text.DeadSimpleJSON.TH (++    -- * Query JSON objects+    jsq,++    -- * Create JSON objects+    json,+    jsonF,++    -- * Include strings+    s,+    sF+) where++import Prelude hiding (True, False)+import qualified Prelude++import Data.Char+import qualified Data.Map as M+import qualified Data.Vector as V++import Text.DeadSimpleJSON (parse)+import Text.DeadSimpleJSON.Convert (Convert (..))+import Text.DeadSimpleJSON.Query+import Text.DeadSimpleJSON.Types++import Language.Haskell.TH+import Language.Haskell.TH.Quote+++s :: QuasiQuoter+-- ^ A QuasiQuoter on raw strings.+--+-- The definition is basically:+--+-- > s = QuasiQuoter {+-- >   quoteExp  = return . LitE . StringL+-- > }+s = QuasiQuoter {+    quoteExp  = return . LitE . StringL,++    quotePat  = \_ -> fail "illegal string QuasiQuote (allowed as expression only, used as a pattern)",+    quoteType = \_ -> fail "illegal string QuasiQuote (allowed as expression only, used as a type)",+    quoteDec  = \_ -> fail "illegal string QuasiQuote (allowed as expression only, used as a dec)"+}+++sF :: QuasiQuoter+-- ^ A QuasiQuoter which includes raw strings from files.+--+-- The following example will include the contents of @file.txt@+-- as a @String@.+--+-- > let str = [sF|file.txt|]+--+-- Note that every character inside the brackets is treated+-- as part of the file name, that is @[sF| file.txt |]@ is not+-- the same as the above example (it will try to find a file which+-- name includes space characters).+sF = quoteFile s++jsonF :: QuasiQuoter+-- ^ A QuasiQuoter which includes JSON data from files.+--+-- The following example will include the contents of @data.json@+-- as 'JSON'.+--+-- > let str = [jsonF|data.json|]+--+-- Note that every character inside the brackets is treated+-- as part of the file name, that is @[jsonF| data.json |]@ is not+-- the same as the above example (it will try to find a file which+-- name includes space characters).++jsonF = quoteFile json++json :: QuasiQuoter+-- ^ A QuasiQuoter which includes JSON data.+--+-- The type of the expression is 'JSON'.+json = QuasiQuoter {+    quoteExp  = jsonQuoter,++    quotePat  = \_ -> fail "illegal json QuasiQuote (allowed as expression only, used as a pattern)",+    quoteType = \_ -> fail "illegal json QuasiQuote (allowed as expression only, used as a type)",+    quoteDec  = \_ -> fail "illegal json QuasiQuote (allowed as expression only, used as a dec)"+}++jsonQuoter :: String -> Q Exp+jsonQuoter = either (fail . show) buildJSON . parse+    where+        buildJSON (JSON json) = do+            json' <- buildJSON' json+            return (AppE (ConE 'JSON) json')++        buildJSON' (String s) = return $ AppE (ConE 'String) (LitE (StringL s))+        buildJSON' (Number n e) = return $ AppE (AppE (ConE 'Number) (LitE (IntegerL n))) (LitE (IntegerL e))+        buildJSON' (Object obj) = do+            m <- mapM (\(k, v) -> do { x <- buildJSON' v; return $ TupE [LitE (StringL k), x] }) (M.toList obj)+            return $ AppE (ConE 'Object) (AppE (VarE 'M.fromList) (ListE m))+        buildJSON' (Array arr) = do+            v <- mapM buildJSON' (V.toList arr)+            return $ AppE (ConE 'Array) (AppE (VarE 'V.fromList) (ListE v))+        buildJSON' True = return $ ConE 'True+        buildJSON' False = return $ ConE 'False+        buildJSON' Null = return $ ConE 'Null+++jsq :: QuasiQuoter+-- ^ A QuasiQuoter which queries a json object using JavaScript notation.+-- +-- Suppose obj contains a json object of type JSON:+--+-- > [jsq| obj.prop.list[3] |]+--+-- The above will query the object in obj as if it was JavaScript.+--+-- The type of the expression is polymorphic: @Convert a => a@.+--+-- You will need to specify the type of the query, like so:+--+-- > [jsq| obj.prop.list |] :: [Integer]+--+-- For possible conversions, see the instances for 'Convert'.+jsq = QuasiQuoter {+    quoteExp  = jsqQuoter,++    quotePat  = \_ -> fail "illegal jsq QuasiQuote (allowed as expression only, used as a pattern)",+    quoteType = \_ -> fail "illegal jsq QuasiQuote (allowed as expression only, used as a type)",+    quoteDec  = \_ -> fail "illegal jsq QuasiQuote (allowed as expression only, used as a dec)"+}++jsqQuoter :: String -> Q Exp+jsqQuoter = either (fail . show) buildQuery . mkQuery' . filter (not . isSpace)+    where+        buildQuery (Field s e) = do+            q <- buildQuery' e+            return $ AppE ((AppE (VarE 'query)) q) (VarE (mkName s))+        buildQuery _ = do+            report Prelude.False "Warning: Empty JSON Query"+            [| convert $ Object M.empty |]++        buildQuery' (Field s e) = do+            exp <- buildQuery' e+            return $ AppE (AppE (ConE 'Field) (LitE (StringL s))) exp+        buildQuery' (Index i e) = do+            exp <- buildQuery' e+            return $ AppE (AppE (ConE 'Index) (LitE (IntegerL (fromIntegral i)))) exp+        buildQuery' (Read) = return $ ConE 'Read++
+ src/Text/DeadSimpleJSON/Types.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE Haskell2010,+             DeriveDataTypeable #-}+{-# OPTIONS -Wall -O2 #-}++-- | The basic JSON data types.+module Text.DeadSimpleJSON.Types (+    Value (..),+    JSON (..)+) where+++import Data.Data+import Data.Map (Map)+import Data.Vector (Vector)+++-- | A top-level JSON object.+--+-- Merely a wrapper that ensures that no other 'Value's+-- but 'Array' and 'Object' reside at the top-level.+newtype JSON = JSON Value+    deriving (Eq, Data, Typeable)++-- | A JSON value.+data Value++    = String String+    -- ^ A JSON String, represented as ordinary Haskell String.++    | Number !Integer !Integer+    -- ^ A JSON Number, represented by two 'Integer's in+    -- exponontial form. @Number n e@ is the same as @{n}e{exp}@,+    -- that is @n * 10 ^ e@. This allows for arbitrary precision+    -- fixed point rationals. See 'Convert' for easy conversions.++    | Object (Map String Value)+    -- ^ A JSON Object, represented as 'Map'.++    | Array  (Vector Value)+    -- ^ A JSON Array, represented as 'Vector' of Values.++    | True+    -- ^ True.++    | False+    -- ^ False.++    | Null+    -- ^ Null (void, unit, @()@).++    deriving (Eq, Show, Read, Data, Typeable)++