melee-roguelite/lib/fennelview.lua

171 lines
4.7 KiB
Lua
Raw Normal View History

2019-04-20 17:38:53 -07:00
local function view_quote(str)
2018-10-17 18:32:39 -07:00
return ("\"" .. str:gsub("\"", "\\\"") .. "\"")
end
2019-04-20 17:38:53 -07:00
local short_control_char_escapes = {["\11"] = "\\v", ["\12"] = "\\f", ["\13"] = "\\r", ["\7"] = "\\a", ["\8"] = "\\b", ["\9"] = "\\t", ["\n"] = "\\n"}
local long_control_char_esapes
do
local long = {}
2018-10-17 18:32:39 -07:00
for i = 0, 31 do
local ch = string.char(i)
2019-04-20 17:38:53 -07:00
if not short_control_char_escapes[ch] then
short_control_char_escapes[ch] = ("\\" .. i)
long[ch] = ("\\%03d"):format(i)
2018-10-17 18:32:39 -07:00
end
end
2019-04-20 17:38:53 -07:00
long_control_char_esapes = long
2018-10-17 18:32:39 -07:00
end
2019-04-20 17:38:53 -07:00
local function escape(str)
2018-10-17 18:32:39 -07:00
local str = str:gsub("\\", "\\\\")
local str = str:gsub("(%c)%f[0-9]", long_control_char_esapes)
return str:gsub("%c", short_control_char_escapes)
end
2019-04-20 17:38:53 -07:00
local function sequence_key_3f(k, len)
return ((type(k) == "number") and (1 <= k) and (k <= len) and (math.floor(k) == k))
2018-10-17 18:32:39 -07:00
end
2019-04-20 17:38:53 -07:00
local type_order = {["function"] = 5, boolean = 2, number = 1, string = 3, table = 4, thread = 7, userdata = 6}
local function sort_keys(a, b)
2018-10-17 18:32:39 -07:00
local ta = type(a)
local tb = type(b)
2019-04-20 17:38:53 -07:00
if ((ta == tb) and (ta ~= "boolean") and ((ta == "string") or (ta == "number"))) then
return (a < b)
2018-10-17 18:32:39 -07:00
else
local dta = type_order[a]
local dtb = type_order[b]
if (dta and dtb) then
2019-04-20 17:38:53 -07:00
return (dta < dtb)
2018-10-17 18:32:39 -07:00
elseif dta then
return true
elseif dtb then
return false
elseif "else" then
2019-04-20 17:38:53 -07:00
return (ta < tb)
2018-10-17 18:32:39 -07:00
end
end
end
2019-04-20 17:38:53 -07:00
local function get_sequence_length(t)
2018-10-17 18:32:39 -07:00
local len = 1
for i in ipairs(t) do
len = i
end
return len
end
2019-04-20 17:38:53 -07:00
local function get_nonsequential_keys(t)
local keys = {}
2018-10-17 18:32:39 -07:00
local sequence_length = get_sequence_length(t)
for k in pairs(t) do
2019-04-20 17:38:53 -07:00
if not sequence_key_3f(k, sequence_length) then
table.insert(keys, k)
2018-10-17 18:32:39 -07:00
end
end
table.sort(keys, sort_keys)
return keys, sequence_length
end
2019-04-20 17:38:53 -07:00
local function count_table_appearances(t, appearances)
if (type(t) == "table") then
if not appearances[t] then
appearances[t] = 1
for k, v in pairs(t) do
count_table_appearances(k, appearances)
count_table_appearances(v, appearances)
2018-10-17 18:32:39 -07:00
end
end
2019-04-20 17:38:53 -07:00
else
if (t and (t == t)) then
appearances[t] = ((appearances[t] or 0) + 1)
end
2018-10-17 18:32:39 -07:00
end
return appearances
end
local put_value = nil
2019-04-20 17:38:53 -07:00
local function puts(self, ...)
for _, v in ipairs({...}) do
2018-10-17 18:32:39 -07:00
table.insert(self.buffer, v)
end
return nil
end
2019-04-20 17:38:53 -07:00
local function tabify(self)
2018-10-17 18:32:39 -07:00
return puts(self, "\n", self.indent:rep(self.level))
end
2019-04-20 17:38:53 -07:00
local function already_visited_3f(self, v)
return (self.ids[v] ~= nil)
2018-10-17 18:32:39 -07:00
end
2019-04-20 17:38:53 -07:00
local function get_id(self, v)
2018-10-17 18:32:39 -07:00
local id = self.ids[v]
2019-04-20 17:38:53 -07:00
if not id then
local tv = type(v)
id = ((self["max-ids"][tv] or 0) + 1)
self["max-ids"][tv] = id
self.ids[v] = id
2018-10-17 18:32:39 -07:00
end
return tostring(id)
end
2019-04-20 17:38:53 -07:00
local function put_sequential_table(self, t, length)
2018-10-17 18:32:39 -07:00
puts(self, "[")
self.level = (self.level + 1)
for i = 1, length do
puts(self, " ")
put_value(self, t[i])
end
self.level = (self.level - 1)
return puts(self, " ]")
end
2019-04-20 17:38:53 -07:00
local function put_key(self, k)
if ((type(k) == "string") and k:find("^[-%w?\\^_`!#$%&*+./@~:|<=>]+$")) then
2018-10-17 18:32:39 -07:00
return puts(self, ":", k)
else
return put_value(self, k)
end
end
2019-04-20 17:38:53 -07:00
local function put_kv_table(self, t)
2018-10-17 18:32:39 -07:00
puts(self, "{")
self.level = (self.level + 1)
for k, v in pairs(t) do
tabify(self)
put_key(self, k)
puts(self, " ")
put_value(self, v)
end
self.level = (self.level - 1)
tabify(self)
return puts(self, "}")
end
2019-04-20 17:38:53 -07:00
local function put_table(self, t)
2018-10-17 18:32:39 -07:00
if already_visited_3f(self, t) then
return puts(self, "#<table ", get_id(self, t), ">")
2019-04-20 17:38:53 -07:00
elseif (self.level >= self.depth) then
2018-10-17 18:32:39 -07:00
return puts(self, "{...}")
elseif "else" then
local non_seq_keys, length = get_nonsequential_keys(t)
local id = get_id(self, t)
2019-04-20 17:38:53 -07:00
if (self.appearances[t] > 1) then
2018-10-17 18:32:39 -07:00
return puts(self, "#<", id, ">")
2019-04-20 17:38:53 -07:00
elseif ((#non_seq_keys == 0) and (#t == 0)) then
2018-10-17 18:32:39 -07:00
return puts(self, "{}")
2019-04-20 17:38:53 -07:00
elseif (#non_seq_keys == 0) then
2018-10-17 18:32:39 -07:00
return put_sequential_table(self, t, length)
elseif "else" then
return put_kv_table(self, t)
end
end
end
2019-04-20 17:38:53 -07:00
local function _0_(self, v)
2018-10-17 18:32:39 -07:00
local tv = type(v)
2019-04-20 17:38:53 -07:00
if (tv == "string") then
return puts(self, view_quote(escape(v)))
elseif ((tv == "number") or (tv == "boolean") or (tv == "nil")) then
2018-10-17 18:32:39 -07:00
return puts(self, tostring(v))
2019-04-20 17:38:53 -07:00
elseif (tv == "table") then
2018-10-17 18:32:39 -07:00
return put_table(self, v)
elseif "else" then
2019-04-20 17:38:53 -07:00
return puts(self, "#<", tostring(v), ">")
2018-10-17 18:32:39 -07:00
end
end
2019-04-20 17:38:53 -07:00
put_value = _0_
local function fennelview(root, options)
local options = (options or {})
local inspector = {["max-ids"] = {}, appearances = count_table_appearances(root, {}), buffer = {}, depth = (options.depth or 128), ids = {}, indent = (options.indent or " "), level = 0}
2018-10-17 18:32:39 -07:00
put_value(inspector, root)
return table.concat(inspector.buffer)
end
2019-04-20 17:38:53 -07:00
return fennelview