View difference between Paste ID: ZsE9BvQM and H3gPsEeC
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