diff options
Diffstat (limited to 'script-beta')
-rw-r--r-- | script-beta/json-beautify.lua | 120 | ||||
-rw-r--r-- | script-beta/json.lua | 450 | ||||
-rw-r--r-- | script-beta/json/decode.lua | 153 | ||||
-rw-r--r-- | script-beta/json/encode.lua | 135 | ||||
-rw-r--r-- | script-beta/json/init.lua | 6 | ||||
-rw-r--r-- | script-beta/proto/proto.lua | 6 |
6 files changed, 573 insertions, 297 deletions
diff --git a/script-beta/json-beautify.lua b/script-beta/json-beautify.lua new file mode 100644 index 00000000..1d2a6cc0 --- /dev/null +++ b/script-beta/json-beautify.lua @@ -0,0 +1,120 @@ +local json = require "json" +local type = type +local next = next +local error = error +local table_concat = table.concat +local table_sort = table.sort +local string_rep = string.rep +local math_type = math.type +local setmetatable = setmetatable +local getmetatable = getmetatable + +local statusMark +local statusQue +local statusDep +local statusOpt + +local defaultOpt = { + newline = "\n", + indent = " ", +} +defaultOpt.__index = defaultOpt + +local function encode_newline() + statusQue[#statusQue+1] = statusOpt.newline..string_rep(statusOpt.indent, statusDep) +end + +local encode_map = {} +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.table(t) + local first_val = next(t) + if first_val == nil then + if getmetatable(t) == json.object then + return "{}" + else + return "[]" + end + end + if statusMark[t] then + error("circular reference") + end + statusMark[t] = true + if type(first_val) == 'string' then + local key = {} + for k in next, t do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + key[#key+1] = k + end + table_sort(key) + statusQue[#statusQue+1] = "{" + statusDep = statusDep + 1 + encode_newline() + local k = key[1] + statusQue[#statusQue+1] = encode_string(k) + statusQue[#statusQue+1] = ": " + encode(t[k]) + for i = 2, #key do + local k = key[i] + statusQue[#statusQue+1] = "," + encode_newline() + statusQue[#statusQue+1] = encode_string(k) + statusQue[#statusQue+1] = ": " + encode(t[k]) + end + statusDep = statusDep - 1 + encode_newline() + statusMark[t] = nil + return "}" + else + 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 + if max < k then + max = k + end + end + statusQue[#statusQue+1] = "[" + statusDep = statusDep + 1 + encode_newline() + encode(t[1]) + for i = 2, max do + statusQue[#statusQue+1] = "," + encode_newline() + encode(t[i]) + end + statusDep = statusDep - 1 + encode_newline() + statusMark[t] = nil + return "]" + end +end + +local function beautify(v, option) + if type(v) == "string" then + v = json.decode(v) + end + statusMark = {} + statusQue = {} + statusDep = 0 + statusOpt = option and setmetatable(option, defaultOpt) or defaultOpt + encode(v) + return table_concat(statusQue) +end + +json.beautify = beautify + +return json diff --git a/script-beta/json.lua b/script-beta/json.lua new file mode 100644 index 00000000..46261d7d --- /dev/null +++ b/script-beta/json.lua @@ -0,0 +1,450 @@ +local type = type +local next = next +local error = error +local tonumber = tonumber +local tostring = tostring +local utf8_char = utf8.char +local table_concat = table.concat +local table_sort = table.sort +local string_char = string.char +local string_byte = string.byte +local string_find = string.find +local string_match = string.match +local string_gsub = string.gsub +local string_sub = string.sub +local string_format = string.format +local math_type = math.type +local setmetatable = setmetatable +local getmetatable = getmetatable +local Inf = math.huge + +local json = {} +json.object = {} + +-- json.encode -- +local statusMark +local statusQue + +local encode_map = {} + +local encode_escape_map = { + [ "\"" ] = "\\\"", + [ "\\" ] = "\\\\", + [ "/" ] = "\\/", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local decode_escape_set = {} +local decode_escape_map = {} +for k, v in next, encode_escape_map do + decode_escape_map[v] = k + decode_escape_set[string_byte(v, 2)] = true +end + +for i = 0, 31 do + local c = string_char(i) + if not encode_escape_map[c] then + encode_escape_map[c] = string_format("\\u%04x", i) + end +end + +local function encode(v) + local res = encode_map[type(v)](v) + statusQue[#statusQue+1] = res +end + +encode_map["nil"] = function () + return "null" +end + +function encode_map.string(v) + return '"' .. string_gsub(v, '[\0-\31\\"]', encode_escape_map) .. '"' +end +local encode_string = encode_map.string + +local function convertreal(v) + local g = string_format('%.16g', v) + if tonumber(g) == v then + return g + end + return string_format('%.17g', v) +end + +function encode_map.number(v) + if v ~= v or v <= -Inf or v >= Inf then + error("unexpected number value '" .. tostring(v) .. "'") + end + return string_gsub(convertreal(v), ',', '.') +end + +function encode_map.boolean(v) + if v then + return "true" + else + return "false" + end +end + +function encode_map.table(t) + local first_val = next(t) + if first_val == nil then + if getmetatable(t) == json.object then + return "{}" + else + return "[]" + end + end + if statusMark[t] then + error("circular reference") + end + statusMark[t] = true + if type(first_val) == 'string' then + local key = {} + for k in next, t do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + key[#key+1] = k + end + table_sort(key) + statusQue[#statusQue+1] = "{" + local k = key[1] + statusQue[#statusQue+1] = encode_string(k) + statusQue[#statusQue+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] = ":" + encode(t[k]) + end + statusMark[t] = nil + return "}" + else + 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 + if max < k then + max = k + end + end + statusQue[#statusQue+1] = "[" + encode(t[1]) + for i = 2, max do + statusQue[#statusQue+1] = "," + encode(t[i]) + end + statusMark[t] = nil + return "]" + end +end + +local function encode_unexpected(v) + if v == json.null then + return "null" + else + error("unexpected type '"..type(v).."'") + end +end +encode_map[ "function" ] = encode_unexpected +encode_map[ "userdata" ] = encode_unexpected +encode_map[ "thread" ] = encode_unexpected + +function json.encode(v) + statusMark = {} + statusQue = {} + encode(v) + return table_concat(statusQue) +end + +json.encode_map = encode_map + +-- json.decode -- + +local statusBuf +local statusPos +local statusTop +local statusAry = {} +local statusRef = {} + +local function find_line() + local line = 1 + local pos = 1 + while true do + local f, _, nl1, nl2 = string_find(statusBuf, '([\n\r])([\n\r]?)', pos) + if not f then + return line, statusPos - pos + 1 + end + local newpos = f + ((nl1 == nl2 or nl2 == '') and 1 or 2) + if newpos > statusPos then + return line, statusPos - pos + 1 + end + pos = newpos + line = line + 1 + end +end + +local function decode_error(msg) + error(string_format("ERROR: %s at line %d col %d", msg, find_line())) +end + +local function get_word() + return string_match(statusBuf, "^[^ \t\r\n%]},]*", statusPos) +end + +local function next_byte() + statusPos = string_find(statusBuf, "[^ \t\r\n]", statusPos) + if statusPos then + return string_byte(statusBuf, statusPos) + end + statusPos = #statusBuf + 1 + decode_error("unexpected character '<eol>'") +end + +local function expect_byte(c) + local _, pos = string_find(statusBuf, c, statusPos) + if not pos then + decode_error(string_format("expected '%s'", string_sub(c, #c))) + end + statusPos = pos +end + +local function decode_unicode_surrogate(s1, s2) + return utf8_char(0x10000 + (tonumber(s1, 16) - 0xd800) * 0x400 + (tonumber(s2, 16) - 0xdc00)) +end + +local function decode_unicode_escape(s) + return utf8_char(tonumber(s, 16)) +end + +local function decode_string() + local has_unicode_escape = false + local has_escape = false + local i = statusPos + 1 + while true do + i = string_find(statusBuf, '["\\\0-\31]', i) + if not i then + decode_error "expected closing quote for string" + end + local x = string_byte(statusBuf, i) + if x < 32 then + statusPos = i + decode_error "control character in string" + end + if x == 34 --[[ '"' ]] then + local s = string_sub(statusBuf, statusPos + 1, i - 1) + if has_unicode_escape then + s = string_gsub(string_gsub(s + , "\\u([dD][89aAbB]%x%x)\\u([dD][c-fC-F]%x%x)", decode_unicode_surrogate) + , "\\u(%x%x%x%x)", decode_unicode_escape) + end + if has_escape then + s = string_gsub(s, "\\.", decode_escape_map) + end + statusPos = i + 1 + return s + end + --assert(x == 92 --[[ "\\" ]]) + local nx = string_byte(statusBuf, i+1) + if nx == 117 --[[ "u" ]] then + if not string_match(statusBuf, "^%x%x%x%x", i+2) then + statusPos = i + decode_error "invalid unicode escape in string" + end + has_unicode_escape = true + i = i + 6 + else + if not decode_escape_set[nx] then + statusPos = i + decode_error("invalid escape char '" .. (nx and string_char(nx) or "<eol>") .. "' in string") + end + has_escape = true + i = i + 2 + end + end +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 .. "'") + end + statusPos = statusPos + #word + return tonumber(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 + +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 .. "'") + end + statusPos = statusPos + #word + return tonumber(word) +end + +local function decode_true() + if string_sub(statusBuf, statusPos, statusPos+3) ~= "true" then + decode_error("invalid literal '" .. get_word() .. "'") + end + statusPos = statusPos + 4 + return true +end + +local function decode_false() + if string_sub(statusBuf, statusPos, statusPos+4) ~= "false" then + decode_error("invalid literal '" .. get_word() .. "'") + end + statusPos = statusPos + 5 + return false +end + +local function decode_null() + if string_sub(statusBuf, statusPos, statusPos+3) ~= "null" then + decode_error("invalid literal '" .. get_word() .. "'") + end + statusPos = statusPos + 4 + return json.null +end + +local function decode_array() + statusPos = statusPos + 1 + local res = {} + if next_byte() == 93 --[[ "]" ]] then + statusPos = statusPos + 1 + return res + end + statusTop = statusTop + 1 + statusAry[statusTop] = true + statusRef[statusTop] = res + return res +end + +local function decode_object() + statusPos = statusPos + 1 + local res = {} + if next_byte() == 125 --[[ "}" ]] then + statusPos = statusPos + 1 + return setmetatable(res, json.object) + end + statusTop = statusTop + 1 + statusAry[statusTop] = false + statusRef[statusTop] = res + return res +end + +local decode_uncompleted_map = { + [ string_byte '"' ] = decode_string, + [ string_byte "0" ] = decode_number_zero, + [ string_byte "1" ] = decode_number, + [ string_byte "2" ] = decode_number, + [ string_byte "3" ] = decode_number, + [ string_byte "4" ] = decode_number, + [ string_byte "5" ] = decode_number, + [ string_byte "6" ] = decode_number, + [ string_byte "7" ] = decode_number, + [ string_byte "8" ] = decode_number, + [ string_byte "9" ] = decode_number, + [ string_byte "-" ] = decode_number_negative, + [ string_byte "t" ] = decode_true, + [ string_byte "f" ] = decode_false, + [ string_byte "n" ] = decode_null, + [ string_byte "[" ] = decode_array, + [ string_byte "{" ] = decode_object, +} +local function unexpected_character() + decode_error("unexpected character '" .. string_sub(statusBuf, statusPos, statusPos) .. "'") +end + +local decode_map = {} +for i = 0, 255 do + decode_map[i] = decode_uncompleted_map[i] or unexpected_character +end + +local function decode() + return decode_map[next_byte()]() +end + +local function decode_item() + local top = statusTop + local ref = statusRef[top] + if statusAry[top] then + ref[#ref+1] = decode() + else + expect_byte '^[ \t\r\n]*"' + local key = decode_string() + expect_byte '^[ \t\r\n]*:' + statusPos = statusPos + 1 + ref[key] = decode() + end + if top == statusTop then + repeat + local chr = next_byte(); statusPos = statusPos + 1 + if chr == 44 --[[ "," ]] then + return + end + if statusAry[statusTop] then + if chr ~= 93 --[[ "]" ]] then decode_error "expected ']' or ','" end + else + if chr ~= 125 --[[ "}" ]] then decode_error "expected '}' or ','" end + end + statusTop = statusTop - 1 + until statusTop == 0 + end +end + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + statusBuf = str + statusPos = 1 + statusTop = 0 + local res = decode() + while statusTop > 0 do + decode_item() + end + if string_find(statusBuf, "[^ \t\r\n]", statusPos) then + decode_error "trailing garbage" + end + return res +end + +-- Generate a lightuserdata +json.null = debug.upvalueid(decode, 1) + +return json diff --git a/script-beta/json/decode.lua b/script-beta/json/decode.lua deleted file mode 100644 index 36f8aa54..00000000 --- a/script-beta/json/decode.lua +++ /dev/null @@ -1,153 +0,0 @@ -local lpeg = require 'lpeglabel' -local tablePack = table.pack -local rawset = rawset -local tointeger = math.tointeger -local tonumber = tonumber -local setmetatable = setmetatable -local stringChar = string.char -local error = error - -_ENV = nil - -local SaveSort -local P = lpeg.P -local S = lpeg.S -local R = lpeg.R -local V = lpeg.V -local C = lpeg.C -local Ct = lpeg.Ct -local Cc = lpeg.Cc -local Cp = lpeg.Cp -local Cs = lpeg.Cs - -local EscMap = { - ['t'] = '\t', - ['r'] = '\r', - ['n'] = '\n', - ['"'] = '"', - ['\\'] = '\\', -} -local BoolMap = { - ['true'] = true, - ['false'] = false, -} - -local hashmt = { - __pairs = function (self) - local i = 1 - local function next() - i = i + 1 - local k = self[i] - if k == nil then - return - end - local v = self[k] - if v == nil then - return next() - end - return k, v - end - return next - end, - __newindex = function (self, k, v) - local i = 2 - while self[i] do - i = i + 1 - end - rawset(self, i, k) - rawset(self, k, v) - end, -} - ------------------------------------------------------------------------------ --- JSON4Lua: JSON encoding / decoding support for the Lua language. --- json Module. --- Author: Craig Mason-Jones --- Homepage: http://github.com/craigmj/json4lua/ --- Version: 1.0.0 --- This module is released under the MIT License (MIT). --- Please see LICENCE.txt for details. --- -local function Utf8(str) - local n = tonumber(str, 16) - -- math.floor(x/2^y) == lazy right shift - -- a % 2^b == bitwise_and(a, (2^b)-1) - -- 64 = 2^6 - -- 4096 = 2^12 (or 2^6 * 2^6) - local x - if n < 0x80 then - x = stringChar(n % 0x80) - elseif n < 0x800 then - -- [110x xxxx] [10xx xxxx] - x = stringChar(0xC0 + ((n // 64) % 0x20), 0x80 + (n % 0x40)) - else - -- [1110 xxxx] [10xx xxxx] [10xx xxxx] - x = stringChar(0xE0 + ((n // 4096) % 0x10), 0x80 + ((n // 64) % 0x40), 0x80 + (n % 0x40)) - end - return x -end - -local function HashTable(patt) - return C(patt) / function (_, ...) - local hash = tablePack(...) - local n = hash.n - hash.n = nil - if SaveSort then - local max = n // 2 - for i = 1, max do - local key, value = hash[2*i-1], hash[2*i] - hash[key] = value - hash[i+1] = key - end - hash[1] = nil - for i = max+2, max*2 do - hash[i] = nil - end - return setmetatable(hash, hashmt) - else - local max = n // 2 - for i = 1, max do - local a = 2*i-1 - local b = 2*i - local key, value = hash[a], hash[b] - hash[key] = value - hash[a] = nil - hash[b] = nil - end - return hash - end - end -end - -local Token = P -{ - V'Value' * Cp(), - Nl = P'\r\n' + S'\r\n', - Sp = S' \t' + '//' * (1-V'Nl')^0, - Spnl = (V'Sp' + V'Nl')^0, - Bool = C(P'true' + P'false') / BoolMap, - Int = C('0' + (P'-'^-1 * R'19' * R'09'^0)) / tointeger, - Float = C(P'-'^-1 * ('0' + R'19' * R'09'^0) * '.' * R'09'^0) / tonumber, - Null = P'null' * Cc(nil), - String = '"' * Cs(V'Char'^0) * '"', - Char = V'Esc' + V'Utf8' + (1 - P'"' - P'\t' - V'Nl'), - Esc = P'\\' * C(S'tnr"\\') / EscMap, - Utf8 = P'\\u' * C(P(4)) / Utf8, - Hash = V'Spnl' * '{' * V'Spnl' * HashTable((V'Object' + P',' * V'Spnl')^0) * V'Spnl' * P'}' * V'Spnl', - Array = V'Spnl' * '[' * V'Spnl' * Ct((V'Value' * V'Spnl' + P',' * V'Spnl')^0) * V'Spnl' * P']' * V'Spnl', - Object = V'Spnl' * V'Key' * V'Spnl' * V'Value' * V'Spnl', - Key = V'String' * V'Spnl' * ':', - Value = V'Hash' + V'Array' + V'Bool' + V'Null' + V'String' + V'Float' + V'Int', -} - -return function (str, save_sort_) - SaveSort = save_sort_ - local table, res, pos = Token:match(str) - if not table then - if not pos or pos <= #str then - pos = pos or 1 - error(('没匹配完[%s][%s]\n%s'):format(pos, res, str:sub(pos, pos+100))) - end - end - return table -end diff --git a/script-beta/json/encode.lua b/script-beta/json/encode.lua deleted file mode 100644 index 492c5a58..00000000 --- a/script-beta/json/encode.lua +++ /dev/null @@ -1,135 +0,0 @@ -local rep = string.rep -local gsub = string.gsub -local sort = table.sort -local find = string.find -local tostring = tostring -local getmetatable = debug.getmetatable -local type = type -local next = next -local pairs = pairs -local tableConcat = table.concat - -_ENV = nil - -local index -local lines -local n = -1 -local tabs = {} - -local esc_map = { - ['\\'] = '\\\\', - ['\r'] = '\\r', - ['\n'] = '\\n', - ['\t'] = '\\t', - ['"'] = '\\"', -} - -local function encode(data, key) - n = n + 1 - if not tabs[n] then - tabs[n] = rep(' ', n) - end - local tp = type(data) - if tp == 'table' then - if not data[1] and next(data) then - -- 认为这个是哈希表 - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": {\r\n' - else - index=index+1;lines[index] = tabs[n] .. '{\r\n' - end - local meta = getmetatable(data) - local sep - if meta and meta.__pairs then - for k, v in meta.__pairs(data), data do - if encode(v, k) then - index=index+1;lines[index] = ',\r\n' - sep = true - end - end - else - local list = {} - local i = 0 - for k in next, data do - i=i+1;list[i] = k - end - sort(list) - for j = 1, i do - local k = list[j] - if encode(data[k], k) then - index=index+1;lines[index] = ',\r\n' - sep = true - end - end - end - if sep then - lines[index] = '\r\n' - end - index=index+1;lines[index] = tabs[n] .. '}' - else - -- 认为这个是数组 - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": [\r\n' - else - index=index+1;lines[index] = tabs[n] .. '[\r\n' - end - local sep - for k, v in pairs(data) do - if encode(v) then - index=index+1;lines[index] = ',\r\n' - sep = true - end - end - if sep then - lines[index] = '\r\n' - end - index=index+1;lines[index] = tabs[n] .. ']' - end - elseif tp == 'number' then - data = tostring(data) - -- 判断 inf -inf -nan(ind) 1.#INF -1.#INF -1.#IND - if find(data, '%a') then - data = '0' - end - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. data - else - index=index+1;lines[index] = tabs[n] .. data - end - elseif tp == 'boolean' then - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. tostring(data) - else - index=index+1;lines[index] = tabs[n] .. tostring(data) - end - elseif tp == 'nil' then - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": null' - else - index=index+1;lines[index] = tabs[n] .. 'null' - end - elseif tp == 'string' then - local str = gsub(data, '[\\\r\n\t"]', esc_map) - if key then - index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": "' .. str .. '"' - else - index=index+1;lines[index] = tabs[n] .. '"' .. str .. '"' - end - else - n = n - 1 - return false - end - n = n - 1 - return true -end - -local function json(t) - lines = {} - index = 0 - - encode(t) - - return tableConcat(lines) -end - -return json diff --git a/script-beta/json/init.lua b/script-beta/json/init.lua deleted file mode 100644 index c28e7aed..00000000 --- a/script-beta/json/init.lua +++ /dev/null @@ -1,6 +0,0 @@ -local api = { - decode = require 'json.decode', - encode = require 'json.encode', -} - -return api diff --git a/script-beta/proto/proto.lua b/script-beta/proto/proto.lua index 05749815..3ceb719d 100644 --- a/script-beta/proto/proto.lua +++ b/script-beta/proto/proto.lua @@ -5,6 +5,7 @@ local pub = require 'pub' local jsonrpc = require 'jsonrpc' local ErrorCodes = require 'define.ErrorCodes' local timer = require 'timer' +local json = require 'json' local reqCounter = util.counter() @@ -30,10 +31,9 @@ function m.response(id, res) log.error('Response id is nil!', util.dump(res)) return end - -- res 可能是nil,为了转成json时保留nil,使用 container 容器 - local data = util.container() + local data = {} data.id = id - data.result = res + data.result = res == nil and json.null or res local buf = jsonrpc.encode(data) --log.debug('Response', id, #buf) io.stdout:write(buf) |