diff options
| author | ruki <[email protected]> | 2018-12-05 22:49:24 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2018-12-05 10:56:25 +0800 |
| commit | b7e17b562985e6854ddcf67c5524da9c5d045875 (patch) | |
| tree | c048e2309c86cebe234b9d42dc6db830f707c036 | |
| parent | 824a61bb67014f10313b2f872b039fc47b51e5db (diff) | |
serialize table and function
| -rw-r--r-- | xmake/core/base/io.lua | 103 | ||||
| -rw-r--r-- | xmake/core/base/table.lua | 91 |
2 files changed, 92 insertions, 102 deletions
diff --git a/xmake/core/base/io.lua b/xmake/core/base/io.lua index a07d127ea..66859f3fc 100644 --- a/xmake/core/base/io.lua +++ b/xmake/core/base/io.lua @@ -70,107 +70,21 @@ function _file:close() return self._FILE:close() end --- save object with the level -function _file:_save(object, level) - - -- save string - if type(object) == "string" then - self:printf("%q", object) - -- save boolean - elseif type(object) == "boolean" then - self:write(tostring(object)) - -- save number - elseif type(object) == "number" then - self:write(object) - -- save table - elseif type(object) == "table" then - - -- save head - self:write("\n") - for l = 1, level do - self:write(" ") - end - self:write("{\n") - - -- save body - local i = 0 - for k, v in pairs(object) do - - -- save spaces and separator - for l = 1, level do - self:write(" ") - end - - self:write(utils.ifelse(i == 0, " ", ", ")) - - -- save key - if type(k) == "string" then - self:write(string.format("[%q]", k), " = ") - end - - -- save value - if not self:_save(v, level + 1) then - return false - end - - -- save newline - self:write("\n") - i = i + 1 - end - - -- save tail - for l = 1, level do - self:write(" ") - end - self:write("}\n") - else - -- error - utils.error("invalid object type: %s", type(object)) - return false - end - - -- ok - return true -end - -- save object function _file:save(object) - return self:_save(object, 0) + local str, errors = table.makestr(object, false, true) + if str then + self:write(str) + end + return str, errors end -- load object function _file:load() - - -- check - assert(self) - - -- load data - local result = nil - local errors = nil local data = self:read("*all") if data and type(data) == "string" then - - -- load script - local script, errs = loadstring("return " .. data) - if script then - - -- load object - local ok, object = pcall(script) - if ok and object then - result = object - elseif object then - -- error - errors = object - else - -- error - errors = string.format("load %s failed!", filepath) - end - -- errors - else errors = errs end + return table.loadstr(data) end - - -- ok? - return result, errors end -- read all data from file @@ -275,10 +189,11 @@ function io.save(filepath, object) end -- save object to file - if not file:save(object) then + local ok, errors = file:save(object) + if not ok then -- error file:close() - return false, string.format("save %s failed!", filepath) + return false, string.format("save %s failed, %s!", filepath, errors) end -- close file diff --git a/xmake/core/base/table.lua b/xmake/core/base/table.lua index 3de4be277..6b600ad1e 100644 --- a/xmake/core/base/table.lua +++ b/xmake/core/base/table.lua @@ -26,10 +26,12 @@ local table = table or {} -- make string with the level -function table._makestr(self, deflate, level) - if type(self) == "string" or type(self) == "boolean" or type(self) == "number" then +function table._makestr(self, deflate, serialize, level) + if type(self) == "string" then + return serialize and string.format("%q", self) or self + elseif type(self) == "boolean" or type(self) == "number" then return tostring(self) - elseif type(self) == "table" and (getmetatable(self) or {}).__tostring then + elseif not serialize and type(self) == "table" and (getmetatable(self) or {}).__tostring then return tostring(self) elseif type(self) == "table" then @@ -64,13 +66,20 @@ function table._makestr(self, deflate, level) -- make key = value if type(k) == "string" then + if serialize then + k = string.format("[%q]", k) + end if deflate then s = s .. k .. "=" else s = s .. k .. " = " end end - s = s .. table._makestr(v, deflate, level + 1) + local substr, errors = table._makestr(v, deflate, serialize, level + 1) + if substr == nil then + return nil, errors + end + s = s .. substr if not deflate then s = s .. "\n" @@ -86,6 +95,10 @@ function table._makestr(self, deflate, level) end s = s .. "}" return s + elseif serialize and type(self) == "function" then + return string.format("%q", string.dump(self)) + elseif serialize then + return nil, "cannot serialize object: " .. type(self) elseif self ~= nil then return "<" .. tostring(self) .. ">" else @@ -93,6 +106,24 @@ function table._makestr(self, deflate, level) end end +-- load table from string in table +function table._loadstr(self) + -- only load luajit function data: e.g. "\27LJ\2\0\6=stdin" + if type(self) == "string" and self:startswith("\27LJ") then + return loadstring(self) + elseif type(self) == "table" then + for k, v in pairs(self) do + local value, errors = table._loadstr(v) + if value ~= nil then + self[k] = value + else + return nil, errors + end + end + end + return self +end + -- clear the table function table.clear(self) for k in next, self do @@ -259,13 +290,57 @@ function table.is_dictionary(dict) end -- dump table -function table.dump(self, deflate) - io.write(table.makestr(self, deflate)) +function table.dump(self, deflate, serialize) + local str = table.makestr(self, deflate, serialize) + if str then + io.write(str) + end end -- make string from the given table -function table.makestr(self, deflate) - return table._makestr(self, deflate, 0) +-- +-- @param deflate deflate empty characters +-- @param serialize make string which can be deserialized, we can use table.loadstr to load it +-- +-- @return string, errors +-- +function table.makestr(self, deflate, serialize) + return table._makestr(self, deflate, serialize, 0) +end + +-- load table from the serialized string +-- +-- @param str the serialized string +-- +-- @return table, errors +-- +function table.loadstr(str) + + -- load table as script + local result = nil + local script, errors = loadstring("return " .. str) + if script then + + -- load object + local ok, object = pcall(script) + if ok and object then + result = object + elseif object then + -- error + errors = object + else + -- error + errors = string.format("cannot deserialize string: %s", str) + end + end + + -- load function from string in table + if result then + result, errors = table._loadstr(result) + end + + -- ok? + return result, errors end -- unwrap object if be only one |
