Skip to content
Snippets Groups Projects
Commit 242d5ed3 authored by 最萌小汐's avatar 最萌小汐
Browse files

update json.lua

parent 67945d4e
Branches
No related tags found
No related merge requests found
......@@ -25,17 +25,22 @@ local function encode_newline()
end
local encode_map = {}
for k ,v in next, json.encode_map do
local encode_string = json._encode_string
for k ,v in next, json._encode_map do
encode_map[k] = v
end
local encode_string = json.encode_map.string
local function encode(v)
local res = encode_map[type(v)](v)
statusQue[#statusQue+1] = res
end
function encode_map.string(v)
statusQue[#statusQue+1] = '"'
statusQue[#statusQue+1] = encode_string(v)
return '"'
end
function encode_map.table(t)
local first_val = next(t)
if first_val == nil then
......@@ -62,15 +67,17 @@ function encode_map.table(t)
statusDep = statusDep + 1
encode_newline()
local k = key[1]
statusQue[#statusQue+1] = '"'
statusQue[#statusQue+1] = encode_string(k)
statusQue[#statusQue+1] = ": "
statusQue[#statusQue+1] = '": '
encode(t[k])
for i = 2, #key do
local k = key[i]
statusQue[#statusQue+1] = ","
encode_newline()
statusQue[#statusQue+1] = '"'
statusQue[#statusQue+1] = encode_string(k)
statusQue[#statusQue+1] = ": "
statusQue[#statusQue+1] = '": '
encode(t[k])
end
statusDep = statusDep - 1
......
......@@ -16,14 +16,17 @@ local string_format = string.format
local math_type = math.type
local setmetatable = setmetatable
local getmetatable = getmetatable
local Inf = math.huge
local huge = math.huge
local tiny = -huge
local json = {}
json.object = {}
json.supportSparseArray = true
-- json.encode --
local statusMark
local statusQue
local statusVisited
local statusBuilder
local encode_map = {}
......@@ -54,17 +57,22 @@ end
local function encode(v)
local res = encode_map[type(v)](v)
statusQue[#statusQue+1] = res
statusBuilder[#statusBuilder+1] = res
end
encode_map["nil"] = function ()
return "null"
end
local function encode_string(v)
return string_gsub(v, '[\0-\31\\"]', encode_escape_map)
end
function encode_map.string(v)
return '"' .. string_gsub(v, '[\0-\31\\"]', encode_escape_map) .. '"'
statusBuilder[#statusBuilder+1] = '"'
statusBuilder[#statusBuilder+1] = encode_string(v)
return '"'
end
local encode_string = encode_map.string
local function convertreal(v)
local g = string_format('%.16g', v)
......@@ -74,11 +82,18 @@ local function convertreal(v)
return string_format('%.17g', v)
end
if string_match(tostring(1/2), "%p") == "," then
local _convertreal = convertreal
function convertreal(v)
return string_gsub(_convertreal(v), ',', '.')
end
end
function encode_map.number(v)
if v ~= v or v <= -Inf or v >= Inf then
if v ~= v or v <= tiny or v >= huge then
error("unexpected number value '" .. tostring(v) .. "'")
end
return string_gsub(convertreal(v), ',', '.')
return convertreal(v)
end
function encode_map.boolean(v)
......@@ -98,50 +113,55 @@ function encode_map.table(t)
return "[]"
end
end
if statusMark[t] then
if statusVisited[t] then
error("circular reference")
end
statusMark[t] = true
statusVisited[t] = true
if type(first_val) == 'string' then
local key = {}
local keys = {}
for k in next, t do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
key[#key+1] = k
keys[#keys+1] = k
end
table_sort(key)
statusQue[#statusQue+1] = "{"
local k = key[1]
statusQue[#statusQue+1] = encode_string(k)
statusQue[#statusQue+1] = ":"
table_sort(keys)
local k = keys[1]
statusBuilder[#statusBuilder+1] = '{"'
statusBuilder[#statusBuilder+1] = encode_string(k)
statusBuilder[#statusBuilder+1] = '":'
encode(t[k])
for i = 2, #key do
local k = key[i]
statusQue[#statusQue+1] = ","
statusQue[#statusQue+1] = encode_string(k)
statusQue[#statusQue+1] = ":"
for i = 2, #keys do
local k = keys[i]
statusBuilder[#statusBuilder+1] = ',"'
statusBuilder[#statusBuilder+1] = encode_string(k)
statusBuilder[#statusBuilder+1] = '":'
encode(t[k])
end
statusMark[t] = nil
statusVisited[t] = nil
return "}"
else
local count = 0
local max = 0
for k in next, t do
if math_type(k) ~= "integer" or k <= 0 then
error("invalid table: mixed or invalid key types")
end
count = count + 1
if max < k then
max = k
end
end
statusQue[#statusQue+1] = "["
if not json.supportSparseArray and count ~= max then
error("sparse array are not supported")
end
statusBuilder[#statusBuilder+1] = "["
encode(t[1])
for i = 2, max do
statusQue[#statusQue+1] = ","
statusBuilder[#statusBuilder+1] = ","
encode(t[i])
end
statusMark[t] = nil
statusVisited[t] = nil
return "]"
end
end
......@@ -158,13 +178,14 @@ encode_map[ "userdata" ] = encode_unexpected
encode_map[ "thread" ] = encode_unexpected
function json.encode(v)
statusMark = {}
statusQue = {}
statusVisited = {}
statusBuilder = {}
encode(v)
return table_concat(statusQue)
return table_concat(statusBuilder)
end
json.encode_map = encode_map
json._encode_map = encode_map
json._encode_string = encode_string
-- json.decode --
......@@ -200,12 +221,20 @@ local function get_word()
end
local function next_byte()
statusPos = string_find(statusBuf, "[^ \t\r\n]", statusPos)
if statusPos then
return string_byte(statusBuf, statusPos)
local pos = string_find(statusBuf, "[^ \t\r\n]", statusPos)
if pos then
statusPos = pos
return string_byte(statusBuf, pos)
end
return -1
end
local function consume_byte(c)
local _, pos = string_find(statusBuf, c, statusPos)
if pos then
statusPos = pos + 1
return true
end
statusPos = #statusBuf + 1
decode_error("unexpected character '<eol>'")
end
local function expect_byte(c)
......@@ -272,49 +301,46 @@ local function decode_string()
end
local function decode_number()
local word = get_word()
if not (
string_match(word, '^.[0-9]*$')
or string_match(word, '^.[0-9]*%.[0-9]+$')
or string_match(word, '^.[0-9]*[Ee][+-]?[0-9]+$')
or string_match(word, '^.[0-9]*%.[0-9]+[Ee][+-]?[0-9]+$')
) then
decode_error("invalid number '" .. word .. "'")
local num, c = string_match(statusBuf, '^([0-9]+%.?[0-9]*)([eE]?)', statusPos)
if not num or string_byte(num, -1) == 0x2E --[[ "." ]] then
decode_error("invalid number '" .. get_word() .. "'")
end
statusPos = statusPos + #word
return tonumber(word)
if c ~= '' then
num = string_match(statusBuf, '^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]', statusPos)
if not num then
decode_error("invalid number '" .. get_word() .. "'")
end
local function decode_number_negative()
local word = get_word()
if not (
string_match(word, '^.[1-9][0-9]*$')
or string_match(word, '^.[1-9][0-9]*%.[0-9]+$')
or string_match(word, '^.[1-9][0-9]*[Ee][+-]?[0-9]+$')
or string_match(word, '^.[1-9][0-9]*%.[0-9]+[Ee][+-]?[0-9]+$')
or word == "-0"
or string_match(word, '^.0%.[0-9]+$')
or string_match(word, '^.0[Ee][+-]?[0-9]+$')
or string_match(word, '^.0%.[0-9]+[Ee][+-]?[0-9]+$')
) then
decode_error("invalid number '" .. word .. "'")
end
statusPos = statusPos + #word
return tonumber(word)
end
statusPos = statusPos + #num
return tonumber(num)
end
local function decode_number_zero()
local word = get_word()
if not (
#word == 1
or string_match(word, '^.%.[0-9]+$')
or string_match(word, '^.[Ee][+-]?[0-9]+$')
or string_match(word, '^.%.[0-9]+[Ee][+-]?[0-9]+$')
) then
decode_error("invalid number '" .. word .. "'")
local num, c = string_match(statusBuf, '^(.%.?[0-9]*)([eE]?)', statusPos)
if not num or string_byte(num, -1) == 0x2E --[[ "." ]] or string_match(statusBuf, '^.[0-9]+', statusPos) then
decode_error("invalid number '" .. get_word() .. "'")
end
if c ~= '' then
num = string_match(statusBuf, '^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]', statusPos)
if not num then
decode_error("invalid number '" .. get_word() .. "'")
end
end
statusPos = statusPos + #num
return tonumber(num)
end
local function decode_number_negative()
statusPos = statusPos + 1
local c = string_byte(statusBuf, statusPos)
if c then
if c == 0x30 then
return -decode_number_zero()
elseif c > 0x30 and c < 0x3A then
return -decode_number()
end
statusPos = statusPos + #word
return tonumber(word)
end
decode_error("invalid number '" .. get_word() .. "'")
end
local function decode_true()
......@@ -344,8 +370,7 @@ end
local function decode_array()
statusPos = statusPos + 1
local res = {}
if next_byte() == 93 --[[ "]" ]] then
statusPos = statusPos + 1
if consume_byte "^[ \t\r\n]*%]" then
return res
end
statusTop = statusTop + 1
......@@ -357,8 +382,7 @@ end
local function decode_object()
statusPos = statusPos + 1
local res = {}
if next_byte() == 125 --[[ "}" ]] then
statusPos = statusPos + 1
if consume_byte "^[ \t\r\n]*}" then
return setmetatable(res, json.object)
end
statusTop = statusTop + 1
......@@ -389,11 +413,15 @@ local decode_uncompleted_map = {
local function unexpected_character()
decode_error("unexpected character '" .. string_sub(statusBuf, statusPos, statusPos) .. "'")
end
local function unexpected_eol()
decode_error("unexpected character '<eol>'")
end
local decode_map = {}
for i = 0, 255 do
decode_map[i] = decode_uncompleted_map[i] or unexpected_character
end
decode_map[-1] = unexpected_eol
local function decode()
return decode_map[next_byte()]()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment