-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson.lua
193 lines (179 loc) · 3.7 KB
/
json.lua
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
local next = next
local type = type
local pcall = pcall
local pairs = pairs
local ipairs = ipairs
local assert = assert
local tostring = tostring
local tonumber = tonumber
local tconcat = table.concat
local format = string.format
local find = string.find
local sub = string.sub
local gsub = string.gsub
local byte = string.byte
local json = {}
---------encode
local encode_func
local function encodebool(b)
return b and "true" or "false"
end
local function encodenumber(n)
return tostring(n)
end
local escape = {
['"'] = '\\"',
['\\'] = '\\\\',
['/'] = '\\/',
}
local unescape = {}
do
for k, v in pairs(escape) do
unescape[v] = k
end
end
local function encodestring(s)
s = gsub(s, '["\\/]', escape)
return format('"%s"', s)
end
local function encodeobj(obj)
if obj[1] ~= nil or next(obj) == nil then --array
local str = {}
for _, v in ipairs(obj) do
v = encode_func[type(v)](v)
str[#str + 1] = v
end
return format("[%s]", tconcat(str, ","))
else --object
local str = {}
for k, v in pairs(obj) do
v = encode_func[type(v)](v)
str[#str + 1] = format("%s:%s", encodestring(k), v)
end
return format("{%s}", tconcat(str, ","))
end
end
encode_func = {
['table'] = encodeobj,
['boolean'] = encodebool,
['number'] = encodenumber,
['string'] = encodestring,
}
----------decode
-- { -> 0x7b , } -> 0x7D, [ -> 0x5B, ] -> 0x5D, : -> 0x3A, " -> 0x22
local decode_func
local function skipspace(str, i)
return find(str, "[^%s]", i)
end
local function decodestr(str, i)
local _, n = find(str, '[^\\]"', i)
local s = sub(str, i + 1, n - 1)
return gsub(s, '(\\["\\/])', unescape), n + 1
end
local function decodebool(str, i)
local n = find(str, "[%s,}]", i)
local k = sub(str, i, n - 1)
if k == "true" then
return true, n
elseif k == "false" then
return false, n
else
assert(false, k)
end
end
local function decodenull(str, i)
local n = find(str, "[%s,}]", i)
local k = sub(str, i, n - 1)
if k == "null" then
return nil, n
else
assert(false, k)
end
end
local function decodenumber(str, i)
local n = find(str, "[%s,}]", i)
local k = sub(str, i, n - 1)
return tonumber(k), n
end
local function decodeobj(str, i)
local len = #str
local obj = {}
i = skipspace(str, i)
if byte(str, i) ~= 0x7b then -- '{'
assert(false, [[need '{']])
end
i = i + 1
while true do
local k, v
i = skipspace(str, i)
local ch = byte(str, i)
if ch == 0x7D then -- '}'
break
end
if ch ~= 0x22 then -- '"'
assert(false, [[need '"']])
end
k, i = decodestr(str, i)
i = skipspace(str, i)
if byte(str, i) ~= 0x3A then
assert(false, [[need ':']])
end
i = skipspace(str, i + 1)
local n = byte(str, i)
v, i = assert(decode_func[n], n)(str, i)
obj[k] = v
i = skipspace(str, i)
if byte(str, i) == 0x2C then -- ','
i = i + 1
end
end
return obj, i + 1
end
local function decodearr(str, i)
local ai = 0
local arr = {}
i = i + 1
while true do
i = skipspace(str, i)
local ch = byte(str, i)
if ch == 0x5D then -- ']'
break
end
ai = ai + 1
arr[ai], i = assert(decode_func[ch], ch)(str, i)
i = skipspace(str, i)
if byte(str, i) == 0x2C then -- ','
i = i + 1
end
end
return arr, i + 1
end
decode_func = {
[0x7b] = decodeobj, --'{'
[0x5b] = decodearr, --'['
[0x22] = decodestr, --'"'
[0x66] = decodebool, --'f'
[0x74] = decodebool, --'t'
[0x6e] = decodenull, --'n'
[0x2d] = decodenumber, --'-'
}
for i = 0x30, 0x39 do
decode_func[i] = decodenumber
end
---------interface
function json.encode(obj)
return encodeobj(obj)
end
function json.decode(str)
local i = skipspace(str)
local cb = decode_func[str:byte(i)]
if not cb then
return nil, " invalid json"
end
local ok, obj, i = pcall(cb, str, i)
if not ok then
return nil, obj
end
return obj, i
end
return json