Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://anggtwu.net/LUA/XPCall1.lua.html
--   http://anggtwu.net/LUA/XPCall1.lua
--          (find-angg "LUA/XPCall1.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2023nov12
--
-- This class implements a modular wrapper around pcall and xpcall
-- that can be used in many ways. For example:
--
--   1) as an unwind/protect that sets global variables temporarily
--   2) as an xpcall that displays the error and a pretraceback
--   3) as an xpcall that returns the error and a pretraceback
--
-- The methods ":stb0()" and ":stb()" save a pretraceback in the
-- global variable ptb, but they only do that if the current value of
-- ptb is nil. (Explain clobbering)

-- ... as an unwind/protect. The xpcall methods save a
-- pretraceback that can be used for post-mortem debugging.
--
-- (defun xp () (interactive) (find-angg "LUA/XPCall1.lua"))
-- (defun pc () (interactive) (find-angg "LUA/PCall1.lua"))

-- This is more powerful than:
--   (find-angg "LUA/PCall1.lua")
-- but the classes here and there are disjoint and the
-- two files can be loaded at the same time.
-- Some of the methods in the XPCall class use pretracebacks:
--   (find-angg "LUA/PrintFunction1.lua" "PreTraceback")
--
-- See:
--   (find-angg "LUA/lua50init.lua" "pack-and-unpack")
--   (find-emlua "Repl1.lua" "WithFakePrint")
-- Used by:
--   (find-angg "LUA/Repl3.lua")

-- «.XPCall»		(to "XPCall")
-- «.XPCall-tests»	(to "XPCall-tests")
-- «.XPCall-tests-x»	(to "XPCall-tests-x")

require "PreTraceback1"    -- (find-angg "LUA/PreTraceback1.lua")




-- __  ______   ____      _ _ 
-- \ \/ /  _ \ / ___|__ _| | |
--  \  /| |_) | |   / _` | | |
--  /  \|  __/| |__| (_| | | |
-- /_/\_\_|    \____\__,_|_|_|
--                            
-- «XPCall»  (to ".XPCall")

XPCall = Class {
  type    = "XPCall",
  __tostring = function (pc) return mytostringv(pc) end,
  __index = {
    m = function (pc,f,...)
        if type(f) == "string" then f = pc[f] end
        if f then f(pc,...) end
        return pc
      end,
    --
    a = function (pc) return pc:m("before") end,
    b = function (pc,...)
        local fargs = pack(...)
        local g     = function () return pc.f(unpack(fargs)) end
        pc.presults = pack(pcall(g))
        return pc
      end,
    c = function (pc) return pc:m("after") end,
    --
    ok   = function (pc) return pc.presults[1] end,
    e    = function (pc) return pc.presults[2] end,
    r    = function (pc) return unpack(pc.presults, 2, pc.presults.n) end,
    re   = function (pc) return false,pc:e() end,
    rr   = function (pc) return true,pc:r() end,
    rre  = function (pc) if pc:ok() then return pc:rr() else return pc:re() end end,
    okr  = function (pc) if pc:ok() then return pc:r() end end,
    --
    pcall  = function (pc,...) return pc:a():b(...):c():rre() end,
    pcall0 = function (pc,...) return pc:a():b(...):c():okr() end,
    --
    eh = function (...) return false end,
    xb = function (pc, ...)
        local fargs = pack(...)
        local g   = function () return pc.f(unpack(fargs)) end
        local geh = function (...)
            pc.gehargs = pack(...)
            pc.errmsg = ...
            pc.traceback = debug.traceback()
            pc.pretraceback = PreTraceback.new(true,true)
            return pc:eh()
          end
        pc.presults = pack(xpcall(g, geh))
        return pc
      end,
    ptb00 = function (pc,a,b) return pc.pretraceback:tostring(a, b) end,
    ptb0  = function (pc,a,b) return pc:ptb00(a or #pc.pretraceback, b or 5) end,
    ptb   = function (pc,a,b) return pc:ptb0(a,b).."\n"..pc.errmsg end,
    stb0  = function (pc) ptb = ptb or pc.pretraceback; return pc end,
    stb   = function (pc) if not pc:ok() then pc:stb0() end; return pc end,
    xpe   = function (pc) if not pc:ok() then print(pc:ptb()) end; return pc end,
    --
    xpcall3 = function (pc,...) return pc:a():xb(...):c() end,
    xpcall5 = function (pc,...) return pc:a():xb(...):c():xpe():okr() end,
    xpcall6 = function (pc,...) return pc:a():xb(...):c():stb():xpe():okr() end,
    --
    clr = function (pc)
        pc = copy(pc)
        pc.traceback,pc.pretraceback = nil,nil
        return pc
      end,
  },
}

-- «XPCall-tests-x»  (to ".XPCall-tests-x")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "XPCall1.lua"
p = XPCall {
  f = function (a,b) print(a,b); return a+b,a*b end,
}
  p:xpcall3(2,3)
  p:xpcall5(2,3)
= p:xpcall5(2,3)
= p:clr()
= ptb
  p:xpcall3(2,false)
  p:xpcall5(2,false)
  p:xpcall6(2,false)
= ptb
= ptb[2]
= ptb[2].locals
= ptb[2].locals:inames()


= p.pretraceback
= p:ptb()
= p:ptb(nil, 0)
= p
= p:clr()


= p:xpcall3(2,false)
= p:xpcall4(2,false)

--]]



-- «XPCall-tests»  (to ".XPCall-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "XPCall1.lua"
p = XPCall {
  before = function ()    print "(before)" end,
  f      = function (a,b) print(a,b); return a+b,a*b end,
  after  = function ()    print "(after)" end,
}

= p:pcall (2,3)
= p:pcall0(2,3)
= p
= p:ok()
= p:r()
= p:rr()
= p:rre()
= p:okr()

= p:pcall(2,false)
= p
= p:e()
= p:re()
= p:rre()
= p:okr()

--]]


-- Local Variables:
-- coding:  utf-8-unix
-- End: