Now, the only feature missing is a Lua value stringifier (serialize/
deserialize) which I'd like to be as a C function. Anyone has such?
Got one in Lua, but it isn't oriented toward performance:
--------------------------------------------------------------------------------
-- Take a value, and return the source of a chunk which generates it.
-- It accepts:
-- * strings, integers, booleans, nil
-- * functions, provided that they don't depend on upvalues
-- * tables whose keys and values are accepted by [serialize()]. Tables can
-- have circular and shared references.
-- The resulting string can be fed into [loadstring].
--------------------------------------------------------------------------------
local function serialize (x)
-- [cache] keeps table->varname association, so that shared and circular
-- references are handled correctly.
-- [case] holds the list of functions which parse values, indexed by type.
-- [accumulator] keeps lines of code generated by [
case.xxx()] calls
local cache, case, accumulator = { }, { }, { }
-- Put a string in the accumulator
local function acc (fmt, ...)
table.insert (accumulator, string.format (fmt, ...))
end
-- Without an argument, generate a fresh variable name
-- With an int argument n, returns the nth variable generated
-- gensym_idx is the index of the last generated variable.
local gensym_idx = 0
local function gensym(i)
if not i then i=gensym_idx+1; gensym_idx=i end
return string.format("v%s", i)
end
-- Serialize a value, by dispatching between case.xxx() functions.
local function parse (x)
local f = case[type(x)]
if not f then error ("Can't serialize objects of type "..type(x))
else return f(x) end
end
-- case.<type> compute serialization of values of type <type>.
function case.number(x) return tostring (x) end
function case.string(x) return string.format ("%q", x) end
function case.boolean(x) return x and "true" or "false" end
case["nil"] = function (x) return "nil" end
case["function"] = function (x)
return string.format ("loadstring (%q, 'flash')", string.dump (x))
end
function case.table (x)
if cache[x] then return cache[x] end
local st = gensym()
cache[x] = st
acc ("%s = { }", st)
for k, v in pairs(x) do
acc("%s[%s] = %s", st, parse(k), parse(v))
end
return st
end
-- Start serialization.
local r = parse (x)
-- If no local variable is needed, return directly the result
if gensym_idx == 0 then return "return " .. r end
-- Collect all generated variables as a single piece of source.
local local_decl = { }
for i = 1, gensym_idx do local_decl[i] = gensym(i) end
local_decl = "do\n local " .. table.concat(local_decl, ", ") .. "\n "
return
local_decl ..
table.concat(accumulator, "\n ") ..
"\n return " .. r .. "\nend"
end