hydra-0.15.0: src/main/haskell/Hydra/Json/Parser.hs
-- Note: this is an automatically generated file. Do not edit.
-- | JSON parser using Hydra parser combinators
module Hydra.Json.Parser where
import qualified Hydra.Json.Model as Model
import qualified Hydra.Lib.Equality as Equality
import qualified Hydra.Lib.Lists as Lists
import qualified Hydra.Lib.Literals as Literals
import qualified Hydra.Lib.Logic as Logic
import qualified Hydra.Lib.Maps as Maps
import qualified Hydra.Lib.Maybes as Maybes
import qualified Hydra.Lib.Strings as Strings
import qualified Hydra.Parsers as Parsers
import qualified Hydra.Parsing as Parsing
import Prelude hiding (Enum, Ordering, decodeFloat, encodeFloat, fail, map, pure, sum)
import qualified Data.Scientific as Sci
import qualified Hydra.Lib.Literals as Literals
-- | Parse a single digit (0-9)
digit :: Parsing.Parser Int
digit = Parsers.satisfy (\c -> Logic.and (Equality.gte c 48) (Equality.lte c 57))
-- | Parse one or more digits as a string
digits :: Parsing.Parser String
digits = Parsers.map Strings.fromList (Parsers.some digit)
-- | Parse a JSON array
jsonArray :: Parsing.Parser Model.Value
jsonArray =
Parsers.map (\x -> Model.ValueArray x) (Parsers.between (token (Parsers.char 91)) (token (Parsers.char 93)) (Parsers.sepBy (Parsers.lazy (\_ -> jsonValue)) (token (Parsers.char 44))))
-- | Parse JSON boolean (true or false)
jsonBool :: Parsing.Parser Model.Value
jsonBool =
Parsers.alt (Parsers.map (\_ -> Model.ValueBoolean True) (token (Parsers.string "true"))) (Parsers.map (\_ -> Model.ValueBoolean False) (token (Parsers.string "false")))
-- | Parse a JSON escape sequence after the backslash
jsonEscapeChar :: Parsing.Parser Int
jsonEscapeChar =
Parsers.choice [
Parsers.map (\_ -> 34) (Parsers.char 34),
(Parsers.map (\_ -> 92) (Parsers.char 92)),
(Parsers.map (\_ -> 47) (Parsers.char 47)),
(Parsers.map (\_ -> 8) (Parsers.char 98)),
(Parsers.map (\_ -> 12) (Parsers.char 102)),
(Parsers.map (\_ -> 10) (Parsers.char 110)),
(Parsers.map (\_ -> 13) (Parsers.char 114)),
(Parsers.map (\_ -> 9) (Parsers.char 116))]
-- | Parse the optional exponent part of a JSON number
jsonExponentPart :: Parsing.Parser (Maybe String)
jsonExponentPart =
Parsers.optional (Parsers.bind (Parsers.satisfy (\c -> Logic.or (Equality.equal c 101) (Equality.equal c 69))) (\_ -> Parsers.bind (Parsers.optional (Parsers.satisfy (\c -> Logic.or (Equality.equal c 43) (Equality.equal c 45)))) (\sign -> Parsers.map (\digits -> Strings.cat2 (Strings.cat2 "e" (Maybes.maybe "" (\arg_ -> Strings.fromList (Lists.pure arg_)) sign)) digits) digits)))
-- | Parse the optional fractional part of a JSON number
jsonFractionPart :: Parsing.Parser (Maybe String)
jsonFractionPart = Parsers.optional (Parsers.bind (Parsers.char 46) (\_ -> Parsers.map (\d -> Strings.cat2 "." d) digits))
-- | Parse the integer part of a JSON number (optional minus, then digits)
jsonIntegerPart :: Parsing.Parser String
jsonIntegerPart =
Parsers.bind (Parsers.optional (Parsers.char 45)) (\sign -> Parsers.bind digits (\digits -> Parsers.pure (Maybes.maybe digits (\_ -> Strings.cat2 "-" digits) sign)))
-- | Parse a JSON object key-value pair
jsonKeyValue :: Parsing.Parser (String, Model.Value)
jsonKeyValue =
Parsers.bind (token (Parsers.bind (Parsers.char 34) (\_ -> Parsers.bind (Parsers.many jsonStringChar) (\chars -> Parsers.bind (Parsers.char 34) (\_2 -> Parsers.pure (Strings.fromList chars)))))) (\key -> Parsers.bind (token (Parsers.char 58)) (\_ -> Parsers.map (\v -> (key, v)) (Parsers.lazy (\_2 -> jsonValue))))
-- | Parse JSON null value
jsonNull :: Parsing.Parser Model.Value
jsonNull = Parsers.map (\_ -> Model.ValueNull) (token (Parsers.string "null"))
-- | Parse a JSON number (integer, decimal, or scientific notation)
jsonNumber :: Parsing.Parser Model.Value
jsonNumber =
token (Parsers.bind jsonIntegerPart (\intPart -> Parsers.bind jsonFractionPart (\fracPart -> Parsers.bind jsonExponentPart (\expPart ->
let numStr =
Strings.cat2 (Strings.cat2 intPart (Maybes.maybe "" Equality.identity fracPart)) (Maybes.maybe "" Equality.identity expPart)
in (Parsers.pure (Model.ValueNumber (Maybes.maybe (Literals.stringToDecimal "0.0") Equality.identity (Literals.readDecimal numStr))))))))
-- | Parse a JSON object
jsonObject :: Parsing.Parser Model.Value
jsonObject =
Parsers.map (\arg_ -> (\x -> Model.ValueObject x) (Maps.fromList arg_)) (Parsers.between (token (Parsers.char 123)) (token (Parsers.char 125)) (Parsers.sepBy jsonKeyValue (token (Parsers.char 44))))
-- | Parse a JSON string value
jsonString :: Parsing.Parser Model.Value
jsonString =
token (Parsers.bind (Parsers.char 34) (\_ -> Parsers.bind (Parsers.many jsonStringChar) (\chars -> Parsers.bind (Parsers.char 34) (\_2 -> Parsers.pure (Model.ValueString (Strings.fromList chars))))))
-- | Parse a single character in a JSON string (handling escapes)
jsonStringChar :: Parsing.Parser Int
jsonStringChar =
Parsers.alt (Parsers.bind (Parsers.char 92) (\_ -> jsonEscapeChar)) (Parsers.satisfy (\c -> Logic.and (Logic.not (Equality.equal c 34)) (Logic.not (Equality.equal c 92))))
-- | Parse any JSON value
jsonValue :: Parsing.Parser Model.Value
jsonValue =
Parsers.choice [
jsonNull,
jsonBool,
jsonNumber,
jsonString,
jsonArray,
jsonObject]
-- | Parse a JSON document from a string
parseJson :: String -> Parsing.ParseResult Model.Value
parseJson input =
Parsing.unParser (Parsers.bind whitespace (\_ -> Parsers.bind jsonValue (\v -> Parsers.bind whitespace (\_2 -> Parsers.bind Parsers.eof (\_3 -> Parsers.pure v))))) input
-- | Parse a token followed by optional whitespace
token :: Parsing.Parser t0 -> Parsing.Parser t0
token p = Parsers.bind p (\x -> Parsers.bind whitespace (\_ -> Parsers.pure x))
-- | Parse zero or more JSON whitespace characters (space, tab, newline, carriage return)
whitespace :: Parsing.Parser ()
whitespace =
Parsers.map (\_ -> ()) (Parsers.many (Parsers.satisfy (\c -> Lists.foldl Logic.or False [
Equality.equal c 32,
(Equality.equal c 9),
(Equality.equal c 10),
(Equality.equal c 13)])))