summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
m---------3rd/json.lua0
-rw-r--r--script/global.d.lua4
-rw-r--r--script/json-beautify.lua23
-rw-r--r--script/json-edit.lua191
-rw-r--r--script/json.lua16
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