diff options
-rw-r--r-- | .gitmodules | 3 | ||||
m--------- | 3rd/json.lua | 0 | ||||
-rw-r--r-- | script/global.d.lua | 4 | ||||
-rw-r--r-- | script/json-beautify.lua | 23 | ||||
-rw-r--r-- | script/json-edit.lua | 191 | ||||
-rw-r--r-- | script/json.lua | 16 |
6 files changed, 157 insertions, 80 deletions
diff --git a/.gitmodules b/.gitmodules index 1dfe374c..ef4d5f5e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "3rd/EmmyLuaCodeStyle"] path = 3rd/EmmyLuaCodeStyle url = https://github.com/CppCXY/EmmyLuaCodeStyle +[submodule "3rd/json.lua"] + path = 3rd/json.lua + url = https://github.com/actboy168/json.lua diff --git a/3rd/json.lua b/3rd/json.lua new file mode 160000 +Subproject b5f5e7b00091974ae2663c6db7ff9d4802bd1f3 diff --git a/script/global.d.lua b/script/global.d.lua index 7e568b94..c120c153 100644 --- a/script/global.d.lua +++ b/script/global.d.lua @@ -69,3 +69,7 @@ CACHEALIVE = false -- (experiment) Compile files in multi cpu cores ---@type integer COMPILECORES = 0 + +-- TODO: delete this after new config +---@diagnostic disable-next-line: lowercase-global +jit = false diff --git a/script/json-beautify.lua b/script/json-beautify.lua index f86a7625..f3467f07 100644 --- a/script/json-beautify.lua +++ b/script/json-beautify.lua @@ -79,11 +79,13 @@ function encode_map.table(t) statusBuilder[#statusBuilder+1] = "{" statusDep = statusDep + 1 encode_newline() - local k = key[1] - statusBuilder[#statusBuilder+1] = '"' - statusBuilder[#statusBuilder+1] = encode_string(k) - statusBuilder[#statusBuilder+1] = '": ' - encode(t[k]) + do + local k = key[1] + statusBuilder[#statusBuilder+1] = '"' + statusBuilder[#statusBuilder+1] = encode_string(k) + statusBuilder[#statusBuilder+1] = '": ' + encode(t[k]) + end for i = 2, #key do local k = key[i] statusBuilder[#statusBuilder+1] = "," @@ -154,16 +156,21 @@ local function beautify_option(option) return setmetatable(option or {}, defaultOpt) end -local function beautify(v, option) +local function beautify_builder(builder, v, option) statusVisited = {} - statusBuilder = {} + statusBuilder = builder statusOpt = beautify_option(option) statusDep = statusOpt.depth encode(v) +end + +local function beautify(v, option) + beautify_builder({}, v, option) return table_concat(statusBuilder) end json.beautify = beautify -json.beautify_option = beautify_option +json._beautify_builder = beautify_builder +json._beautify_option = beautify_option return json diff --git a/script/json-edit.lua b/script/json-edit.lua index 7f20b523..30a55250 100644 --- a/script/json-edit.lua +++ b/script/json-edit.lua @@ -1,9 +1,9 @@ ----@diagnostic disable: param-type-mismatch - local type = type local next = next local error = error local tonumber = tonumber +local table_concat = table.concat +local table_move = table.move local string_char = string.char local string_byte = string.byte local string_find = string.find @@ -45,6 +45,12 @@ if _VERSION == "Lua 5.1" or _VERSION == "Lua 5.2" then end return "float" end + function table_move(a1, f, e, t, a2) + for i = f, e do + a2[t+(i-f)] = a1[i] + end + return a2 + end else utf8_char = utf8.char math_type = math.type @@ -376,6 +382,8 @@ local function decode_item() end end +local JsonEmpty = function () end + local function decode_ast(str) if type(str) ~= "string" then error("expected argument of type string, got " .. type(str)) @@ -384,7 +392,7 @@ local function decode_ast(str) statusPos = 1 statusTop = 0 if next_byte() == -1 then - return json.null + return {s = statusPos, d = statusTop, f = statusPos, v = JsonEmpty} end local res = decode() while statusTop > 0 do @@ -407,7 +415,7 @@ end local function query_(ast, pathlst, n) local data = ast.v if type(data) ~= "table" then - return + return nil, string_format("path `%s` does not point to object or array", "/"..table_concat(pathlst, "/", 1, n-1)) end local k = pathlst[n] local isarray = not json.isObject(data) @@ -416,28 +424,36 @@ local function query_(ast, pathlst, n) k = #data + 1 else if k:match "^0%d+" then - return + return nil, string_format("path `%s` point to array, but invalid", "/"..table_concat(pathlst, "/", 1, n)) end k = tonumber(k) if k == nil or math_type(k) ~= "integer" or k <= 0 or k > #data + 1 then - return + return nil, string_format("path `%s` point to array, but invalid", "/"..table_concat(pathlst, "/", 1, n)) end end end if n == #pathlst then return ast, k, isarray end - return query_(data[k], pathlst, n + 1) + local v = data[k] + if v == nil then + return ast, k, isarray, table_move(pathlst, n + 1, #pathlst, 1, {}) + end + return query_(v, pathlst, n + 1) end -local function query(ast, path) +local function split_path(path) if type(path) ~= "string" then - return + return nil, "path is not a string" end if path:sub(1,1) ~= "/" then - return + return nil, "path must start with `/`" end - return query_(ast, split(path:sub(2)), 1) + return split(path:sub(2)) +end + +local function query(ast, path) + return query_(ast, split_path(path), 1) end local function del_first_empty_line(str) @@ -475,50 +491,59 @@ local function find_max_node(t) return max end +local function encode_newline(option) + return option.newline..string_rep(option.indent, option.depth) +end + local function apply_array_insert_before(str, option, value, node) local start_text = str:sub(1, node.s-1) local finish_text = str:sub(node.s) option.depth = option.depth + node.d - return start_text - .. json.beautify(value, option) - .. "," - .. option.newline - .. string_rep(option.indent, option.depth) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + json._beautify_builder(bd, value, option) + bd[#bd+1] = "," + bd[#bd+1] = encode_newline(option) + bd[#bd+1] = finish_text + return table_concat(bd) end local function apply_array_insert_after(str, option, value, node) local start_text = str:sub(1, node.f-1) local finish_text = str:sub(node.f) option.depth = option.depth + node.d - return start_text - .. "," - .. option.newline - .. string_rep(option.indent, option.depth) - .. json.beautify(value, option) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + bd[#bd+1] = "," + bd[#bd+1] = encode_newline(option) + json._beautify_builder(bd, value, option) + bd[#bd+1] = finish_text + return table_concat(bd) end local function apply_array_insert_empty(str, option, value, node) local start_text = str:sub(1, node.s) local finish_text = str:sub(node.f-1) option.depth = option.depth + node.d + 1 - return start_text - .. option.newline - .. string_rep(option.indent, option.depth) - .. json.beautify(value, option) - .. option.newline - .. string_rep(option.indent, option.depth-1) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + bd[#bd+1] = encode_newline(option) + json._beautify_builder(bd, value, option) + option.depth = option.depth - 1 + bd[#bd+1] = encode_newline(option) + bd[#bd+1] = finish_text + return table_concat(bd) end local function apply_replace(str, option, value, node) local start_text = str:sub(1, node.s-1) local finish_text = str:sub(node.f) option.depth = option.depth + node.d - return start_text - .. json.beautify(value, option) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + json._beautify_builder(bd, value, option) + bd[#bd+1] = finish_text + return table_concat(bd) end local function apply_object_insert(str, option, value, t, k) @@ -527,29 +552,31 @@ local function apply_object_insert(str, option, value, t, k) local start_text = str:sub(1, node.f-1) local finish_text = str:sub(node.f) option.depth = option.depth + node.d - return start_text - .. "," - .. option.newline - .. string_rep(option.indent, option.depth) - .. '"' - .. json._encode_string(k) - .. '": ' - .. json.beautify(value, option) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + bd[#bd+1] = "," + bd[#bd+1] = encode_newline(option) + bd[#bd+1] = '"' + bd[#bd+1] = json._encode_string(k) + bd[#bd+1] = '": ' + json._beautify_builder(bd, value, option) + bd[#bd+1] = finish_text + return table_concat(bd) else local start_text = str:sub(1, t.s) local finish_text = str:sub(t.f-1) option.depth = option.depth + t.d + 1 - return start_text - .. option.newline - .. string_rep(option.indent, option.depth) - .. '"' - .. json._encode_string(k) - .. '": ' - .. json.beautify(value, option) - .. option.newline - .. string_rep(option.indent, option.depth-1) - .. finish_text + local bd = {} + bd[#bd+1] = start_text + bd[#bd+1] = encode_newline(option) + bd[#bd+1] = '"' + bd[#bd+1] = json._encode_string(k) + bd[#bd+1] = '": ' + json._beautify_builder(bd, value, option) + option.depth = option.depth - 1 + bd[#bd+1] = encode_newline(option) + bd[#bd+1] = finish_text + return table_concat(bd) end end @@ -565,20 +592,33 @@ local function apply_remove(str, s, f) end end +local function add_prefix(v, pathlst) + for i = #pathlst, 1, -1 do + v = { [pathlst[i]] = v } + end + return v +end + local OP = {} function OP.add(str, option, path, value) - if value == nil then - return - end - if path == '' then + if path == '/' then return json.beautify(value, option) end local ast = decode_ast(str) - local t, k, isarray = query(ast, path) + if ast.v == JsonEmpty then + local pathlst = split_path(path) + value = add_prefix(value, pathlst) + return json.beautify(value, option) + end + local t, k, isarray, lastpath = query(ast, path) if not t then + error(k) return end + if lastpath then + value = add_prefix(value, lastpath) + end if isarray then if t.v[k] then return apply_array_insert_before(str, option, value, t.v[k]) @@ -597,39 +637,55 @@ function OP.add(str, option, path, value) end function OP.remove(str, _, path) - if path == '' then + if path == '/' then return '' end local ast = decode_ast(str) - local t, k, isarray = query(ast, path) + if ast.v == JsonEmpty then + return '' + end + local t, k, isarray, lastpath = query(ast, path) if not t then + error(k) return end + if lastpath then + --warning: path does not exist + return str + end if isarray then if k > #t.v then - return + --warning: path does not exist + return str end return apply_remove(str, t.v[k].s, t.v[k].f) else if t.v[k] == nil then - return + --warning: path does not exist + return str end return apply_remove(str, t.v[k].key_s, t.v[k].f) end end function OP.replace(str, option, path, value) - if value == nil then - return - end - if path == '' then + if path == '/' then return json.beautify(value, option) end local ast = decode_ast(str) - local t, k, isarray = query(ast, path) + if ast.v == JsonEmpty then + local pathlst = split_path(path) + value = add_prefix(value, pathlst) + return json.beautify(value, option) + end + local t, k, isarray, lastpath = query(ast, path) if not t then + error(k) return end + if lastpath then + value = add_prefix(value, lastpath) + end if t.v[k] then return apply_replace(str, option, value, t.v[k]) else @@ -648,9 +704,10 @@ end local function edit(str, patch, option) local f = OP[patch.op] if not f then + error(string_format("invalid op: %s", patch.op)) return end - option = json.beautify_option(option) + option = json._beautify_option(option) return f(str, option, patch.path, patch.value) end diff --git a/script/json.lua b/script/json.lua index 899d8c36..eaccb43e 100644 --- a/script/json.lua +++ b/script/json.lua @@ -183,11 +183,13 @@ function encode_map.table(t) keys[#keys+1] = k end table_sort(keys) - local k = keys[1] - statusBuilder[#statusBuilder+1] = '{"' - statusBuilder[#statusBuilder+1] = encode_string(k) - statusBuilder[#statusBuilder+1] = '":' - encode(t[k]) + do + local k = keys[1] + statusBuilder[#statusBuilder+1] = '{"' + statusBuilder[#statusBuilder+1] = encode_string(k) + statusBuilder[#statusBuilder+1] = '":' + encode(t[k]) + end for i = 2, #keys do local k = keys[i] statusBuilder[#statusBuilder+1] = ',"' @@ -219,6 +221,10 @@ function encode_map.table(t) if t[1] == nil then error("invalid table: sparse array is not supported") end + if jit and t[0] ~= nil then + -- 0 is the first index in luajit + error("invalid table: mixed or invalid key types: "..0) + end statusBuilder[#statusBuilder+1] = "[" encode(t[1]) local count = 2 |