Last active
January 24, 2021 03:19
-
-
Save OgelGames/1b8f289fd53e5ac7ee1f44edc4d5400d to your computer and use it in GitHub Desktop.
Luacontroller JSON parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- 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