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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
# A JSON text (RFC 8259) read into a tree of values, then walked breadth first for a digest of it: how many of each
# kind, the numbers' sum, the strings' and the keys' bytes. Input that is no JSON text leaves valid false.
variant Json {
null
bool(bool)
num(number)
str(text)
arr(list of Json)
obj(list of Member)
}
record Member {
name: text
value: Json
}
record Open {
items: list of Json
members: list of Member
name: text
object = false
}
state valid = false
state nulls = 0
state trues = 0
state falses = 0
state numbers = 0
state strings = 0
state arrays = 0
state objects = 0
state sum = 0
state text_bytes = 0
state key_bytes = 0
input check = message { data: bytes }
fn space(b) = b == 0x20 || b == 0x09 || b == 0x0a || b == 0x0d
fn digit(b) = b >= 0x30 && b <= 0x39
fn hex(b) = digit(b) || (b >= 0x61 && b <= 0x66) || (b >= 0x41 && b <= 0x46)
fn nibble(b) = if digit(b) { b - 0x30 } else if b >= 0x61 { b - 0x57 } else { b - 0x37 }
on check {
nulls, trues, falses, numbers, strings, arrays, objects, sum, text_bytes, key_bytes = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
let d = bytes(text(check.data))
let n, i, ok, mode = d.bytes, 0, true, 0 # mode 0: a value, 1: after one, 2: a key, 3: a key or }, 4: a value or ]
let root: list of Json
let open: list of Open
let v: list of Json # the value just read, then placed
let q: list of Json # the tree's values, breadth first
while ok {
while i < n && space(d[i]) { i = i + 1 }
if i == n {
ok = mode == 1 && open.count == 0
break
}
let b = d[i]
if mode == 1 {
if open.count == 0 { ok = false }
else if b == 0x2c { mode = if open.last.object { 2 } else { 0 } }
else if b == 0x5d && !open.last.object { v.append(Json.arr(open.last.items)) }
else if b == 0x7d && open.last.object { v.append(Json.obj(open.last.members)) }
else { ok = false }
if v.count > 0 { open.remove(open.last) }
i = i + 1
} else if mode == 3 && b == 0x7d || mode == 4 && b == 0x5d {
if b == 0x7d { v.append(Json.obj(open.last.members)) } else { v.append(Json.arr(open.last.items)) }
open.remove(open.last)
i = i + 1
} else if mode == 2 || mode == 3 {
ok = b == 0x22
mode = 5 # the key, then ':'
} else if b == 0x5b || b == 0x7b {
open.append(Open { object: b == 0x7b })
mode = if b == 0x5b { 4 } else { 3 }
i = i + 1
} else if b == 0x22 || mode == 5 {
i = i + 1 # a string: its bytes, escapes decoded
let s = d[i .. i]
while ok && i < n && d[i] != 0x22 {
let start = i
while i < n && d[i] != 0x22 && d[i] != 0x5c && d[i] >= 0x20 { i = i + 1 }
s = s + d[start .. i]
if i < n && d[i] < 0x20 { ok = false }
else if i + 1 < n && d[i] == 0x5c {
let e = d[i + 1]
if e == 0x75 {
ok = i + 5 < n && hex(d[i + 2]) && hex(d[i + 3]) && hex(d[i + 4]) && hex(d[i + 5])
let u = if ok { nibble(d[i + 2]) << 12 | nibble(d[i + 3]) << 8 | nibble(d[i + 4]) << 4 | nibble(d[i + 5]) } else { 0 }
i = i + 6
if (u >= 0xd800 && u < 0xdc00 && i + 5 < n && d[i] == 0x5c && d[i + 1] == 0x75 && hex(d[i + 2]) && hex(d[i + 3]) &&
hex(d[i + 4]) && hex(d[i + 5])) {
let low = nibble(d[i + 2]) << 12 | nibble(d[i + 3]) << 8 | nibble(d[i + 4]) << 4 | nibble(d[i + 5])
if low >= 0xdc00 && low < 0xe000 {
u = 0x10000 + ((u - 0xd800) << 10 | low - 0xdc00)
i = i + 6
}
}
if u < 0x80 { s = s + byte(u) }
else if u < 0x800 { s = s + byte(0xc0 | u >> 6) + byte(0x80 | u & 0x3f) }
else if u < 0x10000 { s = s + byte(0xe0 | u >> 12) + byte(0x80 | u >> 6 & 0x3f) + byte(0x80 | u & 0x3f) }
else { s = s + byte(0xf0 | u >> 18) + byte(0x80 | u >> 12 & 0x3f) + byte(0x80 | u >> 6 & 0x3f) + byte(0x80 | u & 0x3f) }
} else {
let to = (if e == 0x62 { 0x08 } else if e == 0x66 { 0x0c } else if e == 0x6e { 0x0a } else if e == 0x72 { 0x0d }
else if e == 0x74 { 0x09 } else { e })
ok = e == 0x22 || e == 0x5c || e == 0x2f || e == 0x62 || e == 0x66 || e == 0x6e || e == 0x72 || e == 0x74
s = s + byte(to)
i = i + 2
}
} else if i < n && d[i] == 0x5c { ok = false }
}
ok = ok && i < n
i = i + 1
if mode == 5 {
open[open.count - 1].name = text(s)
while i < n && space(d[i]) { i = i + 1 }
ok = ok && i < n && d[i] == 0x3a
i = i + 1
mode = 0
} else { v.append(Json.str(text(s))) }
} else if b == 0x2d || digit(b) { # -?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?: its text read as a number
let start = i
if b == 0x2d { i = i + 1 }
while i < n && (digit(d[i]) || d[i] == 0x2e || d[i] == 0x65 || d[i] == 0x45 || d[i] == 0x2b || d[i] == 0x2d) { i = i + 1 }
v.append(Json.num(number(text(d[start .. i]))))
} else {
let word = if b == 0x74 { "true" } else if b == 0x66 { "false" } else { "null" }
ok = i + word.bytes <= n && text(d[i .. i + word.bytes]) == word
i = i + word.bytes
if ok && b == 0x74 { v.append(Json.bool(true)) }
else if ok && b == 0x66 { v.append(Json.bool(false)) }
else if ok { v.append(Json.null) }
}
if ok && v.count > 0 { # a value read: placed in what is open, or the root
if open.count == 0 {
ok = root.count == 0
root.append(v.last)
} else if open.last.object { open.last.members.append(Member { name: open.last.name, value: v.last }) }
else { open.last.items.append(v.last) }
v.remove(v.last)
mode = 1
}
}
valid = ok
if ok {
q.append(root.first)
let at = 0
while at < q.count {
match q[at] {
null => nulls = nulls + 1
bool(t) => if t { trues = trues + 1 } else { falses = falses + 1 }
num(x) => {
numbers = numbers + 1
sum = sum + x
}
str(t) => {
strings = strings + 1
text_bytes = text_bytes + t.bytes
}
arr(items) => {
arrays = arrays + 1
for y in items { q.append(y) }
}
obj(members) => {
objects = objects + 1
for m in members {
key_bytes = key_bytes + m.name.bytes
q.append(m.value)
}
}
}
at = at + 1
}
}
}
|