SHOW:
|
|
- or go back to the newest paste.
1 | local json = {} | |
2 | do | |
3 | ||
4 | local valuePipes = {} | |
5 | ||
6 | - | local function pipeValue(json, copyPos, pos) |
6 | + | local function pipeValue(jsonStr, copyPos, pos) |
7 | - | local cPos, c = json:match('()(%S)', pos) |
7 | + | local cPos, c = jsonStr:match('()(%S)', pos) |
8 | if not c then | |
9 | error('unexpected end of input') | |
10 | end | |
11 | local pipe = valuePipes[c] | |
12 | if not pipe then | |
13 | error('invalid JSON at: ' .. cPos) | |
14 | end | |
15 | - | return pipe(json, copyPos, cPos) |
15 | + | return pipe(jsonStr, copyPos, cPos) |
16 | end | |
17 | ||
18 | - | function json.parse(json) |
18 | + | function json.parse(jsonStr) |
19 | local chunk = assert(load(coroutine.wrap(function() | |
20 | - | coroutine.yield('return ') |
20 | + | coroutine.yield('local json = ...; return ') |
21 | - | local copyPos, pos = pipeValue(json, 1, 1) |
21 | + | local copyPos, pos = pipeValue(jsonStr, 1, 1) |
22 | - | local invalidPos = json:match('()%S', pos) |
22 | + | local invalidPos = jsonStr:match('()%S', pos) |
23 | if invalidPos then | |
24 | error('invalid JSON at: ' .. invalidPos) | |
25 | end | |
26 | if (copyPos < pos) then | |
27 | - | coroutine.yield(json:sub(copyPos)) |
27 | + | coroutine.yield(jsonStr:sub(copyPos)) |
28 | end | |
29 | end))) | |
30 | - | return chunk() |
30 | + | return chunk(json) |
31 | end | |
32 | ||
33 | - | local function pipeStringContent(json, copyPos, pos) |
33 | + | local function pipeStringContent(jsonStr, copyPos, pos) |
34 | while true do | |
35 | - | local cPos, c = json:match('()(["\\])', pos) |
35 | + | local cPos, c = jsonStr:match('()(["\\])', pos) |
36 | if (c == '"') then | |
37 | return copyPos, cPos+1 | |
38 | elseif (c == '\\') then | |
39 | - | local escape = json:sub(cPos+1, cPos+1) |
39 | + | local escape = jsonStr:sub(cPos+1, cPos+1) |
40 | if (escape == 'u') then | |
41 | - | local code = tonumber(json:sub(cPos+2, cPos+5), 16) |
41 | + | local code = tonumber(jsonStr:sub(cPos+2, cPos+5), 16) |
42 | if not code then | |
43 | error('invalid string escape') | |
44 | end | |
45 | if (code < 0x80) then | |
46 | code = string.format('\\%03d', code) | |
47 | elseif (code < 0x800) then | |
48 | code = string.format('\\%03d\\%03d', | |
49 | 0xC0 + math.floor(code/0x40), | |
50 | 0x80 + code%0x40) | |
51 | else | |
52 | code = string.format('\\%03d\\%03d\\%03d', | |
53 | 0xE0 + math.floor(code/0x1000), | |
54 | 0x80 + math.floor(code/0x40)%0x40, | |
55 | 0x80 + code%0x40) | |
56 | end | |
57 | - | coroutine.yield(json:sub(copyPos, cPos-1) .. code) |
57 | + | coroutine.yield(jsonStr:sub(copyPos, cPos-1) .. code) |
58 | copyPos = cPos+6 | |
59 | pos = copyPos | |
60 | elseif escape == '/' then | |
61 | - | coroutine.yield(json:sub(copyPos, cPos-1) .. '/') |
61 | + | coroutine.yield(jsonStr:sub(copyPos, cPos-1) .. '/') |
62 | pos = cPos+2 | |
63 | copyPos = pos | |
64 | elseif escape:match('["\\bfnrt]') then | |
65 | pos = cPos+2 | |
66 | else | |
67 | error('invalid string escape') | |
68 | end | |
69 | else | |
70 | error('unexpected end of input') | |
71 | end | |
72 | end | |
73 | end | |
74 | ||
75 | - | valuePipes['['] = function(json, copyPos, pos) |
75 | + | valuePipes['['] = function(jsonStr, copyPos, pos) |
76 | - | coroutine.yield(json:sub(copyPos, pos-1) .. 'json.array{') |
76 | + | coroutine.yield(jsonStr:sub(copyPos, pos-1) .. 'json.array{') |
77 | copyPos = pos+1 | |
78 | pos = copyPos | |
79 | - | local emptyPos = json:match('^%s*%]()', copyPos) |
79 | + | local emptyPos = jsonStr:match('^%s*%]()', copyPos) |
80 | if emptyPos then | |
81 | coroutine.yield('}') | |
82 | return emptyPos, emptyPos | |
83 | end | |
84 | while true do | |
85 | - | copyPos, pos = pipeValue(json, copyPos, pos) |
85 | + | copyPos, pos = pipeValue(jsonStr, copyPos, pos) |
86 | - | local cPos, c = json:match('()(%S)', pos) |
86 | + | local cPos, c = jsonStr:match('()(%S)', pos) |
87 | if not c then | |
88 | error('unexpected end of input') | |
89 | end | |
90 | if (c == ']') then | |
91 | - | coroutine.yield(json:sub(copyPos, cPos-1) .. '}') |
91 | + | coroutine.yield(jsonStr:sub(copyPos, cPos-1) .. '}') |
92 | return cPos+1, cPos+1 | |
93 | elseif (c ~= ',') then | |
94 | error('invalid JSON at: ' .. cPos) | |
95 | end | |
96 | pos = cPos+1 | |
97 | end | |
98 | end | |
99 | - | valuePipes['"'] = function(json, copyPos, pos) |
99 | + | valuePipes['"'] = function(jsonStr, copyPos, pos) |
100 | - | return pipeStringContent(json, copyPos, pos+1) |
100 | + | return pipeStringContent(jsonStr, copyPos, pos+1) |
101 | end | |
102 | - | valuePipes['{'] = function(json, copyPos, pos) |
102 | + | valuePipes['{'] = function(jsonStr, copyPos, pos) |
103 | pos = pos + 1 | |
104 | - | local emptyPos = json:match('^%s*%}()', pos) |
104 | + | local emptyPos = jsonStr:match('^%s*%}()', pos) |
105 | if emptyPos then | |
106 | return copyPos, emptyPos | |
107 | end | |
108 | while true do | |
109 | - | local keyPos, key = json:match('^%s*()(%S)', pos) |
109 | + | local keyPos, key = jsonStr:match('^%s*()(%S)', pos) |
110 | if (key ~= '"') then | |
111 | if not keyPos then | |
112 | error('unexpected end of input') | |
113 | end | |
114 | error('invalid JSON at: ' .. pos) | |
115 | end | |
116 | - | coroutine.yield(json:sub(copyPos, keyPos-1) .. '["') |
116 | + | coroutine.yield(jsonStr:sub(copyPos, keyPos-1) .. '["') |
117 | - | copyPos, pos = pipeStringContent(json, keyPos+1, keyPos+1) |
117 | + | copyPos, pos = pipeStringContent(jsonStr, keyPos+1, keyPos+1) |
118 | - | local valPos, v = json:match('^%s*()(%S)', pos) |
118 | + | local valPos, v = jsonStr:match('^%s*()(%S)', pos) |
119 | if (v ~= ':') then | |
120 | if not valPos then | |
121 | error('unexpected end of input') | |
122 | end | |
123 | error('invalid JSON at: ' .. pos) | |
124 | end | |
125 | - | coroutine.yield(json:sub(copyPos, pos-1) .. ']=') |
125 | + | coroutine.yield(jsonStr:sub(copyPos, pos-1) .. ']=') |
126 | - | copyPos, pos = pipeValue(json, valPos+1, valPos+1) |
126 | + | copyPos, pos = pipeValue(jsonStr, valPos+1, valPos+1) |
127 | - | local cPos, c = json:match('()(%S)', pos) |
127 | + | local cPos, c = jsonStr:match('()(%S)', pos) |
128 | if not c then | |
129 | error('unexpected end of input') | |
130 | end | |
131 | pos = cPos + 1 | |
132 | if (c == '}') then | |
133 | return copyPos, pos | |
134 | elseif (c ~= ',') then | |
135 | error('invalid JSON at: ' .. cPos) | |
136 | end | |
137 | end | |
138 | end | |
139 | - | valuePipes['t'] = function(json, copyPos, pos) |
139 | + | valuePipes['t'] = function(jsonStr, copyPos, pos) |
140 | - | assert(json:sub(pos, pos+3) == 'true', 'invalid JSON at: ' .. pos) |
140 | + | assert(jsonStr:sub(pos, pos+3) == 'true', 'invalid JSON at: ' .. pos) |
141 | return copyPos, pos+4 | |
142 | end | |
143 | - | valuePipes['f'] = function(json, copyPos, pos) |
143 | + | valuePipes['f'] = function(jsonStr, copyPos, pos) |
144 | - | assert(json:sub(pos, pos+4) == 'false', 'invalid JSON at: ' .. pos) |
144 | + | assert(jsonStr:sub(pos, pos+4) == 'false', 'invalid JSON at: ' .. pos) |
145 | return copyPos, pos+5 | |
146 | end | |
147 | - | valuePipes['n'] = function(json, copyPos, pos) |
147 | + | valuePipes['n'] = function(jsonStr, copyPos, pos) |
148 | - | assert(json:sub(pos, pos+3) == 'null', 'invalid JSON at: ' .. pos) |
148 | + | assert(jsonStr:sub(pos, pos+3) == 'null', 'invalid JSON at: ' .. pos) |
149 | - | coroutine.yield(json:sub(copyPos, pos-1) .. 'json.') |
149 | + | coroutine.yield(jsonStr:sub(copyPos, pos-1) .. 'json.') |
150 | return pos, pos+4 | |
151 | end | |
152 | - | local function numParser(json, copyPos, pos) |
152 | + | local function numParser(jsonStr, copyPos, pos) |
153 | - | local afterPos = json:match('^%-?[0-9]+()', pos) |
153 | + | local afterPos = jsonStr:match('^%-?[0-9]+()', pos) |
154 | if not afterPos then | |
155 | error('invalid JSON at: ' .. pos) | |
156 | end | |
157 | - | afterPos = json:match('^%.[0-9]+()', afterPos) or afterPos |
157 | + | afterPos = jsonStr:match('^%.[0-9]+()', afterPos) or afterPos |
158 | - | afterPos = json:match('^[eE][%+%-]?[0-9]+()', afterPos) or afterPos |
158 | + | afterPos = jsonStr:match('^[eE][%+%-]?[0-9]+()', afterPos) or afterPos |
159 | return copyPos, afterPos | |
160 | end | |
161 | for i = 0, 9 do | |
162 | valuePipes[tostring(i)] = numParser | |
163 | end | |
164 | valuePipes['-'] = numParser | |
165 | ||
166 | -- override to replace default functionality | |
167 | json.null = nil | |
168 | json.array = function(a) | |
169 | return a | |
170 | end | |
171 | ||
172 | end | |
173 | - | return json |
173 | + | return json |
174 | ||
175 |