Skip to content

Instantly share code, notes, and snippets.

@bpk-t
Last active December 14, 2019 06:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpk-t/227c71196445d44d81f4a95471b9991e to your computer and use it in GitHub Desktop.
Save bpk-t/227c71196445d44d81f4a95471b9991e to your computer and use it in GitHub Desktop.
open System
open FParsec
type Json =
| JInteger of int
| JFloat of float
| JString of string
| JBool of bool
| JArray of Json list
| JObject of Map<string, Json>
| JNull
let ws = spaces
let parseBy p str =
match run (ws >>. p .>> eof) str with
| Success(res, _, _) -> res
| Failure(msg, _, _) -> failwithf "parse error: %s" msg
let minusSign = opt (pchar '-') |>> Option.isSome
let digit1to9 = anyOf ['1'..'9']
let integer = (many1Chars2 digit1to9 digit <|> pstring "0") |>> int
let jinteger =
minusSign .>>. integer
|>> (fun (hasMinus, x) -> JInteger (if hasMinus then -x else x))
let jfloat =
tuple3 minusSign integer (pchar '.' >>. integer)
|>> (fun (hasMinus, i, flac) ->
let f = float i + float ("0." + string flac)
JFloat (if hasMinus then -f else f))
let jnumber = (attempt jfloat <|> jinteger) .>> ws
let convEsc = function
| 'b' -> '\b'
| 'f' -> '\f'
| 'n' -> '\n'
| 'r' -> '\r'
| 't' -> '\t'
| t -> t
let nonEscapedChar = noneOf ['\\'; '"']
let escapedChar = pchar '\\' >>. anyOf @"\""/bfnrt" |>> convEsc
let jstring =
manyChars (nonEscapedChar <|> escapedChar)
|> between (pchar '"') (pchar '"')
.>> ws
|>> JString
let jbool =
choice [pstring "true"; pstring "false"]
.>> ws
|>> (fun x -> match x with
| "true" -> JBool(true)
| "false" -> JBool(false))
let json, jsonRef = createParserForwardedToRef()
let jarray =
sepBy json (pchar ',' >>. ws)
|> between (pchar '[' >>. ws) (pchar ']' >>. ws)
|>> (fun xs -> JArray xs)
let objKey =
manyChars nonEscapedChar
|> between (pchar '"') (pchar '"')
.>> ws
let keyAndValue =
objKey .>> (pchar ':' >>. ws) .>>. json
let jobject =
sepBy keyAndValue (pchar ',' >>. ws)
|> between (pchar '{' >>. ws) (pchar '}' >>. ws)
|>> (fun xs -> JObject(Map(xs)))
let jnull =
pstring "null" .>> ws
|>> (fun _ -> JNull)
jsonRef :=
choice [jnumber; jstring; jarray; jbool; jobject; jnull]
[<EntryPoint>]
let main argv =
let ans = "1.3" |> parseBy jnumber
printfn "ans = %A" ans
let a = "[ 1 , 2.5 , 3, true, false ]" |> parseBy jarray
printfn "%A" a
let b = "true" |> parseBy jbool
printfn "%A" b
let obj = """{ "a" : 100, "b": 0.5, "c": [100, 200], "d": null }""" |> parseBy json
printfn "%A" obj
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment