Last active
December 11, 2016 13:24
-
-
Save notwa/13fbddf05f654ba48321 to your computer and use it in GitHub Desktop.
lua table dumping as pseudo-yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__root: &__root_t0x4004f960 | |
_G: *__root_t0x4004f960 | |
_VERSION: Lua 5.1 | |
arg: &arg_t0x40055cc8 | |
"-1": luajit | |
0: run.lua | |
assert: fbuiltin#2 | |
bit: &bit_t0x40054d58 | |
arshift: fbuiltin#70 | |
band: fbuiltin#73 | |
bnot: fbuiltin#66 | |
bor: fbuiltin#74 | |
bswap: fbuiltin#67 | |
bxor: fbuiltin#75 | |
lshift: fbuiltin#68 | |
rol: fbuiltin#71 | |
ror: fbuiltin#72 | |
rshift: fbuiltin#69 | |
tobit: fbuiltin#65 | |
tohex: fbuiltin#76 | |
collectgarbage: fbuiltin#27 | |
coroutine: &coroutine_t0x40051730 | |
create: fbuiltin#32 | |
resume: fbuiltin#34 | |
running: fbuiltin#31 | |
status: fbuiltin#30 | |
wrap: fbuiltin#36 | |
yield: fbuiltin#33 | |
debug: &debug_t0x40054740 | |
debug: fbuiltin#145 | |
getfenv: fbuiltin#134 | |
gethook: fbuiltin#144 | |
getinfo: fbuiltin#136 | |
getlocal: fbuiltin#137 | |
getmetatable: fbuiltin#132 | |
getregistry: fbuiltin#131 | |
getupvalue: fbuiltin#139 | |
setfenv: fbuiltin#135 | |
sethook: fbuiltin#143 | |
setlocal: fbuiltin#138 | |
setmetatable: fbuiltin#133 | |
setupvalue: fbuiltin#140 | |
traceback: fbuiltin#146 | |
upvalueid: fbuiltin#141 | |
upvaluejoin: fbuiltin#142 | |
dofile: fbuiltin#25 | |
dump: f0x4005dd40 | |
error: fbuiltin#19 | |
gcinfo: fbuiltin#26 | |
getfenv: fbuiltin#10 | |
getmetatable: fbuiltin#8 | |
io: &io_t0x40052a90 | |
close: fbuiltin#112 | |
flush: fbuiltin#115 | |
input: fbuiltin#116 | |
lines: fbuiltin#118 | |
open: fbuiltin#109 | |
output: fbuiltin#117 | |
popen: fbuiltin#110 | |
read: fbuiltin#113 | |
stderr: file (0x7ff9dd21f500) | |
stdin: file (0x7ff9dd21e8a0) | |
stdout: file (0x7ff9dd21f5e0) | |
tmpfile: fbuiltin#111 | |
type: fbuiltin#119 | |
write: fbuiltin#114 | |
ipairs: fbuiltin#7 | |
jit: &jit_t0x40055318 | |
arch: x64 | |
attach: fbuiltin#151 | |
flush: fbuiltin#149 | |
off: fbuiltin#148 | |
on: fbuiltin#147 | |
opt: &opt_t0x40055bd8 | |
start: fbuiltin#163 | |
os: Linux | |
status: fbuiltin#150 | |
util: &util_t0x400556a0 | |
funcbc: fbuiltin#153 | |
funcinfo: fbuiltin#152 | |
funck: fbuiltin#154 | |
funcuvname: fbuiltin#155 | |
ircalladdr: fbuiltin#162 | |
traceexitstub: fbuiltin#161 | |
traceinfo: fbuiltin#156 | |
traceir: fbuiltin#157 | |
tracek: fbuiltin#158 | |
tracemc: fbuiltin#160 | |
tracesnap: fbuiltin#159 | |
version: LuaJIT 2.0.4 | |
version_num: 20004 | |
load: fbuiltin#23 | |
loadfile: fbuiltin#22 | |
loadstring: fbuiltin#24 | |
math: &math_t0x40053b60 | |
abs: fbuiltin#37 | |
acos: fbuiltin#47 | |
asin: fbuiltin#46 | |
atan: fbuiltin#48 | |
atan2: fbuiltin#57 | |
ceil: fbuiltin#39 | |
cos: fbuiltin#44 | |
cosh: fbuiltin#50 | |
deg: fbuiltin#54 | |
exp: fbuiltin#42 | |
floor: fbuiltin#38 | |
fmod: fbuiltin#59 | |
frexp: fbuiltin#52 | |
huge: inf | |
ldexp: fbuiltin#60 | |
log: fbuiltin#56 | |
log10: fbuiltin#41 | |
max: fbuiltin#62 | |
min: fbuiltin#61 | |
mod: fbuiltin#59 | |
modf: fbuiltin#53 | |
pi: 3.1415926535898 | |
pow: fbuiltin#58 | |
rad: fbuiltin#55 | |
random: fbuiltin#63 | |
randomseed: fbuiltin#64 | |
sin: fbuiltin#43 | |
sinh: fbuiltin#49 | |
sqrt: fbuiltin#40 | |
tan: fbuiltin#45 | |
tanh: fbuiltin#51 | |
module: f0x40051ee0 | |
newproxy: fbuiltin#28 | |
next: fbuiltin#4 | |
os: &os_t0x40052fd0 | |
clock: fbuiltin#126 | |
date: fbuiltin#127 | |
difftime: fbuiltin#129 | |
execute: fbuiltin#120 | |
exit: fbuiltin#125 | |
getenv: fbuiltin#124 | |
remove: fbuiltin#121 | |
rename: fbuiltin#122 | |
setlocale: fbuiltin#130 | |
time: fbuiltin#128 | |
tmpname: fbuiltin#123 | |
package: &package_t0x40051ac8 | |
config: | |
/ | |
; | |
? | |
! | |
- | |
cpath: /home/notwa/opt/local/lib/?.so;/home/notwa/.luarocks/lib/lua/5.1/?.so;/home/notwa/opt/local/lib/lua/5.1/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so | |
loaded: &loaded_t0x40050b38 | |
_G: *__root_t0x4004f960 | |
bit: *bit_t0x40054d58 | |
coroutine: *coroutine_t0x40051730 | |
debug: *debug_t0x40054740 | |
extra: &extra_t0x4005cd30 | |
add_zeros: f0x4005db58 | |
mixed_sorter: f0x4005db98 | |
opairs: f0x4005cca8 | |
order_keys: f0x4005b2f8 | |
strpad: f0x4004f8b8 | |
traverse: f0x4005cce8 | |
io: *io_t0x40052a90 | |
jit: *jit_t0x40055318 | |
"jit.opt": *opt_t0x40055bd8 | |
"jit.util": *util_t0x400556a0 | |
math: *math_t0x40053b60 | |
os: *os_t0x40052fd0 | |
package: *package_t0x40051ac8 | |
pt: &pt_t0x4005ce20 | |
__metatable: *pt_t0x4005ce20 | |
__call: f0x4005dc98 | |
__index: *pt_t0x4005ce20 | |
inner: f0x4005dde0 | |
outer: f0x4005dd18 | |
outer_old: f0x4005dc00 | |
safecanon: f0x4005dd60 | |
safekey: f0x4005dd80 | |
safeval: f0x4005ddc0 | |
write: f0x4005dcd8 | |
string: *string_t0x400534b0 | |
table: *table_t0x400522f8 | |
loaders: &loaders_t0x40051c38 | |
1: f0x40051c88 | |
2: f0x40051cb0 | |
3: f0x40051cd8 | |
4: f0x40051d00 | |
loadlib: f0x40051b58 | |
path: /home/notwa/.luarocks/share/lua/5.1/?.lua;/home/notwa/.luarocks/share/lua/5.1/?/init.lua;/home/notwa/opt/local/share/lua/5.1/?.lua;/home/notwa/opt/local/share/lua/5.1/?/init.lua;./?.lua;/home/notwa/opt/local/share/luajit-2.1.0-beta1/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua | |
preload: &preload_t0x400520c0 | |
ffi: f0x40055c80 | |
searchpath: f0x40051ba0 | |
seeall: f0x40051bf0 | |
pairs: fbuiltin#5 | |
pcall: fbuiltin#20 | |
print: fbuiltin#29 | |
rawequal: fbuiltin#14 | |
rawget: fbuiltin#12 | |
rawset: fbuiltin#13 | |
require: f0x40051f28 | |
select: fbuiltin#16 | |
setfenv: fbuiltin#11 | |
setmetatable: fbuiltin#9 | |
string: &string_t0x400534b0 | |
byte: fbuiltin#78 | |
char: fbuiltin#79 | |
dump: fbuiltin#85 | |
find: fbuiltin#86 | |
format: fbuiltin#91 | |
gfind: fbuiltin#89 | |
gmatch: fbuiltin#89 | |
gsub: fbuiltin#90 | |
len: fbuiltin#77 | |
lower: fbuiltin#83 | |
match: fbuiltin#87 | |
rep: fbuiltin#81 | |
reverse: fbuiltin#82 | |
sub: fbuiltin#80 | |
upper: fbuiltin#84 | |
t: &t_t0x4005e298 | |
A: hello | |
B: &B_t0x4005e328 | |
a: beep | |
b: boop | |
c: burp | |
d: *d_t0x4005e550 | |
C: &d_t0x4005e550 | |
a: nude | |
b: dude | |
c: lewd | |
d: *B_t0x4005e328 | |
D: goodbye | |
E: *t_t0x4005e298 | |
table: &table_t0x400522f8 | |
concat: fbuiltin#98 | |
foreach: fbuiltin#93 | |
foreachi: fbuiltin#92 | |
getn: fbuiltin#94 | |
insert: fbuiltin#96 | |
maxn: fbuiltin#95 | |
remove: fbuiltin#97 | |
sort: fbuiltin#99 | |
tonumber: fbuiltin#17 | |
tostring: fbuiltin#18 | |
type: fbuiltin#3 | |
unpack: fbuiltin#15 | |
xpcall: fbuiltin#21 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local insert = table.insert | |
local pairs = pairs | |
local rawget = rawget | |
local sort = table.sort | |
local tostring = tostring | |
local type = type | |
local function strpad(num, count, pad) | |
num = tostring(num) | |
return (pad:rep(count)..num):sub(#num) | |
end | |
local function add_zeros(num, count) | |
return strpad(num, count - 1, '0') | |
end | |
local function mixed_sorter(a, b) | |
a = type(a) == 'number' and add_zeros(a, 16) or tostring(a) | |
b = type(b) == 'number' and add_zeros(b, 16) or tostring(b) | |
return a < b | |
end | |
-- loosely based on http://lua-users.org/wiki/SortedIteration | |
-- the original didn't make use of closures for who knows why | |
local function order_keys(t) | |
local oi = {} | |
for key in pairs(t) do | |
insert(oi, key) | |
end | |
sort(oi, mixed_sorter) | |
return oi | |
end | |
local function opairs(t, cache) | |
local oi = cache and cache[t] or order_keys(t) | |
if cache then | |
cache[t] = oi | |
end | |
local i = 0 | |
return function() | |
i = i + 1 | |
local key = oi[i] | |
if key ~= nil then return key, t[key] end | |
end | |
end | |
local function traverse(path) | |
if not path then return end | |
local parent = _G | |
local key | |
for w in path:gfind("[%w_]+") do | |
if key then | |
parent = rawget(parent, key) | |
if type(parent) ~= 'table' then return end | |
end | |
key = w | |
end | |
if not key then return end | |
return {parent=parent, key=key} | |
end | |
return { | |
strpad = strpad, | |
add_zeros = add_zeros, | |
mixed_sorter = mixed_sorter, | |
order_keys = order_keys, | |
opairs = opairs, | |
traverse = traverse, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local path = string.gsub(..., "[^.]+$", "") | |
return require(path.."pt") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local path = string.gsub(..., "[^.]+$", "") | |
local extra = require(path.."extra") | |
local opairs = extra.opairs | |
local pt = {} | |
pt.__index = pt | |
setmetatable(pt, pt) | |
local function rawstr(v) | |
if v == nil then return 'nil' end | |
local mt = getmetatable(v) | |
local ts = mt and rawget(mt, '__tostring') | |
if not ts then return tostring(v) end | |
mt.__tostring = nil | |
local s = tostring(v) | |
mt.__tostring = ts | |
return s | |
end | |
local function getaddr(t) | |
return rawstr(t):sub(#type(t) + 3) | |
end | |
local function copy(t) | |
-- shallow copy | |
if type(t) ~= 'table' then return end | |
local new = {} | |
for k,v in pairs(t) do | |
new[k] = v | |
end | |
return new | |
end | |
function pt.__call(pt, args) | |
-- print a table as semi-valid YAML | |
-- with references to prevent recursion/duplication | |
local t = args.table or args[1] | |
local self = {} | |
setmetatable(self, pt) | |
self.seen = copy(args.seen) or {} | |
self.skipped = copy(args.skipped) or {} | |
self.seen_elsewhere = args.seen or {} | |
self.depth = args.depth or 16 | |
self.writer = args.writer or io.write | |
self.skeleton = args.skeleton or false | |
self.outer = args.alt_order and self.outer_old or self.outer | |
self.noncanon = args.noncanon or false | |
self.indent = args.indent or ' ' | |
self.queued = {} | |
self.cache = {} | |
self.canonicalized = {} | |
self:inner('__root', t, '') | |
return self.seen | |
end | |
function pt:write(...) | |
self.writer(...) | |
end | |
function pt:safecanon(k) | |
local s = tostring(k) | |
return s:gsub('[^%w_]', '_') | |
end | |
function pt:safekey(k) | |
if type(k) == 'table' then | |
return 't'..getaddr(k) | |
end | |
local s = tostring(k) | |
s = s:gsub('[\r\n]', '') | |
return s:find('[^%w_]') and ('%q'):format(s) or s | |
end | |
function pt:safeval(v, indentation) | |
if type(v) == 'function' then | |
return 'f'..getaddr(v) | |
end | |
local s = tostring(v) | |
if type(v) == 'number' then | |
return s | |
end | |
-- TODO: move newline/indentation handling to another function? | |
if s:find('[\r\n]') then | |
s = ('\n'..s):gsub('[\r\n]', '\n'..indentation..self.indent) | |
end | |
--local safe = ('%q'):format(s) | |
--return s == safe:sub(2, -2) and s or safe | |
-- TODO: finish matching valid characters | |
return s:find('[^%w_()[]{}.]') and ('%q'):format(s) or s | |
end | |
function pt:inner(k, v, indentation) | |
if type(v) ~= 'table' then | |
if self.skeleton then return end | |
self:write(indentation, self:safekey(k), ': ') | |
self:write(self:safeval(v, indentation), '\n') | |
return | |
end | |
local addr = getaddr(v) | |
self:write(indentation, self:safekey(k)) | |
local canon | |
if not self.noncanon and type(k) ~= 'table' then | |
canon = self.canonicalized[addr] | |
if canon == nil then | |
canon = self:safecanon(k)..'_t'..addr | |
self.canonicalized[addr] = canon | |
end | |
else | |
canon = 't'..addr | |
end | |
if #indentation > self.depth or self.skipped[addr] then | |
--self.skipped[addr] = true -- TODO: extra logics | |
self:write(': #', canon, '\n') | |
return | |
end | |
if self.seen[addr] or self.queued[addr] then | |
self:write(': *', canon, self.seen_elsewhere[addr] and ' #\n' or '\n') | |
return | |
end | |
self.seen[addr] = true | |
self:write(': &', canon, '\n') | |
self:outer(v, indentation..self.indent) | |
end | |
function pt:outer_old(t, indentation) | |
if type(t) ~= "table" then | |
local s = self:safeval(t, indentation) | |
self:write(indentation, s, '\n') | |
return | |
end | |
local ours = {} | |
local not_ours = {} | |
for k,v in opairs(t) do | |
if type(v) == 'table' then | |
local addr = getaddr(v) | |
if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then | |
self.queued[addr] = true | |
ours[k] = v | |
else | |
not_ours[k] = v | |
end | |
else | |
self:inner(k, v, indentation) | |
end | |
end | |
for k,v in opairs(not_ours) do | |
self:inner(k, v, indentation) | |
end | |
for k,v in opairs(ours) do | |
self.queued[getaddr(v)] = nil | |
self:inner(k, v, indentation) | |
end | |
local mt = getmetatable(t) | |
if mt ~= nil then | |
self:inner('__metatable', mt, indentation) | |
end | |
end | |
function pt:outer(t, indentation) | |
if type(t) ~= "table" then | |
local s = self:safeval(t, indentation) | |
self:write(indentation, s, '\n') | |
return | |
end | |
local ours = {} | |
for k,v in opairs(t, self.cache) do | |
if type(v) == 'table' then | |
local addr = getaddr(v) | |
if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then | |
self.queued[addr] = true | |
ours[k] = addr | |
end | |
end | |
end | |
local mt = getmetatable(t) | |
if mt ~= nil then | |
self:inner('__metatable', mt, indentation) | |
end | |
for k,v in opairs(t, self.cache) do | |
local addr = ours[k] | |
if addr then | |
self.queued[addr] = nil | |
end | |
self:inner(k, v, indentation) | |
end | |
end | |
return pt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/lua | |
local pt = require('pt') | |
t = { | |
A = 'hello', | |
B = { | |
a = 'beep', | |
b = 'boop', | |
c = 'burp', | |
}, | |
C = { | |
a = 'nude', | |
b = 'dude', | |
c = 'lewd', | |
}, | |
D = 'goodbye', | |
} | |
t.B.d = t.C | |
t.C.d = t.B | |
t.E = t | |
function dump(t, fn, seen) | |
if t == nil then return end | |
local file = io.open(fn, "w") | |
if not file then | |
io.write("Failed opening ", fn, "\n") | |
return | |
end | |
local writer = function(...) | |
file:write(...) | |
end | |
seen = pt{t, writer=writer, seen=seen} | |
file:close() | |
return seen | |
end | |
pt{t} | |
dump(_G, '_G.yml') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment