(= json-true (match-literal "true" t))
(= json-false (match-literal "false" nil))
(= json-null (match-literal "null" nil))
(= json-number-char
(match [find _ ".-+eE1234567890"]))
(= json-number
(with-result cs (many1 json-number-char)
(coerce (string cs) 'num)))
(def hexdigit (c)
(and (isa c 'char)
(or (<= #\a c #\f) (<= #\A c #\F) (<= #\0 c #\9))))
(= fourhex
(must "four hex digits required after \\u"
(with-seq (h1 (match hexdigit)
h2 (match hexdigit)
h3 (match hexdigit)
h4 (match hexdigit))
(coerce (int (coerce (list h1 h2 h3 h4) 'string) 16) 'char))))
(def json-backslash-char (c)
(case c
#\" #\"
#\\ #\\
#\/ #\/
#\b #\backspace
#\f #\page
#\n #\newline
#\r #\return
#\t #\tab
(err "invalid backslash char" c)))
(= json-backslash-escape
(seq2 (match-is #\\)
(alt (seq2 (match-is #\u)
fourhex)
(fn (p)
(return cdr.p (json-backslash-char car.p))))))
(= json-string
(on-result string
(seq2 (match-is #\")
(must "missing closing quote in JSON string"
(seq1 (many (alt json-backslash-escape
(match [isnt _ #\"])))
(match-is #\"))))))
(= json-array
(seq2 (match-is #\[)
(optional (cons-seq forward.json-value
(many (seq2 (skipwhite:match-is #\,)
(must "a comma must be followed by a value"
forward.json-value)))))
(must "a JSON array must be terminated with a closing ]"
(skipwhite:match-is #\]))))
(= json-object-kv
(with-seq (key skipwhite.json-string
colon (must "a JSON object key string must be followed by a :"
(skipwhite:match-is #\:))
value (must "a colon in a JSON object must be followed by a value"
forward.json-value))
(list key value)))
(= json-object
(on-result listtab
(seq2 (match-is #\{)
(comma-separated json-object-kv "comma must be followed by a key")
(must "a JSON object must be terminated with a closing }"
(skipwhite:match-is #\})))))
(= json-value
(skipwhite:alt json-true
json-false
json-null
json-number
json-string
json-array
json-object))
(def fromjson (s)
(iflet (p r) (json-value (coerce s 'cons))
(do (if p (err "Unexpected characters after JSON value" (coerce p 'string)))
r)
(err:string "not a JSON value: " s)))
Parses a JSON expression and converts it to an Arc value.
arc> (fromjson "[1, 2, {\"a\": 3, \"b\": 4}, true, false]")
(1 2 #hash(("a" . 3) ("b" . 4)) t nil)This hack depends on arc3.1 and parsecomb0.
Download fromjson0.arc and its prerequisite, parsecomb.
Or, using the hackinator:
hack ycombinator.com/arc/arc3.1.tar \ awwx.ws/parsecomb0.arc \ awwx.ws/fromjson0.arc
This code is in the public domain.