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) --]]