You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
6.5 KiB
262 lines
6.5 KiB
-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro>
|
|
--
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
-- this software and associated documentation files (the "Software"), to deal in
|
|
-- the Software without restriction, including without limitation the rights to
|
|
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
-- the Software, and to permit persons to whom the Software is furnished to do so,
|
|
-- subject to the following conditions:
|
|
--
|
|
-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
--
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
-- Pretty prints expression results (console only)
|
|
|
|
local format = string.format
|
|
local tconcat = table.concat
|
|
local tsort = table.sort
|
|
local tostring = tostring
|
|
local type = type
|
|
local floor = math.floor
|
|
local pairs = pairs
|
|
local ipairs = ipairs
|
|
local error = error
|
|
local stderr = io.stderr
|
|
|
|
pcall(require, 'luarocks.require')
|
|
local ok, term = pcall(require, 'term')
|
|
if not ok then
|
|
term = nil
|
|
end
|
|
|
|
local keywords = {
|
|
['and'] = true,
|
|
['break'] = true,
|
|
['do'] = true,
|
|
['else'] = true,
|
|
['elseif'] = true,
|
|
['end'] = true,
|
|
['false'] = true,
|
|
['for'] = true,
|
|
['function'] = true,
|
|
['if'] = true,
|
|
['in'] = true,
|
|
['local'] = true,
|
|
['nil'] = true,
|
|
['not'] = true,
|
|
['or'] = true,
|
|
['repeat'] = true,
|
|
['return'] = true,
|
|
['then'] = true,
|
|
['true'] = true,
|
|
['until'] = true,
|
|
['while'] = true,
|
|
}
|
|
|
|
local function compose(f, g)
|
|
return function(...)
|
|
return f(g(...))
|
|
end
|
|
end
|
|
|
|
local emptycolormap = setmetatable({}, { __index = function()
|
|
return function(s)
|
|
return s
|
|
end
|
|
end})
|
|
|
|
local colormap = emptycolormap
|
|
|
|
if term then
|
|
colormap = {
|
|
['nil'] = term.colors.blue,
|
|
string = term.colors.yellow,
|
|
punctuation = compose(term.colors.green, term.colors.bright),
|
|
ident = term.colors.red,
|
|
boolean = term.colors.green,
|
|
number = term.colors.cyan,
|
|
path = term.colors.white,
|
|
misc = term.colors.magenta,
|
|
}
|
|
end
|
|
|
|
local function isinteger(n)
|
|
return type(n) == 'number' and floor(n) == n
|
|
end
|
|
|
|
local function isident(s)
|
|
return type(s) == 'string' and not keywords[s] and s:match('^[a-zA-Z_][a-zA-Z0-9_]*$')
|
|
end
|
|
|
|
-- most of these are arbitrary, I *do* want numbers first, though
|
|
local type_order = {
|
|
number = 0,
|
|
string = 1,
|
|
userdata = 2,
|
|
table = 3,
|
|
thread = 4,
|
|
boolean = 5,
|
|
['function'] = 6,
|
|
cdata = 7,
|
|
}
|
|
|
|
local function cross_type_order(a, b)
|
|
local pos_a = type_order[ type(a) ]
|
|
local pos_b = type_order[ type(b) ]
|
|
|
|
if pos_a == pos_b then
|
|
return a < b
|
|
else
|
|
return pos_a < pos_b
|
|
end
|
|
end
|
|
|
|
local function sortedpairs(t)
|
|
local keys = {}
|
|
|
|
local seen_non_string
|
|
|
|
for k in pairs(t) do
|
|
keys[#keys + 1] = k
|
|
|
|
if not seen_non_string and type(k) ~= 'string' then
|
|
seen_non_string = true
|
|
end
|
|
end
|
|
|
|
local sort_func = seen_non_string and cross_type_order or nil
|
|
tsort(keys, sort_func)
|
|
|
|
local index = 1
|
|
return function()
|
|
if keys[index] == nil then
|
|
return nil
|
|
else
|
|
local key = keys[index]
|
|
local value = t[key]
|
|
index = index + 1
|
|
|
|
return key, value
|
|
end
|
|
end, keys
|
|
end
|
|
|
|
local function find_longstring_nest_level(s)
|
|
local level = 0
|
|
|
|
while s:find(']' .. string.rep('=', level) .. ']', 1, true) do
|
|
level = level + 1
|
|
end
|
|
|
|
return level
|
|
end
|
|
|
|
local function dump(params)
|
|
local pieces = params.pieces
|
|
local seen = params.seen
|
|
local path = params.path
|
|
local v = params.value
|
|
local indent = params.indent
|
|
|
|
local t = type(v)
|
|
|
|
if t == 'nil' or t == 'boolean' or t == 'number' then
|
|
pieces[#pieces + 1] = colormap[t](tostring(v))
|
|
elseif t == 'string' then
|
|
if v:match '\n' then
|
|
local level = find_longstring_nest_level(v)
|
|
pieces[#pieces + 1] = colormap.string('[' .. string.rep('=', level) .. '[' .. v .. ']' .. string.rep('=', level) .. ']')
|
|
else
|
|
pieces[#pieces + 1] = colormap.string(format('%q', v))
|
|
end
|
|
elseif t == 'table' then
|
|
if seen[v] then
|
|
pieces[#pieces + 1] = colormap.path(seen[v])
|
|
return
|
|
end
|
|
|
|
seen[v] = path
|
|
|
|
local lastintkey = 0
|
|
|
|
pieces[#pieces + 1] = colormap.punctuation '{\n'
|
|
for i, v in ipairs(v) do
|
|
for j = 1, indent do
|
|
pieces[#pieces + 1] = ' '
|
|
end
|
|
dump {
|
|
pieces = pieces,
|
|
seen = seen,
|
|
path = path .. '[' .. tostring(i) .. ']',
|
|
value = v,
|
|
indent = indent + 1,
|
|
}
|
|
pieces[#pieces + 1] = colormap.punctuation ',\n'
|
|
lastintkey = i
|
|
end
|
|
|
|
for k, v in sortedpairs(v) do
|
|
if not (isinteger(k) and k <= lastintkey and k > 0) then
|
|
for j = 1, indent do
|
|
pieces[#pieces + 1] = ' '
|
|
end
|
|
|
|
if isident(k) then
|
|
pieces[#pieces + 1] = colormap.ident(k)
|
|
else
|
|
pieces[#pieces + 1] = colormap.punctuation '['
|
|
dump {
|
|
pieces = pieces,
|
|
seen = seen,
|
|
path = path .. '.' .. tostring(k),
|
|
value = k,
|
|
indent = indent + 1,
|
|
}
|
|
pieces[#pieces + 1] = colormap.punctuation ']'
|
|
end
|
|
pieces[#pieces + 1] = colormap.punctuation ' = '
|
|
dump {
|
|
pieces = pieces,
|
|
seen = seen,
|
|
path = path .. '.' .. tostring(k),
|
|
value = v,
|
|
indent = indent + 1,
|
|
}
|
|
pieces[#pieces + 1] = colormap.punctuation ',\n'
|
|
end
|
|
end
|
|
|
|
for j = 1, indent - 1 do
|
|
pieces[#pieces + 1] = ' '
|
|
end
|
|
|
|
pieces[#pieces + 1] = colormap.punctuation '}'
|
|
else
|
|
pieces[#pieces + 1] = colormap.misc(tostring(v))
|
|
end
|
|
end
|
|
|
|
repl:requirefeature 'console'
|
|
|
|
function override:displayresults(results)
|
|
local pieces = {}
|
|
|
|
for i = 1, results.n do
|
|
dump {
|
|
pieces = pieces,
|
|
seen = {},
|
|
path = '<topvalue>',
|
|
value = results[i],
|
|
indent = 1,
|
|
}
|
|
pieces[#pieces + 1] = '\n'
|
|
end
|
|
|
|
stderr:write(tconcat(pieces, ''))
|
|
end
|
|
|