Skip to content

Instantly share code, notes, and snippets.

@OgelGames
Last active January 24, 2021 03:19
Show Gist options
  • Select an option

  • Save OgelGames/1b8f289fd53e5ac7ee1f44edc4d5400d to your computer and use it in GitHub Desktop.

Select an option

Save OgelGames/1b8f289fd53e5ac7ee1f44edc4d5400d to your computer and use it in GitHub Desktop.
Luacontroller JSON parser
-- JSON parser code for the Minetest Mesecons Luacontroller
-- License: CC0 1.0 Universal (public domain)
-- Based on https://gist.github.com/tylerneylon/59f4bcf316be525b30ab
-- Rewritten by OgelGames to work in the restricted Luacontroller sandbox
-- Designed to be copy-pasted into a standalone Luacontroller
if event.type ~= "digiline" or event.channel ~= "json" then
return
elseif type(event.msg) ~= "string" then
digiline_send("json", "Cannot parse non-string value!")
end
local sub, find, concat, tonum = string.sub, string.find, table.concat, tonumber
local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
local whitespace = {
[' '] = true, ['\b'] = true, ['\f'] = true, ['\n'] = true,
['\r'] = true, ['\t'] = true, ['\v'] = true
}
local digits = {
['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true,
['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, ['0'] = true,
['-'] = true, ['+'] = true, ['e'] = true, ['E'] = true, ['.'] = true
}
local function skip_chars(str, pos, chars)
local c ; while pos <= #str do
c = sub(str, pos, pos)
if not chars[c] then return pos, c end
pos = pos + 1
end
end
local function check_delim(str, pos, delim, err)
if not pos then return end
local c ; pos, c = skip_chars(str, pos, whitespace)
if c ~= delim then
if err then return end ; return pos, false
end
return pos + 1, true
end
local function find_str_end(str, pos)
local a = find(str, '"', pos, true)
local b = find(str, '\\', pos, true)
if not a or not b then return a or b, (a and '"') or (b and '\\')
elseif a < b then return a, '"' end ; return b, '\\'
end
local function parse_json(str, pos, end_delim)
pos = pos or 1 ; local first
if pos > #str then return end
pos, first = skip_chars(str, pos, whitespace)
if first == end_delim then
return nil, pos + 1
elseif first == '{' then
local t, f , k = {}, true ; pos = pos + 1
while true do
k, pos = parse_json(str, pos, '}') ; if not pos then return end
if k == nil then return t, pos end ; if not f then return end
pos = check_delim(str, pos, ':', true) ; if not pos then return end
t[k], pos = parse_json(str, pos) ; if not pos then return end
pos, f = check_delim(str, pos, ',')
end
elseif first == '[' then
local a, f, v = {}, true ; pos = pos + 1
while true do
v, pos = parse_json(str, pos, ']') ; if not pos then return end
if v == nil then return a, pos end ; if not f then return end
a[#a + 1] = v ; pos, f = check_delim(str, pos, ',')
end
elseif first == '"' then
local p, i, c = {} ; pos = pos + 1
while true do
i, c = find_str_end(str, pos)
if not c then return end
p[#p + 1] = sub(str, pos, i-1) ; i = i + 1
if c == '"' then return concat(p), i end
local nc = sub(str, i, i)
p[#p + 1] = esc_map[nc] or nc ; pos = i + 1
end
elseif digits[first] then
local i = skip_chars(str, pos, digits)
local num = tonum(sub(str, pos, i - 1))
if not num then return end ; return num, i
else
local s = sub(str, pos, pos + 3)
if s == 'true' then return true, pos + 4 end
if s == 'null' then return {}, pos + 4 end
s = sub(str, pos, pos + 4)
if s == 'false' then return false, pos + 5 end
end
end
digiline_send("json", parse_json(event.msg) or "Error parsing json!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment