-
Notifications
You must be signed in to change notification settings - Fork 0
/
fromjson2.arc
95 lines (74 loc) · 2.01 KB
/
fromjson2.arc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
(def json-true ()
(mliteral "true" t))
(def json-false ()
(mliteral "false" nil))
(def json-null ()
(mliteral "null" nil))
(def json-number-char (x)
(some x ".-+eE1234567890"))
(def json-number ()
(coerce (string (many1is json-number-char)) 'num))
(def hexdigit (c)
(and (isa c 'char)
(or (<= #\a c #\f) (<= #\A c #\F) (<= #\0 c #\9))))
(def tochar (i)
(coerce i 'char))
(def hex (s)
(int s 16))
(def fourhex ()
(tochar:hex:string
(must "four hex digits required after \\u"
(n-of 4 (one hexdigit)))))
(def json-backslash-char (c)
(case c
#\" #\"
#\\ #\\
#\/ #\/
#\b #\backspace
#\f #\page
#\n #\newline
#\r #\return
#\t #\tab
(err "invalid backslash char" c)))
(def json-backslash-escape ()
(one #\\)
(alt (do (one #\u) (fourhex))
(json-backslash-char (next))))
(def json-string ()
(one #\")
(do1 (string (many (alt (json-backslash-escape)
(onenot #\"))))
(must "missing closing quote in JSON string"
(one #\"))))
(def json-value-here ()
(alt (json-false)
(json-true)
(json-null)
(json-number)
(json-string)))
(def json-value ()
(skipwhite)
(json-value-here))
(mac wrapped (begin end mustmsg body)
`(do ,begin
(do1 ,body
(skipwhite)
(must ,mustmsg ,end))))
(def json-array ()
(wrapped (one #\[) (one #\]) "missing ] in json array"
(comma-separated (json-value))))
(defalt json-value-here (json-array))
(def json-object-kv ()
(skipwhite)
(let key (json-string)
(skipwhite)
(must "a JSON object key string must be followed by a :" (one #\:))
(let value (json-value)
(list key value))))
(def json-object ()
(wrapped (one #\{) (one #\}) "missing } in JSON object"
(listtab (comma-separated (json-object-kv)))))
(defalt json-value-here (json-object))
;; todo this will ignore trailing garbage... do we care about that?
(def fromjson (s)
(match s (must (string "not a JSON value: " s) (json-value))))