size: 3 KiB

1-- Modified from
2-- json.lua
3-- Copyright (c) 2020 rxi
4--
5-- Permission is hereby granted, free of charge, to any person obtaining a copy of
6-- this software and associated documentation files (the "Software"), to deal in
7-- the Software without restriction, including without limitation the rights to
8-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9-- of the Software, and to permit persons to whom the Software is furnished to do
10-- so, subject to the following conditions:
11--
12-- The above copyright notice and this permission notice shall be included in all
13-- copies or substantial portions of the Software.
14--
15-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-- SOFTWARE.
22--
23-- Modifications to the original code:
24--
25-- * Removed JSON decoding code
26
27local json = { _version = "0.1.2" }
28
29-- Encode
30
31local encode
32
33local escape_char_map = {
34 [ "\\" ] = "\\",
35 [ "\"" ] = "\"",
36 [ "\b" ] = "b",
37 [ "\f" ] = "f",
38 [ "\n" ] = "n",
39 [ "\r" ] = "r",
40 [ "\t" ] = "t",
41}
42
43local escape_char_map_inv = { [ "/" ] = "/" }
44for k, v in pairs(escape_char_map) do
45 escape_char_map_inv[v] = k
46end
47
48
49local function escape_char(c)
50 return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
51end
52
53
54local function encode_nil(val)
55 return "null"
56end
57
58local function encode_table(val, stack)
59 local res = {}
60 stack = stack or {}
61
62 -- Circular reference?
63 if stack[val] then error("circular reference") end
64
65 stack[val] = true
66
67 if rawget(val, 1) ~= nil or next(val) == nil then
68 -- Treat as array -- check keys are valid and it is not sparse
69 local n = 0
70 for k in pairs(val) do
71 if type(k) ~= "number" then
72 error("invalid table: mixed or invalid key types")
73 end
74 n = n + 1
75 end
76 if n ~= #val then
77 error("invalid table: sparse array")
78 end
79 -- Encode
80 for i, v in ipairs(val) do
81 table.insert(res, encode(v, stack))
82 end
83 stack[val] = nil
84 return "[" .. table.concat(res, ",") .. "]"
85
86 else
87 -- Treat as an object
88 for k, v in pairs(val) do
89 if type(k) ~= "string" then
90 error("invalid table: mixed or invalid key types")
91 end
92 table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
93 end
94 stack[val] = nil
95 return "{" .. table.concat(res, ",") .. "}"
96 end
97end
98
99
100local function encode_string(val)
101 return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
102end
103
104
105local function encode_number(val)
106 -- Check for NaN, -inf and inf
107 if val ~= val or val <= -math.huge or val >= math.huge then
108 error("unexpected number value '" .. tostring(val) .. "'")
109 end
110 return string.format("%.14g", val)
111end
112
113
114local type_func_map = {
115 [ "nil" ] = encode_nil,
116 [ "table" ] = encode_table,
117 [ "string" ] = encode_string,
118 [ "number" ] = encode_number,
119 [ "boolean" ] = tostring,
120}
121
122
123encode = function(val, stack)
124 local t = type(val)
125 local f = type_func_map[t]
126 if f then
127 return f(val, stack)
128 end
129 error("unexpected type '" .. t .. "'")
130end
131
132
133function json.encode(val)
134 return ( encode(val) )
135end
136
137return json