2012-06-04 05:34:39 +00:00
# Serpent
2012-06-02 06:11:32 +00:00
2012-06-04 05:34:39 +00:00
Lua serializer and pretty printer.
## Features
* Human readable:
2012-06-04 05:52:02 +00:00
* Provides single-line and multi-line output.
* Nested tables are properly indented in the multi-line output.
* Numerical keys are listed first.
2012-06-13 06:17:44 +00:00
* Keys are (optionally) sorted alphanumerically.
2012-06-04 05:53:42 +00:00
* Array part skips keys (`{'a', 'b'}` instead of `{[1] = 'a', [2] = 'b'}` ).
* `nil` values are included when expected (`{1, nil, 3}` instead of `{1, [3]=3}` ).
* Keys use short notation (`{foo = 'foo'}` instead of `{['foo'] = 'foo'}` ).
2012-06-13 06:17:44 +00:00
* Shared references and self-references are marked in the output.
2012-06-04 05:34:39 +00:00
* Machine readable: provides reliable deserialization using `loadstring()` .
* Supports deeply nested tables.
* Supports tables with self-references.
2013-03-05 18:38:06 +00:00
* Keeps shared tables and functions shared after de/serialization.
2012-06-04 05:34:39 +00:00
* Supports function serialization using `string.dump()` .
* Supports serialization of global functions.
2013-03-05 18:38:06 +00:00
* Supports `__tostring` and `__serialize` metamethods.
2012-06-04 05:53:42 +00:00
* Escapes new-line `\010` and end-of-file control `\026` characters in strings.
2012-06-13 06:17:44 +00:00
* Configurable with options and custom formatters.
2012-06-04 05:34:39 +00:00
## Usage
2012-06-06 03:09:41 +00:00
```lua
2012-06-04 05:34:39 +00:00
local serpent = require("serpent")
local a = {1, nil, 3, x=1, ['true'] = 2, [not true]=3}
a[a] = a -- self-reference with a table as key and value
2012-06-13 06:17:44 +00:00
print(serpent.dump(a)) -- full serialization
print(serpent.line(a)) -- single line, no self-ref section
print(serpent.block(a)) -- multi-line indented, no self-ref section
2012-06-04 05:34:39 +00:00
2012-06-13 06:17:44 +00:00
local fun, err = loadstring(serpent.dump(a))
2012-06-04 05:34:39 +00:00
if err then error(err) end
local copy = fun()
2013-11-05 19:52:05 +00:00
-- or using serpent.load:
local ok, copy = serpent.load(serpent.dump(a))
print(ok and copy[3] == a[3])
2012-06-13 06:17:44 +00:00
```
## Functions
Serpent provides three functions that are shortcuts to the same
internal function, but set different options by default:
2013-11-03 02:20:59 +00:00
* `dump(a[, {...}])` -- full serialization; sets `name` , `compact` and `sparse` options;
* `line(a[, {...}])` -- single line pretty printing, no self-ref section; sets `sortkeys` and `comment` options;
* `block(a[, {...}])` -- multi-line indented pretty printing, no self-ref section; sets `indent` , `sortkeys` , and `comment` options.
Note that `line` and `block` functions return pretty-printed data structures and if you want to deserialize them, you need to add `return` before running them through `loadstring` .
For example: `loadstring('return '..require('mobdebug').line("foo"))() == "foo"` .
2012-06-13 06:17:44 +00:00
2013-11-05 19:52:05 +00:00
While you can use `loadstring` or `load` functions to load serialized fragments, Serpent also provides `load` function that adds safety checks and reports an error if there is any executable code in the fragment.
2014-01-09 22:05:47 +00:00
* `ok, res = serpent.load(str[, {safe = true}])` -- loads serialized fragment; you need to pass `{safe = false}` as the second value if you want to turn safety checks off.
2013-11-05 19:52:05 +00:00
Similar to `pcall` and `loadstring` calls, `load` returns status as the first value and the result or the error message as the second value.
2012-06-13 06:17:44 +00:00
## Options
* indent (string) -- indentation; triggers long multi-line output
2013-11-03 02:20:59 +00:00
* comment (true/false/maxlevel) -- provide stringified value in a comment (up to `maxlevel` of depth)
2013-02-27 21:31:18 +00:00
* sortkeys (true/false/function) -- sort keys
2013-11-03 02:20:59 +00:00
* sparse (true/false) -- force sparse encoding (no nil filling based on `#t` )
2013-02-27 21:31:18 +00:00
* compact (true/false) -- remove spaces
2013-11-03 02:20:59 +00:00
* fatal (true/False) -- raise fatal error on non-serilizable values
* nocode (true/False) -- disable bytecode serialization for easy comparison
* nohuge (true/False) -- disable checking numbers against undefined and huge values
2012-06-13 16:50:26 +00:00
* maxlevel (number) -- specify max level up to which to expand nested tables
2013-09-29 21:33:15 +00:00
* maxnum (number) -- specify max number of elements in a table
2015-05-08 05:53:47 +00:00
* numformat (string; "%.17g") -- specify format for numeric values (shortest possible round-trippable double)
2013-01-08 18:09:12 +00:00
* valignore (table) -- allows to specify a list of values to ignore (as keys)
2013-01-04 02:37:49 +00:00
* keyallow (table) -- allows to specify the list of keys to be serialized. Any keys not in this list are not included in final output (as keys)
2013-01-04 08:24:30 +00:00
* valtypeignore (table) -- allows to specify a list of value *types* to ignore (as keys)
2012-06-13 06:17:44 +00:00
* custom (function) -- provide custom output for tables
2013-11-03 02:20:59 +00:00
* name (string) -- name; triggers full serialization with self-ref section
2012-06-13 06:17:44 +00:00
These options can be provided as a second parameter to Serpent functions.
```lua
block(a, {fatal = true})
2013-01-08 18:09:12 +00:00
line(a, {nocode = true, valignore = {[arrayToIgnore] = true}})
2012-06-13 06:17:44 +00:00
function todiff(a) return dump(a, {nocode = true, indent = ' '}) end
```
2014-01-09 22:05:47 +00:00
Serpent functions set these options to different default values:
* `dump` sets `compact` and `sparse` to `true` ;
* `line` sets `sortkeys` and `comment` to `true` ;
* `block` sets `sortkeys` and `comment` to `true` and `indent` to `' '` .
2013-03-05 18:38:06 +00:00
## Metatables with __tostring and __serialize methods
If a table or a userdata value has `__tostring` or `__serialize` method, the method will be used to serialize the value.
If `__serialize` method is present, it will be called with the value as a parameter.
if `__serialize` method is not present, but `__tostring` is, then `tostring` will be called with the value as a parameter.
In both cases, the result will be serialized, so `__serialize` method can return a table, that will be serialize and replace the original value.
2013-02-27 21:31:18 +00:00
## Sorting
A custom sort function can be provided to sort the contents of tables. The function takes 2 parameters, the first being the table (a list) with the keys, the second the original table. It should modify the first table in-place, and return nothing.
For example, the following call will apply a sort function identical to the standard sort, except that it will not distinguish between lower- and uppercase.
```lua
local mysort = function(k, o) -- k=keys, o=original table
local maxn, to = 12, {number = 'a', string = 'b'}
local function padnum(d) return ("%0"..maxn.."d"):format(d) end
local sort = function(a,b)
2013-02-28 07:19:53 +00:00
-- this -vvvvvvvvvv- is needed to sort array keys first
2013-02-27 21:31:18 +00:00
return ((k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))):upper()
< ((k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum))):upper()
2013-02-28 07:19:53 +00:00
end
2013-02-27 21:31:18 +00:00
table.sort(k, sort)
end
2013-02-28 07:19:53 +00:00
local content = { some = 1, input = 2, To = 3, serialize = 4 }
2013-02-27 21:31:18 +00:00
local result = require('serpent').block(content, {sortkeys = mysort})
```
2012-06-13 06:17:44 +00:00
## Formatters
Serpent supports a way to provide a custom formatter that allows to fully
2014-01-09 22:05:47 +00:00
customize the output. The formatter takes four values:
* tag -- the name of the current element with '=' or an empty string in case of array index,
* head -- an opening table bracket `{` and associated indentation and newline (if any),
* body -- table elements concatenated into a string using commas and indentation/newlines (if any), and
* tail -- a closing table bracket `}` and associated indentation and newline (if any).
For example, the following call will apply
2012-06-13 06:17:44 +00:00
`Foo{bar} notation to its output (used by Metalua to display ASTs):
2012-06-04 05:34:39 +00:00
2012-06-13 06:17:44 +00:00
```lua
print((require "serpent").block(ast, {comment = false, custom =
function(tag,head,body,tail)
local out = head..body..tail
if tag:find('^lineinfo') then
out = out:gsub("\n%s+", "") -- collapse lineinfo to one line
elseif tag == '' then
body = body:gsub('%s*lineinfo = [^\n]+', '')
local _,_ ,atag = body:find('tag = "(%w+)"%s*$')
if atag then
out = "`"..atag..head.. body:gsub('%s*tag = "%w+"%s*$', '')..tail
out = out:gsub("\n%s+", ""):gsub(",}","}")
else out = head..body..tail end
end
return tag..out
end}))
2012-06-04 05:34:39 +00:00
```
## Limitations
* Doesn't handle userdata (except filehandles in `io.*` table).
* Threads, function upvalues/environments, and metatables are not serialized.
## Performance
A simple performance test against `serialize.lua` from metalua, `pretty.write`
from Penlight, and `tserialize.lua` from lua-nucleo is included in `t/bench.lua` .
These are the results from one of the runs:
* nucleo (1000): 0.256s
* metalua (1000): 0.177s
* serpent (1000): 0.22s
* serpent (1000): 0.161s -- no comments, no string escapes, no math.huge check
* penlight (1000): 0.132s
Serpent does additional processing to escape `\010` and `\026` characters in
strings (to address http://lua-users.org/lists/lua-l/2007-07/msg00362.html,
which is already fixed in Lua 5.2) and to check all numbers for `math.huge` .
The seconds number excludes this processing to put it on an equal footing
2012-06-04 05:52:02 +00:00
with other modules that skip these checks (`nucleo` still checks for `math.huge` ).
2012-06-04 05:34:39 +00:00
## Author
Paul Kulchenko (paul@kulchenko.com)
## License
See LICENSE file.
2012-06-13 06:17:44 +00:00
## History
2015-05-07 06:27:44 +00:00
### v0.28 (May 06 2015)
- Switched to a method proposed by @SoniEx2 to disallow function calls (#15).
- Added more `tostring` for Lua 5.3 support (pkulchenko/ZeroBraneStudio#401).
- Updated environment handling to localize the impact (#15).
- Added setting env to protect against assigning global functions (closes #15 ).
- Updated tests to work with Lua 5.3.
- Added explicit `tostring` for Lua 5.3 with `LUA_NOCVTN2S` set (pkulchenko/ZeroBraneStudio#401).
- Fixed crash when not all Lua standard libraries are loaded (thanks to Tommy Nguyen).
- Improved Lua 5.2 support for serialized functions.
2014-01-11 18:38:08 +00:00
### v0.27 (Jan 11 2014)
- Fixed order of elements in the array part with `sortkeys=true` (fixes #13 ).
- Updated custom formatter documentation (closes #11 ).
- Added `load` function to deserialize; updated documentation (closes #9 ).
2013-11-05 19:52:05 +00:00
### v0.26 (Nov 05 2013)
- Added `load` function that (safely) loads serialized/pretty-printed values.
- Updated documentation.
2013-09-29 21:33:15 +00:00
### v0.25 (Sep 29 2013)
- Added `maxnum` option to limit the number of elements in tables.
2013-10-01 04:17:59 +00:00
- Optimized processing of tables with numeric indexes.
2013-09-29 21:33:15 +00:00
2013-06-12 18:06:02 +00:00
### v0.24 (Jun 12 2013)
- Fixed an issue with missing numerical keys (fixes #8 ).
- Fixed an issue with luaffi that returns `getmetatable(ffi.C)` as `true` .
2013-03-24 22:23:31 +00:00
### v0.23 (Mar 24 2013)
- Added support for `cdata` type in LuaJIT (thanks to [Evan ](https://github.com/neomantra )).
- Added comment to indicate incomplete output.
- Added support for metatables with __serialize method.
- Added handling of metatables with __tostring method.
- Fixed an issue with having too many locals in self-reference section.
- Fixed emitting premature circular reference in self-reference section, which caused invalid serialization.
- Modified the sort function signature to also pass the original table, so not only keys are available when sorting, but also the values in the original table.
2013-01-15 19:53:07 +00:00
### v0.22 (Jan 15 2013)
- Added ability to process __tostring results that may be non-string values.
2013-01-08 18:09:12 +00:00
### v0.21 (Jan 08 2013)
- Added `keyallow` and `valtypeignore` options (thanks to Jess Telford).
- Renamed `ignore` to `valignore` .
### v0.19 (Nov 16 2012)
2012-11-17 05:21:42 +00:00
- Fixed an issue with serializing shared functions as keys.
- Added serialization of metatables using __tostring (when present).
2013-01-08 18:09:12 +00:00
### v0.18 (Sep 13 2012)
2012-09-14 01:38:52 +00:00
- Fixed an issue with serializing data structures with circular references that require emitting temporary variables.
- Fixed an issue with serializing keys pointing to shared references.
- Improved overall serialization logic to inline values when possible.
2013-01-08 18:09:12 +00:00
### v0.17 (Sep 12 2012)
2012-09-12 22:18:50 +00:00
- Fixed an issue with serializing userdata that doesn't provide tostring().
2013-01-08 18:09:12 +00:00
### v0.16 (Aug 28 2012)
2012-08-29 04:42:28 +00:00
- Removed confusing --[[err]] comment from serialized results.
- Added a short comment to serialized functions when the body is skipped.
2013-01-08 18:09:12 +00:00
### v0.15 (Jun 17 2012)
2012-06-18 05:33:07 +00:00
- Added `ignore` option to allow ignoring table values.
- Added `comment=num` option to set the max level up to which add comments.
- Changed all comments (except math.huge) to be controlled by `comment` option.
2013-01-08 18:09:12 +00:00
### v0.14 (Jun 13 2012)
2012-06-13 18:07:59 +00:00
- Fixed an issue with string keys with numeric values `['3']` getting mixed
with real numeric keys (only with `sortkeys` option set to `true` ).
2012-06-14 04:06:23 +00:00
- Fixed an issue with negative and real value numeric keys being misplaced.
2012-06-13 18:07:59 +00:00
2013-01-08 18:09:12 +00:00
### v0.13 (Jun 13 2012)
2012-06-18 05:33:07 +00:00
- Added `maxlevel` option.
2012-06-13 17:21:44 +00:00
- Fixed key sorting such that `true` and `'true'` are always sorted in
the same order (for a more stable output).
- Removed addresses from names of temporary variables (for stable output).
2013-01-08 18:09:12 +00:00
### v0.12 (Jun 12 2012)
2012-06-13 06:17:44 +00:00
- Added options to configure serialization process.
2012-06-18 05:33:07 +00:00
- Added `goto` to the list of keywords for Lua 5.2.
2012-06-13 06:17:44 +00:00
- Changed interface to dump/line/block methods.
2012-06-18 05:33:07 +00:00
- Changed `math.huge` to 1/0 for better portability.
2012-06-13 06:17:44 +00:00
- Replaced \010 with \n for better readability.
2013-01-08 18:09:12 +00:00
### v0.10 (Jun 03 2012)
2012-06-13 06:17:44 +00:00
- First public release.