|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://angg.twu.net/LUA/GetInfo.lua.html
-- http://angg.twu.net/LUA/GetInfo.lua
-- (find-angg "LUA/GetInfo.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2021sep25
-- Introduction
-- ============
-- For many years I thought that debug.getinfo was horribly hard to
-- use, because we have to make the right adjustments to the "lvl"
-- parameter in each call to it... then in 2021 I realized that we can
-- use it in this way: we first run all the "debug.getinfo"s and
-- "debug.getlocal"s that we can, to get all the data in the call
-- stack, and we put all that data in an array of tables; then we can
-- use that data to inspect it or to produce tracebacks. Calls to
-- "debug.setlocal" still need a well-adjusted "lvl", but I use that
-- very rarely.
--
-- How to use this: a call to GetInfos.new() collects all data from
-- the call stack and returns a table with otype "GetInfos" of tables
-- with otype "GetInfo". See the tests.
--
-- TODO: the version in the init file is more recent than this - update.
-- «.dependencies» (to "dependencies")
-- «.GetInfo» (to "GetInfo")
-- «.GetInfo-tests» (to "GetInfo-tests")
-- «.GetInfos» (to "GetInfos")
-- «.old-tests» (to "old-tests")
-- «dependencies» (to ".dependencies")
-- (find-angg "emacs-lua/")
-- (find-angg "emacs-lua/EdrxRepl.lua")
-- (find-angg "emacs-lua/DFS.lua")
-- Path.prepend("path", "~/emacs-lua/?.lua")
-- require "EdrxRepl"
-- require "DFS"
-- «GetInfo» (to ".GetInfo")
-- Also here: (find-angg "LUA/lua50init.lua" "GetInfo")
-- (find-lua51manual "#5.9" "The Debug Library")
-- (find-lua51manual "#lua_getinfo")
-- (find-lua51manual "#lua_getlocal")
-- (find-lua51manual "#pdf-debug.getlocal")
-- (find-lua51manual "#pdf-debug.setlocal")
-- (find-es "lua5" "debug.getinfo")
-- 'n': fills in the field name and namewhat;
-- 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
-- 'l': fills in the field currentline;
-- 'u': fills in the field nups;
-- 'f': pushes onto the stack the function that is running at the given level;
-- 'L': pushes onto the stack a table whose indices are the numbers of the lines...
--
GetInfo = Class {
type = "GetInfo",
what = "nSluf",
new = function () return GetInfo({}) end,
--
level_nil = function ()
for i=0,1000 do if debug.getinfo(i, "f") == nil then return i end end
end,
level_f = function (i, j, f)
for k=i,j do if debug.getinfo(i, "f").func == f then return k end end
end,
atlevel = function (lvl, getvalues)
local gi = debug.getinfo(lvl, GetInfo.what)
if not gi then return end
if getvalues then gi.values = {} end
for i=1,1000 do
local name,value = debug.getlocal(lvl, i)
if not name then break end
gi[i] = name
if getvalues then gi.values[i] = value end
end
return GetInfo(gi)
end,
__tostring = function (gi)
return gi:funname().." :: "..gi:vars()
end,
__index = {
funname = function (gi) return gi.name or "(noname)" end,
vars = function (gi)
return table.concat(gi, " ")
end,
--
-- gi:varns("nameoffirstarg") == 1
-- gi:v ("nameoffirstarg") == firstarg
-- gi:vs() .nameoffirstarg == firstarg
-- gi:vs() .badname == nil
-- gi:v ("badname") == error
varns = function (gi)
local namens = {}
for i,name in ipairs(gi) do namens[name] = i end
return namens
end,
vs = function (gi)
local values = {}
for i,name in ipairs(gi) do values[name] = gi.values[i] end
return values
end,
v = function (gi, name)
local n = gi:varns()[name] or error("Bad var name: "..tostring(name))
return gi.values[n]
end,
},
}
-- «GetInfo-tests» (to ".GetInfo-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "GetInfo.lua"
f = function (a1,a2) local l1,l2; ff(41,42) end
ff = function (aa1,aa2,...) local ll1,ll2; fff(411,422) end
fff = function (aaa1,aaa2)
print(GetInfo.atlevel(0):vars()); -- ?
print(GetInfo.atlevel(1):vars()); -- GetInfo.atlevel
print(GetInfo.atlevel(2):vars()); -- fff
print(GetInfo.atlevel(3):vars()); -- ff
print(GetInfo.atlevel(4):vars()); -- f
PP(GetInfo.atlevel(3))
PP(GetInfo.atlevel(3, "getvalues"))
gis = GetInfos:new("getvalues")
end
f()
= gis[0]
= gis[2]
= gis
= gis:firstsuch(function (gi) return gi.name == "fff" end)
gis:setbase (function (gi) return gi.name == "fff" end)
= gis:tostring(gis.base+2, gis.base)
= gis:tostring(gis.base, gis.base+2)
= gis.base
= gis[gis.base]
PP(gis[gis.base])
PP(gis[gis.base]:varns())
= gis[gis.base]:v("aaa1")
= gis[gis.base]:vs().aaa1
= gis[gis.base]:vs().badname
= gis[gis.base]:v("badname")
_fff = gis[gis.base]
_fff_v = gis[gis.base]:vs()
= _fff
= _fff_v.aaa1
--]]
-- «GetInfos» (to ".GetInfos")
-- Also here: (find-angg "LUA/lua50init.lua" "GetInfos")
--
GetInfos = Class {
type = "GetInfos",
new = function (getvalues) return GetInfos({}):getinfos(getvalues) end,
newv = function () return GetInfos().new("getvalues") end,
__tostring = function (gis) return gis:tostring() end,
__index = {
getinfos = function (gis, getvalues)
gis.infos = {}
for i=0,1000 do
gis[i] = GetInfo.atlevel(i, getvalues)
if not gis[i] then return gis end
end
end,
tostring = function (gis, a, b, dir)
a,b = (a or #gis),(b or 0)
dir = dir or (a <= b and 1 or -1)
local f = function (i) return format("%d -> %s", i, tostring(gis[i])) end
return mapconcat(f, seq(a, b, dir), "\n")
end,
firstsuch = function (gis, f)
for i=0,#gis do
if f(gis[i], i) then return i end
end
end,
setbase = function (gis, f)
local z = gis:firstsuch(f)
if not z then error("setbase: not found") end
gis.base = z
return gis
end,
},
}
-- «GetInfo-tests» (to ".GetInfo-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "GetInfo.lua"
f = function (a1,a2) local l1,l2; ff(41,42) end
ff = function (aa1,aa2,...) local ll1,ll2; fff(411,422) end
fff = function (aaa1,aaa2)
gis = GetInfos:new("getvalues")
end
f()
= gis
gis:setbase (function (gi) return gi.name == "fff" end)
= gis:tostring(gis.base+2, gis.base)
= gis:tostring(gis.base, gis.base+2)
_fff = gis[gis.base]
_fff_v = gis[gis.base]:vs()
= _fff
= _fff_v.aaa1
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "GetInfo.lua"
f = function (a1,a2) local l1,l2; ff(41,42) end
ff = function (aa1,aa2,...) local ll1,ll2; fff(411,422) end
fff = function (aaa1,aaa2)
print(GetInfo.atlevel(0):vars()); -- ?
print(GetInfo.atlevel(1):vars()); -- GetInfo.atlevel
print(GetInfo.atlevel(2):vars()); -- fff
print(GetInfo.atlevel(3):vars()); -- ff
print(GetInfo.atlevel(4):vars()); -- f
PP(GetInfo.atlevel(3))
PP(GetInfo.atlevel(3, "getvalues"))
gis = GetInfos:new("getvalues")
end
f()
= gis[0]
= gis[2]
= gis
= gis:firstsuch(function (gi) return gi.name == "fff" end)
gis:setbase (function (gi) return gi.name == "fff" end)
= gis:tostring(gis.base+2, gis.base)
= gis:tostring(gis.base, gis.base+2)
= gis.base
= gis[gis.base]
PP(gis[gis.base])
PP(gis[gis.base]:varns())
= gis[gis.base]:v("aaa1")
= gis[gis.base]:vs().aaa1
= gis[gis.base]:vs().badname
= gis[gis.base]:v("badname")
_fff = gis[gis.base]
_fff_v = gis[gis.base]:vs()
= _fff
= _fff_v.aaa1
--]]
-- «old-tests» (to ".old-tests")
f = function (a, b)
local c, d
g(5, 6)
print("f ok")
end
g = function (aa, bb, ...)
local cc, dd
h(5, 6)
print("g ok")
end
h = function ()
REPL = EdrxRepl.new()
REPL:repl() -- enter the repl
end
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "GetInfo.lua"
f(10, 20)
gis = GetInfos.new()
PPV(gis.infos[4])
PPV(gis.infos[4]:vars())
for i,gi in gis:gen() do print(i, gi:vars()) end
for i,gi in gis:gen() do PP(i, gi.name, gi.what, gi.namewhat) end
for i,gi in gis:gen() do PP(i, gi.short_src, gi.source) end
PPV(gis.infos[5])
d = DFS.new():nameluatables():nameallfunctions()
for i,gi in gis:gen() do PP(i, gi.name, gi.what, gi.namewhat) end
for i,gi in gis:gen() do PP(i, d:getname(gi.func), gi:vars()) end
gis = gis:after(EdrxRepl.__index.repl)
for i,gi in gis:gen() do PP(i, gi.name, gi.what, gi.namewhat) end
for i,gi in gis:gen() do PP(i, d:getname(gi.func), gi:vars()) end
level_nil = GetInfo.level_nil()
level_repl = GetInfo.level_f(0, level_nil - 1, EdrxRepl.__index.repl)
= level_nil, level_repl
--> /home/edrx/emacs-lua/EdrxRepl.lua:124: attempt to call method 'outsuccess' (a nil value)
--]]