diff options
| author | ruki <[email protected]> | 2023-01-19 16:54:59 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-01-19 16:54:59 +0800 |
| commit | 6aa98ec8055538a5ec3742d0faafa47938fefd80 (patch) | |
| tree | d9280d1e9e3e2f171559607a9458a7c9ace17a73 | |
| parent | 17978855ebb374e21593129b52d3266db7715eb5 (diff) | |
| parent | ed38818a56f40b2fbd51ea10957c1cd6ed0ced41 (diff) | |
Merge pull request #3305 from xmake-io/json
Improve json
| -rw-r--r-- | core/src/lua-cjson/xmake.lua | 7 | ||||
| -rwxr-xr-x | core/src/lua-cjson/xmake.sh | 17 | ||||
| -rw-r--r-- | core/src/luajit/xmake.lua | 2 | ||||
| -rwxr-xr-x | core/src/luajit/xmake.sh | 2 | ||||
| -rw-r--r-- | core/src/xmake/engine.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/xmake.lua | 10 | ||||
| -rwxr-xr-x | core/src/xmake/xmake.sh | 23 | ||||
| -rw-r--r-- | core/xmake.lua | 16 | ||||
| -rwxr-xr-x | core/xmake.sh | 59 | ||||
| -rw-r--r-- | xmake/core/base/json.lua | 213 |
10 files changed, 297 insertions, 54 deletions
diff --git a/core/src/lua-cjson/xmake.lua b/core/src/lua-cjson/xmake.lua index 74406d67e..e4206c9fc 100644 --- a/core/src/lua-cjson/xmake.lua +++ b/core/src/lua-cjson/xmake.lua @@ -1,13 +1,18 @@ target("lua-cjson") set_kind("static") set_warnings("all") - add_deps("lua") + if is_config("runtime", "luajit") then + add_deps("luajit") + else + add_deps("lua") + end if is_plat("windows") then set_languages("c89") end add_files("lua-cjson/*.c|fpconv.c") -- Use internal strtod() / g_fmt() code for performance and disable multi-thread add_defines("NDEBUG", "USE_INTERNAL_FPCONV") + add_defines("XM_CONFIG_API_HAVE_LUA_CJSON", {public = true}) if is_plat("windows") then -- Windows sprintf()/strtod() handle NaN/inf differently. Not supported. add_defines("DISABLE_INVALID_NUMBERS") diff --git a/core/src/lua-cjson/xmake.sh b/core/src/lua-cjson/xmake.sh index 134173051..f3ab17546 100755 --- a/core/src/lua-cjson/xmake.sh +++ b/core/src/lua-cjson/xmake.sh @@ -4,12 +4,18 @@ target "lua_cjson" set_kind "static" set_default false set_warnings "all" - if is_config "runtime" "luajit" && has_config "luajit"; then - add_options "luajit" "{public}" - elif has_config "lua"; then - add_options "lua" "{public}" + if is_config "runtime" "luajit"; then + if has_config "luajit"; then + add_options "luajit" "{public}" + elif ! has_config "external"; then + add_deps "luajit" + fi else - add_deps "lua" + if has_config "lua"; then + add_options "lua" "{public}" + elif ! has_config "external"; then + add_deps "lua" + fi fi add_files "lua-cjson/dtoa.c" add_files "lua-cjson/lua_cjson.c" @@ -17,4 +23,5 @@ target "lua_cjson" add_files "lua-cjson/g_fmt.c" # Use internal strtod() / g_fmt() code for performance and disable multi-thread add_defines "NDEBUG" "USE_INTERNAL_FPCONV" + add_defines "XM_CONFIG_API_HAVE_LUA_CJSON" "{public}" diff --git a/core/src/luajit/xmake.lua b/core/src/luajit/xmake.lua index 8ad0bf1af..1e6bca80a 100644 --- a/core/src/luajit/xmake.lua +++ b/core/src/luajit/xmake.lua @@ -22,7 +22,7 @@ end local autogendir = path.join("luajit", "autogen", plat, jit and "jit" or "nojit", arch) -- add target -target("lua") +target("luajit") -- make as a static library set_kind("static") diff --git a/core/src/luajit/xmake.sh b/core/src/luajit/xmake.sh index 459da8999..0a0b0002c 100755 --- a/core/src/luajit/xmake.sh +++ b/core/src/luajit/xmake.sh @@ -30,7 +30,7 @@ else fi jit_autogendir="luajit/autogen/${jit_plat}/${jit_dir}/${jit_arch}" -target "lua" +target "luajit" set_kind "static" set_default false set_warnings "all" diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index 0ecafd064..a0a019c33 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -1109,9 +1109,11 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c xm_lua_curses_register(engine->lua, "curses"); #endif +#ifdef XM_CONFIG_API_HAVE_LUA_CJSON // bind cjson luaopen_cjson(engine->lua); lua_setglobal(engine->lua, "cjson"); +#endif // init host xm_engine_init_host(engine); diff --git a/core/src/xmake/xmake.lua b/core/src/xmake/xmake.lua index e100832ba..d4e11040e 100644 --- a/core/src/xmake/xmake.lua +++ b/core/src/xmake/xmake.lua @@ -2,7 +2,15 @@ target("xmake") set_kind("static") -- add deps - add_deps("sv", "lua-cjson", "lua", "lz4", "tbox") + add_deps("sv", "lz4", "tbox") + if is_config("runtime", "luajit") then + add_deps("luajit") + else + add_deps("lua") + end + if has_config("lua_cjson") then + add_deps("lua-cjson") + end if is_plat("windows") and has_config("pdcurses") then add_deps("pdcurses") end diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh index f3fe92aa1..06170e5bc 100755 --- a/core/src/xmake/xmake.sh +++ b/core/src/xmake/xmake.sh @@ -5,20 +5,29 @@ target "xmake" set_default false # add deps - local libs="lua_cjson lz4 sv tbox" + local libs="lz4 sv tbox" for lib in $libs; do if has_config "$lib"; then add_options "$lib" "{public}" - else + elif ! has_config "external"; then add_deps "$lib" fi done - if is_config "runtime" "luajit" && has_config "luajit"; then - add_options "luajit" "{public}" - elif has_config "lua"; then - add_options "lua" "{public}" + if has_config "lua_cjson" && ! has_config "external"; then + add_deps "lua_cjson" + fi + if is_config "runtime" "luajit"; then + if has_config "luajit"; then + add_options "luajit" "{public}" + elif ! has_config "external"; then + add_deps "luajit" + fi else - add_deps "lua" + if has_config "lua"; then + add_options "lua" "{public}" + elif ! has_config "external"; then + add_deps "lua" + fi fi # add options diff --git a/core/xmake.lua b/core/xmake.lua index af92e54ea..b3c8bbed6 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -50,15 +50,19 @@ end -- the runtime option option("runtime") - set_showmenu(true) set_default("lua") set_description("Use luajit or lua runtime") set_values("luajit", "lua") option_end() +-- the lua-cjson option +option("lua_cjson") + set_default(true) + set_description("Use lua-cjson as json parser") +option_end() + -- the readline option option("readline") - set_showmenu(true) set_description("Enable or disable readline library") add_links("readline") add_cincludes("readline/readline.h") @@ -68,7 +72,6 @@ option_end() -- the curses option option("curses") - set_showmenu(true) set_description("Enable or disable curses library") add_links("curses") add_cincludes("curses.h") @@ -78,7 +81,6 @@ option_end() -- the pdcurses option option("pdcurses") set_default(true) - set_showmenu(true) set_description("Enable or disable pdcurses library") add_defines("PDCURSES") add_defines("XM_CONFIG_API_HAVE_CURSES") @@ -87,7 +89,6 @@ option_end() -- only build xmake libraries for development? option("onlylib") set_default(false) - set_showmenu(true) set_description("Only build xmake libraries for development") option_end() @@ -98,7 +99,10 @@ if is_plat("windows") then end -- add projects -includes("src/lua-cjson", "src/sv", "src/lz4", "src/tbox", "src/xmake", "src/demo") +includes("src/sv", "src/lz4", "src/tbox", "src/xmake", "src/demo") +if has_config("lua_cjson") then + includes("src/lua-cjson") +end if is_config("runtime", "luajit") then includes("src/luajit") else diff --git a/core/xmake.sh b/core/xmake.sh index 759981225..af43f2ec1 100755 --- a/core/xmake.sh +++ b/core/xmake.sh @@ -35,6 +35,12 @@ fi # the runtime option, lua or luajit option "runtime" "Use luajit or lua runtime" "lua" +# always use external dependencies +option "external" "Always use external dependencies" false + +# use lua-cjson? +option "lua_cjson" "Use lua-cjson as json parser" true + # the readline option option "readline" add_links "readline" @@ -75,17 +81,6 @@ void test() {\n }" option_end -# the lua-cjson option -option "lua_cjson" - add_links "lua5.1-cjson" - add_csnippets " -int luaopen_cjson(void *l);\n -void test() {\n - luaopen_cjson(0);\n -} -" -option_end - # the lua option option "lua" add_cfuncs "lua_pushstring" @@ -116,8 +111,13 @@ option_end option_find_luajit() { local ldflags="" + local cflags="" option "luajit" - add_cflags `pkg-config --cflags luajit 2>/dev/null` + cflags=`pkg-config --cflags luajit 2>/dev/null` + if test_z "${cflags}"; then + cflags="/usr/include/luajit-2.1" + fi + add_cflags "${cflags}" ldflags=`pkg-config --libs luajit 2>/dev/null` if test_z "${ldflags}"; then ldflags="-lluajit" @@ -188,25 +188,28 @@ option_find_tbox() { } # add projects -if ! has_config "lua"; then +if ! has_config "external"; then if is_config "runtime" "luajit"; then - includes "src/luajit" + if ! has_config "luajit"; then + includes "src/luajit" + fi else - includes "src/lua" + if ! has_config "lua"; then + includes "src/lua" + fi + fi + if has_config "lua_cjson"; then + includes "src/lua-cjson" + fi + if ! has_config "lz4"; then + includes "src/lz4" + fi + if ! has_config "sv"; then + includes "src/sv" + fi + if ! has_config "tbox"; then + includes "src/tbox" fi -fi -if ! has_config "lua_cjson"; then - includes "src/lua-cjson" -fi -if ! has_config "lz4"; then - includes "src/lz4" -fi -if ! has_config "sv"; then - includes "src/sv" -fi -if ! has_config "tbox"; then - includes "src/tbox" fi includes "src/xmake" includes "src/demo" - diff --git a/xmake/core/base/json.lua b/xmake/core/base/json.lua index e83f6b320..4c619e69a 100644 --- a/xmake/core/base/json.lua +++ b/xmake/core/base/json.lua @@ -20,14 +20,219 @@ -- define module: json local json = json or {} -local cjson = cjson or {} -- load modules local io = require("base/io") +local os = require("base/os") local utils = require("base/utils") -- export null -json.null = cjson.null +if cjson then + json.null = cjson.null +else + json.null = {} + setmetatable(json.null, { + __is_json_null = true, + __eq = function (obj) + if type(obj) == "table" then + local mt = getmetatable(obj) + if mt and mt.__is_json_null then + return true + end + end + return false + end, + __tostring = function() + return "null" + end}) +end + +function json._pure_kind_of(obj) + if type(obj) ~= "table" then + return type(obj) + end + if json.is_marked_as_array(obj) then + return "array" + end + if obj == json.null then + return "nil" + end + local i = 1 + for _ in pairs(obj) do + if obj[i] ~= nil then + i = i + 1 + else + return "table" + end + end + if i == 1 then + return "table" + else + return "array" + end +end + +function json._pure_escape_str(s) + local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} + local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + for i, c in ipairs(in_char) do + s = s:gsub(c, '\\' .. out_char[i]) + end + return s +end + +function json._pure_skip_delim(str, pos, delim, err_if_missing) + pos = pos + #str:match('^%s*', pos) + if str:sub(pos, pos) ~= delim then + if err_if_missing then + os.raise("expected %s near position %d", delim, pos) + end + return pos, false + end + return pos + 1, true +end + +function json._pure_parse_str_val(str, pos, val) + val = val or '' + local early_end_error = "end of input found while parsing string." + if pos > #str then + os.raise(early_end_error) + end + local c = str:sub(pos, pos) + if c == '"' then + return val, pos + 1 + end + if c ~= '\\' then + return json._pure_parse_str_val(str, pos + 1, val .. c) + end + + -- we must have a \ character. + local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} + local nextc = str:sub(pos + 1, pos + 1) + if not nextc then + os.raise(early_end_error) + end + return json._pure_parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) +end + +function json._pure_parse_num_val(str, pos) + local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) + local val = tonumber(num_str) + if not val then + os.raise("error parsing number at position %d", pos) + end + return val, pos + #num_str +end + +function json._pure_stringify(obj, as_key) + local s = {} + local kind = json._pure_kind_of(obj) + if kind == "array" then + if as_key then + os.raise("can\'t encode array as key.") + end + s[#s + 1] = '[' + for i, val in ipairs(obj) do + if i > 1 then s[#s + 1] = ',' end + s[#s + 1] = json._pure_stringify(val) + end + s[#s + 1] = ']' + elseif kind == "table" then + if as_key then + os.raise("can\'t encode table as key.") + end + s[#s + 1] = '{' + for k, v in pairs(obj) do + if #s > 1 then s[#s + 1] = ',' end + s[#s + 1] = json._pure_stringify(k, true) + s[#s + 1] = ':' + s[#s + 1] = json._pure_stringify(v) + end + s[#s + 1] = '}' + elseif kind == "string" then + return '"' .. json._pure_escape_str(obj) .. '"' + elseif kind == "number" then + if as_key then + return '"' .. tostring(obj) .. '"' + end + return tostring(obj) + elseif kind == "boolean" then + return tostring(obj) + elseif kind == "nil" then + return "null" + else + os.raise("unknown type: %s", kind) + end + return table.concat(s) +end + +function json._pure_parse(str, pos, end_delim) + pos = pos or 1 + if pos > #str then + os.raise("reached unexpected end of input.") + end + -- skip whitespace. + local pos = pos + #str:match('^%s*', pos) + local first = str:sub(pos, pos) + if first == '{' then + local obj, key, delim_found = {}, true, true + pos = pos + 1 + while true do + key, pos = json._pure_parse(str, pos, '}') + if key == nil then + return obj, pos + end + if not delim_found then + os.raise("comma missing between object items.") + end + pos = json._pure_skip_delim(str, pos, ':', true) -- true -> error if missing. + obj[key], pos = json._pure_parse(str, pos) + pos, delim_found = json._pure_skip_delim(str, pos, ',') + end + elseif first == '[' then + local arr, val, delim_found = {}, true, true + json.mark_as_array(arr) + pos = pos + 1 + while true do + val, pos = json._pure_parse(str, pos, ']') + if val == nil then + return arr, pos + end + if not delim_found then + os.raise("comma missing between array items.") + end + arr[#arr + 1] = val + pos, delim_found = json._pure_skip_delim(str, pos, ',') + end + elseif first == '"' then + return json._pure_parse_str_val(str, pos + 1) + elseif first == '-' or first:match("%d") then + return json._pure_parse_num_val(str, pos) + elseif first == end_delim then + -- end of an object or array. + return nil, pos + 1 + else + local literals = {["true"] = true, ["false"] = false, ["null"] = json.null} + for lit_str, lit_val in pairs(literals) do + local lit_end = pos + #lit_str - 1 + if str:sub(pos, lit_end) == lit_str then + return lit_val, lit_end + 1 + end + end + local pos_info_str = "position " .. pos .. ": " .. str:sub(pos, pos + 10) + os.raise("invalid json syntax starting at " .. pos_info_str) + end +end + +-- decode json string using pure lua +function json._pure_decode(jsonstr, opt) + return json._pure_parse(jsonstr) +end + +-- encode json string using pua lua +function json._pure_encode(luatable, opt) + return json._pure_stringify(luatable) +end -- support empty array -- @see https://github.com/mpx/lua-cjson/issues/11 @@ -51,7 +256,7 @@ end -- @return the lua table -- function json.decode(jsonstr, opt) - local ok, luatable_or_errors = utils.trycall(cjson.decode, nil, jsonstr) + local ok, luatable_or_errors = utils.trycall(cjson and cjson.decode or json._pure_decode, nil, jsonstr) if not ok then return nil, string.format("decode json failed, %s", luatable_or_errors) end @@ -66,7 +271,7 @@ end -- @return the json string -- function json.encode(luatable, opt) - local ok, jsonstr_or_errors = utils.trycall(cjson.encode, nil, luatable) + local ok, jsonstr_or_errors = utils.trycall(cjson and cjson.encode or json._pure_encode, nil, luatable) if not ok then return nil, string.format("encode json failed, %s", jsonstr_or_errors) end |
