Skip to content

Instantly share code, notes, and snippets.

@jfkinslow
Forked from tylerneylon/json.lua
Created July 18, 2021 01:11
Show Gist options
  • Select an option

  • Save jfkinslow/a5d04e3946d03cce0bc7c4038cffc1c7 to your computer and use it in GitHub Desktop.

Select an option

Save jfkinslow/a5d04e3946d03cce0bc7c4038cffc1c7 to your computer and use it in GitHub Desktop.
Pure Lua json library.
-- 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