201 lines
5.6 KiB
Lua
Executable File
201 lines
5.6 KiB
Lua
Executable File
--------------------------------------------------------------------------------
|
|
---------------------- ## ##### ##### ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## ## -----------------------
|
|
---------------------- ## ## ## ## ## ###### -----------------------
|
|
---------------------- ## ## ## ## ## ## -----------------------
|
|
---------------------- ###### ##### ##### ## -----------------------
|
|
---------------------- -----------------------
|
|
----------------------- Lua Object-Oriented Programming ------------------------
|
|
--------------------------------------------------------------------------------
|
|
-- Project: LOOP Class Library --
|
|
-- Release: 2.3 beta --
|
|
-- Title : Visualization of Lua Values --
|
|
-- Author : Renato Maia <maia@inf.puc-rio.br> --
|
|
--------------------------------------------------------------------------------
|
|
|
|
local _G = _G
|
|
local select = select
|
|
local type = type
|
|
local next = next
|
|
local pairs = pairs
|
|
local rawget = rawget
|
|
local rawset = rawset
|
|
local getmetatable = getmetatable
|
|
local setmetatable = setmetatable
|
|
local luatostring = tostring
|
|
local loaded = package and package.loaded
|
|
|
|
local string = require "string"
|
|
local table = require "table"
|
|
local io = require "io"
|
|
local oo = require "loop.base"
|
|
|
|
module("loop.debug.Viewer", oo.class)
|
|
|
|
maxdepth = -1
|
|
indentation = " "
|
|
linebreak = "\n"
|
|
prefix = ""
|
|
output = io.output()
|
|
|
|
function writevalue(self, buffer, value, history, prefix, maxdepth)
|
|
local luatype = type(value)
|
|
if luatype == "nil" or luatype == "boolean" or luatype == "number" then
|
|
buffer:write(luatostring(value))
|
|
elseif luatype == "string" then
|
|
buffer:write(string.format("%q", value))
|
|
else
|
|
local label = history[value]
|
|
if label then
|
|
buffer:write(label)
|
|
else
|
|
label = self.labels[value] or self:label(value)
|
|
history[value] = label
|
|
if luatype == "table" then
|
|
buffer:write("{ --[[",label,"]]")
|
|
local key, field = next(value)
|
|
if key then
|
|
if maxdepth == 0 then
|
|
buffer:write(" ... ")
|
|
else
|
|
maxdepth = maxdepth - 1
|
|
local newprefix = prefix..self.indentation
|
|
for i = 1, #value do
|
|
buffer:write(self.linebreak, newprefix)
|
|
self:writevalue(buffer, value[i], history, newprefix, maxdepth)
|
|
buffer:write(",")
|
|
end
|
|
repeat
|
|
local keytype = type(key)
|
|
if keytype ~= "number" or key<=0 or key>#value or (key%1)~=0 then
|
|
buffer:write(self.linebreak, newprefix)
|
|
if keytype == "string" and key:match("^[%a_][%w_]*$") then
|
|
buffer:write(key)
|
|
else
|
|
buffer:write("[")
|
|
self:writevalue(buffer, key, history, newprefix, maxdepth)
|
|
buffer:write("]")
|
|
end
|
|
buffer:write(" = ")
|
|
self:writevalue(buffer, field, history, newprefix, maxdepth)
|
|
buffer:write(",")
|
|
end
|
|
key, field = next(value, key)
|
|
until not key
|
|
buffer:write(self.linebreak, prefix)
|
|
end
|
|
else
|
|
buffer:write(" ")
|
|
end
|
|
buffer:write("}")
|
|
else
|
|
buffer:write(label)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function writeto(self, buffer, ...)
|
|
local prefix = self.prefix
|
|
local maxdepth = self.maxdepth
|
|
local history = {}
|
|
for i = 1, select("#", ...) do
|
|
if i ~= 1 then buffer:write(", ") end
|
|
self:writevalue(buffer, select(i, ...), history, prefix, maxdepth)
|
|
end
|
|
end
|
|
|
|
local function add(self, ...)
|
|
for i = 1, select("#", ...) do self[#self+1] = select(i, ...) end
|
|
end
|
|
function tostring(self, ...)
|
|
local buffer = { write = add }
|
|
self:writeto(buffer, ...)
|
|
return table.concat(buffer)
|
|
end
|
|
|
|
function write(self, ...)
|
|
self:writeto(self.output, ...)
|
|
end
|
|
|
|
function print(self, ...)
|
|
local output = self.output
|
|
local prefix = self.prefix
|
|
local maxdepth = self.maxdepth
|
|
local history = {}
|
|
local value
|
|
for i = 1, select("#", ...) do
|
|
value = select(i, ...)
|
|
if type(value) == "string"
|
|
then output:write(value)
|
|
else self:writevalue(output, value, history, prefix, maxdepth)
|
|
end
|
|
end
|
|
output:write("\n")
|
|
end
|
|
|
|
function label(self, value)
|
|
local meta = getmetatable(value)
|
|
if meta then
|
|
local custom = rawget(meta, "__tostring")
|
|
if custom then
|
|
rawset(meta, "__tostring", nil)
|
|
local raw = luatostring(value)
|
|
rawset(meta, "__tostring", custom)
|
|
custom = luatostring(value)
|
|
if raw == custom
|
|
then return raw
|
|
else return custom.." ("..raw..")"
|
|
end
|
|
end
|
|
end
|
|
return luatostring(value)
|
|
end
|
|
|
|
function package(self, name, pack)
|
|
local labels = self.labels
|
|
labels[pack] = name
|
|
for field, member in pairs(pack) do
|
|
local kind = type(member)
|
|
if
|
|
labels[member] == nil and
|
|
(kind == "function" or kind == "userdata") and
|
|
field:match("^[%a_]+[%w_]*$")
|
|
then
|
|
labels[member] = name.."."..field
|
|
end
|
|
end
|
|
end
|
|
|
|
if loaded then
|
|
local luapacks = {
|
|
coroutine = true,
|
|
package = true,
|
|
string = true,
|
|
table = true,
|
|
math = true,
|
|
io = true,
|
|
os = true,
|
|
}
|
|
-- create cache for global values
|
|
labels = { __mode = "k" }
|
|
setmetatable(labels, labels)
|
|
-- cache names of global functions
|
|
for name, func in pairs(_G) do
|
|
if type(func) == "function" then
|
|
labels[func] = name
|
|
end
|
|
end
|
|
-- label loaded Lua library packages
|
|
for name in pairs(luapacks) do
|
|
local pack = loaded[name]
|
|
if pack then package(_M, name, pack) end
|
|
end
|
|
-- label other loaded packages
|
|
for name, pack in pairs(loaded) do
|
|
if not luapacks[name] and type(pack) == "table" then
|
|
package(_M, name, pack)
|
|
end
|
|
end
|
|
end
|