lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 2/23/07, Asko Kauppi <askok@dnainternet.net> wrote:
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