mirror of https://github.com/kepler155c/opus
105 lines
2.3 KiB
Lua
105 lines
2.3 KiB
Lua
-- stack trace by SquidDev (MIT License)
|
|
-- https://raw.githubusercontent.com/SquidDev-CC/mbs/master/lib/stack_trace.lua
|
|
|
|
local type = type
|
|
local debug_traceback = type(debug) == "table" and type(debug.traceback) == "function" and debug.traceback
|
|
|
|
local function traceback(x)
|
|
-- Attempt to detect error() and error("xyz", 0).
|
|
-- This probably means they're erroring the program intentionally and so we
|
|
-- shouldn't display anything.
|
|
if x == nil or (type(x) == "string" and not x:find(":%d+:")) then
|
|
return x
|
|
end
|
|
|
|
if x and x:match(':%d+: 0$') then
|
|
return x
|
|
end
|
|
|
|
if debug_traceback then
|
|
-- The parens are important, as they prevent a tail call occuring, meaning
|
|
-- the stack level is preserved. This ensures the code behaves identically
|
|
-- on LuaJ and PUC Lua.
|
|
return (debug_traceback(tostring(x), 2))
|
|
else
|
|
local level = 3
|
|
local out = { tostring(x), "stack traceback:" }
|
|
while true do
|
|
local _, msg = pcall(error, "", level)
|
|
if msg == "" then break end
|
|
|
|
out[#out + 1] = " " .. msg
|
|
level = level + 1
|
|
end
|
|
|
|
return table.concat(out, "\n")
|
|
end
|
|
end
|
|
|
|
local function trim_traceback(stack)
|
|
local trace = { }
|
|
local filters = {
|
|
"%[C%]: in function 'xpcall'",
|
|
"(...tail calls...)",
|
|
"xpcall: $",
|
|
"trace.lua:%d+:",
|
|
"stack traceback:",
|
|
}
|
|
|
|
for line in stack:gmatch("([^\n]*)\n?") do table.insert(trace, line) end
|
|
|
|
local err = { }
|
|
while true do
|
|
local line = table.remove(trace, 1)
|
|
if not line or line == 'stack traceback:' then
|
|
break
|
|
end
|
|
table.insert(err, line)
|
|
end
|
|
err = table.concat(err, '\n')
|
|
|
|
local function matchesFilter(line)
|
|
for _, filter in pairs(filters) do
|
|
if line:match(filter) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
local t = { }
|
|
for _, line in pairs(trace) do
|
|
if not matchesFilter(line) then
|
|
line = line:gsub("in function", "in"):gsub('%w+/', '')
|
|
table.insert(t, line)
|
|
end
|
|
end
|
|
|
|
return err, t
|
|
end
|
|
|
|
return function (fn, ...)
|
|
local args = { ... }
|
|
local res = table.pack(xpcall(function()
|
|
return fn(table.unpack(args))
|
|
end, traceback))
|
|
|
|
if not res[1] and res[2] ~= nil then
|
|
local err, trace = trim_traceback(res[2])
|
|
|
|
if err:match(':%d+: 0$') then
|
|
return true
|
|
end
|
|
|
|
if #trace > 0 then
|
|
_G._syslog('\n' .. err .. '\n' .. 'stack traceback:')
|
|
for _, v in ipairs(trace) do
|
|
_G._syslog(v)
|
|
end
|
|
end
|
|
|
|
return res[1], err, trace
|
|
end
|
|
|
|
return table.unpack(res, 1, res.n)
|
|
end
|