JNumber Parser
The following syntax diagram summarises the specification for the JNumber parser.

Again we'll break this seemingly complex syntax diagram into its constituent parts; representing each as a sub parsing function that'll we composite together to create the JNumber parser:
Optional Negative Sign
The
Zero Parser
The
Digit 1 to 9 Parser
The
Digit Parser
The
Dot Parser
The
Exponent Symbol Parser
The
Optional +/- Parser
The
Non Zero Integer Parser
The
Integer Parser
The
Fraction Parser
The
Exponent Parser
The
Convert Helper Function
The
JNumber parser tied to JValue
Finally we take all our sub parser and tie them together with the infix
From json.org
A number is very much like a C or Java number, except that the octal and hexadecimal formats are not used.
The following syntax diagram summarises the specification for the JNumber parser.

Again we'll break this seemingly complex syntax diagram into its constituent parts; representing each as a sub parsing function that'll we composite together to create the JNumber parser:
Optional Negative Sign
The
pOptionalSign defines a optional - character parser, used to denote only the negative sign.
C#:
module JSON =
...
// --- Parse a JNumber ---
let private pOptionalSign = Parser.opt (Parser.pchar '-') <?> "Optional Sign"
Zero Parser
The
pDigit1to9 defines a 0 digit character parser, used to denote only a zero digit.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pZero = Parser.pstring "0" <?> "Zero"
Digit 1 to 9 Parser
The
pDigit1to9 defines a 1 to 9 digit character parser, used to denote any of the number's digits, excluding the zero 0 digit.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pDigit1to9 = Parser.satisfy (fun c -> Char.IsDigit c && c <> '0') "Digit 1 to 9"
Digit Parser
The
pDigit defines a 0 to 9 digit character parser, used to denote any of the number's digits.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pDigit = Parser.satisfy Char.IsDigit "Digit"
Dot Parser
The
pDot defines a . character parser, used to denote an decimal part of a number.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pDot = Parser.pchar '.' <?> "Dot ."
Exponent Symbol Parser
The
pE defines an orElse parser between e or E character, used to denote an exponent part of a number.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pE = Parser.pchar 'e' <|> Parser.pchar 'E' <?> "Exponent Symbol"
Optional +/- Parser
The
pOptionalPlusMinus defines an optional plus + or minus - sign parser.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pOptionalPlusMinus = Parser.opt (Parser.pchar '-' <|> Parser.pchar '+') <?> "Optional +/-"
Non Zero Integer Parser
The
pIntegerNonZero parser requires a pDigit1to9 prefix tied to a zerp or more digits (0 to 9) Parser.manyChars pDigit.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pIntegerNonZero = pDigit1to9 .>>. Parser.manyChars pDigit <&> fun (h, t) -> string h + t
Integer Parser
The
pInteger parser is a orElse between a pZero parser and a pIntegerNonZero parser.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pInteger = pZero <|> pIntegerNonZero <?> "Integer Non Zero"
Fraction Parser
The
pFraction parser requires a pDot prefix but it excludes it from the result by linking it with the >>. infix operator tied to a 1 or more digits (0 to 9) Parser.many1Chars pDigit.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pFraction = pDot >>. Parser.many1Chars pDigit <?> "Fraction"
Exponent Parser
The
pExponent parser requires a pE prefix but it excludes it from the result by linking it with the >>. infix operator tied to an optional +/- sign pOptionalPlusMinus, tied (andThen .>>. operator) to a 1 or more digits (0 to 9) Parser.many1Chars pDigit.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private pExponent = pE >>. pOptionalPlusMinus .>>. Parser.many1Chars pDigit <?> "Exponent"
Convert Helper Function
convert is a helper function to transform the result of the jNumber parser to a float and then a JNumber that encapsulates that float i.e. a set of tuples wrapped in a tuple wrapped in another tuple. The (((sign, int), fraction), exponent) parameter syntax serves to splat the tupled values as variables with the same names; which we then glue together using a new infix operator |>? that converts an Option wrapped value to string using a string conversion function; we add everything together with the + infix operator and then pipe that through to float; which converts a string to a float, and finally we pipe to JNumber to encapsulate the float in a JValue.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private convert (((sign, int), fraction), exponent) =
(sign |>? string) + int + (fraction |>? fun n -> "." + n) + (exponent |>? fun (s, d) -> "e" + (s |>? string) + d) |> float |> JNumber
|>? infix operator is used to match over a Option wrapped value, converting the result to a string using a string conversion function parameter. This operator is defined as follows as will be added to the Parser library's Parser and Operator modules.
C#:
[<RequireQualifiedAccess>]
module Parser =
...
let optToString opt f =
match opt with
| None -> ""
| Some x -> f x
...
[<AutoOpen>]
module Operators =
...
// Infix Option to string
let (|>?) = Parser.optToString
JNumber parser tied to JValue
Finally we take all our sub parser and tie them together with the infix
andThen operator .>>.; the pFraction and pExponent are defined as optional re Parser.opt, finally we convert the result; which is a tuple of tuple of tuple to JNumber i.e. a member value of the JValue discriminated union type we declared above.
C#:
module JSON =
...
// --- Parse a JNumber ---
...
let private jNumber = pOptionalSign .>>. pInteger .>>. Parser.opt pFraction .>>. Parser.opt pExponent <&> convert <?> "JNumber"
Last edited:







