diff options
Diffstat (limited to 'script/json')
-rw-r--r-- | script/json/decode.lua | 153 | ||||
-rw-r--r-- | script/json/encode.lua | 135 | ||||
-rw-r--r-- | script/json/init.lua | 6 |
3 files changed, 294 insertions, 0 deletions
diff --git a/script/json/decode.lua b/script/json/decode.lua new file mode 100644 index 00000000..36f8aa54 --- /dev/null +++ b/script/json/decode.lua @@ -0,0 +1,153 @@ +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/json/encode.lua b/script/json/encode.lua new file mode 100644 index 00000000..97a1680b --- /dev/null +++ b/script/json/encode.lua @@ -0,0 +1,135 @@ + +local rep = string.rep +local format = string.format +local gsub = string.gsub +local sub = string.sub +local sort = table.sort +local find = string.find +local tostring = tostring +local getmetatable = debug.getmetatable +local type = type +local next = next +local ipairs = ipairs + +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 table.concat(lines) +end + +return json diff --git a/script/json/init.lua b/script/json/init.lua new file mode 100644 index 00000000..c28e7aed --- /dev/null +++ b/script/json/init.lua @@ -0,0 +1,6 @@ +local api = { + decode = require 'json.decode', + encode = require 'json.encode', +} + +return api |