summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpportunityLiu <[email protected]>2019-07-26 20:37:21 +0800
committerOpportunityLiu <[email protected]>2019-07-28 14:45:01 +0800
commitef1b33a90b2fcb87c070de07d22ed89d830fcbd0 (patch)
treefcb3c454f822aac7c36aab8f7bd5e14b62e6ad82
parentab8e62f99a161981fbb485aaa895e429b8c31144 (diff)
fix keyword as key
-rw-r--r--tests/modules/string/serialize/test.lua2
-rw-r--r--xmake/core/base/serialize.lua106
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