-
-
Save jfkinslow/a5d04e3946d03cce0bc7c4038cffc1c7 to your computer and use it in GitHub Desktop.
Pure Lua json library.
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.lua | |
| -- | |
| -- A function to stringify a Lua object into json. | |
| -- | |
| -- This expects the following to be true of any tables | |
| -- being encoded: | |
| -- * They only have string or number keys. | |
| -- Number keys must be represented as strings in json; | |
| -- this is part of the json spec. | |
| -- * They are not recursive. Such a structure cannot be | |
| -- specified in json. | |
| -- | |
| -- A Lua table is considered to be an array if and only if | |
| -- its set of keys is a consecutive sequence of positive | |
| -- integers starting at 1. Arrays are encoded like so: | |
| -- [2, 3, false, "hi"]. Any other type of Lua table is | |
| -- encoded as a json object, encoded like so: | |
| -- {"key1": 2, "key2": false}. | |
| -- | |
| -- Because the Lua nil value cannot be a key, and as a | |
| -- table value is considerd equivalent to a missing key, | |
| -- there is no way to express the json "null" value in a | |
| -- Lua table. The only way this will output "null" is if | |
| -- your entire input obj is nil itself. | |
| -- | |
| -- An empty Lua table, {}, could be considered either a | |
| -- json object or array - it's an ambiguous edge case. | |
| -- We choose to treat this as an object as it is the | |
| -- more general type. | |
| -- | |
| -- To be clear, none of the above considerations is a | |
| -- limitation of this code. Rather, it is what we get when | |
| -- we completely observe the json specification for | |
| -- as arbitrary a Lua object as json is capable of | |
| -- expressing. | |
| -- | |
| function kind_of(obj) | |
| if type(obj) ~= 'table' then return type(obj) end | |
| local i = 1 | |
| for _ in pairs(obj) do | |
| if obj[i] ~= nil then i = i + 1 else return 'table' end | |
| end | |
| if i == 1 then return 'table' else return 'array' end | |
| end | |
| function escape_str(s) | |
| local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} | |
| local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} | |
| for i, c in ipairs(in_char) do | |
| s = s:gsub(c, '\\' .. out_char[i]) | |
| end | |
| return s | |
| end | |
| function json_stringify(obj, as_key) | |
| local s = {} -- We'll build the string as an array of strings to be concatenated. | |
| local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. | |
| if kind == 'array' then | |
| if as_key then error('Can\'t encode array as key.') end | |
| s[#s + 1] = '[' | |
| for i, val in ipairs(obj) do | |
| if i > 1 then s[#s + 1] = ', ' end | |
| s[#s + 1] = json_stringify(val) | |
| end | |
| s[#s + 1] = ']' | |
| elseif kind == 'table' then | |
| if as_key then error('Can\'t encode table as key.') end | |
| s[#s + 1] = '{' | |
| for k, v in pairs(obj) do | |
| if #s > 1 then s[#s + 1] = ', ' end | |
| s[#s + 1] = json_stringify(k, true) | |
| s[#s + 1] = ':' | |
| s[#s + 1] = json_stringify(v) | |
| end | |
| s[#s + 1] = '}' | |
| elseif kind == 'string' then | |
| return '"' .. escape_str(obj) .. '"' | |
| elseif kind == 'number' then | |
| if as_key then return '"' .. tostring(obj) .. '"' end | |
| return tostring(obj) | |
| elseif kind == 'boolean' then | |
| return tostring(obj) | |
| elseif kind == 'nil' then | |
| return 'null' | |
| else | |
| error('Unjsonifiable type: ' .. kind .. '.') | |
| end | |
| return table.concat(s) | |
| end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment