diff options
| author | OpportunityLiu <[email protected]> | 2019-07-26 20:37:21 +0800 |
|---|---|---|
| committer | OpportunityLiu <[email protected]> | 2019-07-28 14:45:01 +0800 |
| commit | ef1b33a90b2fcb87c070de07d22ed89d830fcbd0 (patch) | |
| tree | fcb3c454f822aac7c36aab8f7bd5e14b62e6ad82 | |
| parent | ab8e62f99a161981fbb485aaa895e429b8c31144 (diff) | |
fix keyword as key
| -rw-r--r-- | tests/modules/string/serialize/test.lua | 2 | ||||
| -rw-r--r-- | xmake/core/base/serialize.lua | 106 |
2 files changed, 63 insertions, 45 deletions
diff --git a/tests/modules/string/serialize/test.lua b/tests/modules/string/serialize/test.lua index 1fcb62f66..3c21d4410 100644 --- a/tests/modules/string/serialize/test.lua +++ b/tests/modules/string/serialize/test.lua @@ -41,6 +41,8 @@ end function test_table(t) t:are_equal(roundtrip({}), {}) + t:are_equal(roundtrip({{},{1}}), {{},{1}}) + t:are_equal(roundtrip({["true"] = true}), {["true"] = true}) t:are_equal(roundtrip({1, 2, 3}), {1, 2, 3}) t:are_equal(roundtrip({1, "", 3}), {1, "", 3}) t:are_equal(roundtrip({{1, 2, 3, nil, 4}}), {{1, 2, 3, nil, 4}}) diff --git a/xmake/core/base/serialize.lua b/xmake/core/base/serialize.lua index f5e078da0..59feae24a 100644 --- a/xmake/core/base/serialize.lua +++ b/xmake/core/base/serialize.lua @@ -25,40 +25,14 @@ local serialize = serialize or {} -- load modules local math = require("base/math") local table = require("base/table") +local hashset = require("base/hashset") + +-- reserved keywords in lua +local keywords = hashset.of("and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while") -- save original interfaces serialize._dump = serialize._dump or string._dump or string.dump -function serialize._createstub(resolver, env, ...) - env.has_stub = true - local params = table.pack(...) - return function(root, fenv) - return resolver(root, fenv, table.unpack(params, 1, params.n)) - end -end - -function serialize._resolvestub(object, root, fenv) - if type(object) == "function" then - local ok, result, errors = pcall(object, root, fenv) - if ok and errors == nil then - return result - end - return nil, errors or result or "unspecified error" - end - if type(object) ~= "table" then - return object - end - - for k, v in pairs(object) do - local result, errors = serialize._resolvestub(v, root, fenv) - if errors ~= nil then - return nil, errors - end - object[k] = result - end - return object -end - function serialize._makestring(str, opt) return string.format("%q", str) end @@ -117,6 +91,11 @@ function serialize._maketable(object, opt, level, path, reftab) serialized[k] = sval end + -- empty table + if isarr and numidxcount == 0 then + return opt.indent and "{ }" or "{}" + end + -- too sparse if numidxcount * 2 < maxn then isarr = false @@ -128,17 +107,6 @@ function serialize._maketable(object, opt, level, path, reftab) indent = string.rep(opt.indent, level) end - -- make head - local headstr = opt.indent and ("{\n" .. indent .. opt.indent) or "{" - - -- make tail - local tailstr - if opt.indent then - tailstr = "\n" .. indent .. "}" - else - tailstr = "}" - end - -- make body local bodystrs = {} if isarr then @@ -150,11 +118,11 @@ function serialize._maketable(object, opt, level, path, reftab) for k, v in pairs(serialized) do -- serialize key if type(k) == "string" then - if not k:match("^[%a_][%w_]*$") then + if keywords:has(k) or not k:match("^[%a_][%w_]*$") then k = string.format("[%q]", k) end else -- type(k) == "number" - local nval, err = serialize._makedefault(k, opt, childlevel) + local nval, err = serialize._makedefault(k, opt) if err ~= nil then return nil, err end @@ -165,9 +133,18 @@ function serialize._maketable(object, opt, level, path, reftab) end end - if #bodystrs == 0 then - return opt.indent and "{ }" or "{}" + -- make head + local headstr = opt.indent and ("{\n" .. indent .. opt.indent) or "{" + + -- make tail + local tailstr + if opt.indent then + tailstr = "\n" .. indent .. "}" + else + tailstr = "}" end + + -- concat together return headstr .. table.concat(bodystrs, opt.indent and (",\n" .. indent .. opt.indent) or ",") .. tailstr end @@ -324,6 +301,45 @@ function serialize.save(object, opt) return (#dump < #result) and dump or result end +-- called by functions in deserialize environment +-- create a function (called stub) to finish deserialization +function serialize._createstub(resolver, env, ...) + env.has_stub = true + local params = table.pack(...) + return function(root, fenv) + return resolver(root, fenv, table.unpack(params, 1, params.n)) + end +end + +-- after deserialization by load() +-- use this routine to call all stubs in deserialzed data +-- +-- @param object object to search stubs +-- root root object +-- fenv fenv of deserialzer caller +function serialize._resolvestub(object, root, fenv) + if type(object) == "function" then + local ok, result, errors = pcall(object, root, fenv) + if ok and errors == nil then + return result + end + return nil, errors or result or "unspecified error" + end + if type(object) ~= "table" then + return object + end + + for k, v in pairs(object) do + local result, errors = serialize._resolvestub(v, root, fenv) + if errors ~= nil then + return nil, errors + end + object[k] = result + end + return object +end + +-- create a env for deserialze load() call function serialize._createenv() -- init env |
