Skip to content

refactor TryCatch implementation for improved error handling #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 81 additions & 35 deletions game/packages/thlib-scripts/plus/Utility.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,51 +43,97 @@ function plus.Class(base)
return class
end

--! @brief 模拟TryCatch块
--! @param t 条件上下文
--!
--! 执行一个try..catch..finally块
--! 当try语句中出现错误时,将把错误信息发送到catch语句块,否则返回try函数结果
--! 当catch语句块被执行时,若发生错误将重新抛出,否则返回catch函数结果
--! finally块总是会保证在try或者catch后被执行
function plus.TryCatch(t)
assert(t.try ~= nil, "invalid argument.")
do
local type = type
local concat = table.concat
local unpack = table.unpack or unpack
local select = select
local assert = assert
local xpcall = xpcall
local traceback = debug.traceback
local error = error

local ret = {
xpcall(t.try, function(err)
return err .. "\n<=== inner traceback ===>\n" .. debug.traceback() .. "\n<=======================>"
end)
}
if ret[1] == true then
if t.finally then
t.finally()
---@class plus.TryCatch.Data
---@field try function @尝试执行
---@field catch function @错误捕获
---@field finally function @结束行为
local _ = {
try = function()
end,
---@param err string @错误信息
catch = function(err)
end,
finally = function()
end
return unpack(ret, 2)
else
local cret
}

if t.catch then
cret = {
xpcall(t.catch, function(err)
return "error in catch block: " .. err .. "\n<=== inner traceback ===>\n" .. debug.traceback() .. "\n<=======================>"
end, ret[2])
}
end
---基础错误回调
---@param err string @错误信息
---@return string
local function innerFunc(err)
return concat({
err or "unknown exception",
"<=== inner traceback ===>",
traceback(),
"<=======================>",
}, "\n")
end

if t.finally then
t.finally()
end
---捕获仍然错误回调
---@param err string @错误信息
---@return string
local function innerCatchFunc(err)
return concat({
"error in catch block: ",
err or "unknown exception",
"<=== inner traceback ===>",
traceback(),
"<=======================>"
}, "\n")
end

---捕获所有返回值
---@return number, table
local function packageResult(...)
return select("#", ...), { ... }
end

if cret == nil then
error("unhandled error: " .. ret[2])
---```
---模拟TryCatch块
---执行一个try..catch..finally块
---当try语句中出现错误时,将把错误信息发送到catch语句块,否则返回try函数结果
---当catch语句块被执行时,若发生错误将重新抛出,否则返回catch函数结果
---finally块总是会保证在try或者catch后被执行
---```
---@param data plus.TryCatch.Data @条件上下文
local function tryCatch(data, ...)
local try, catch, finally = data.try, data.catch, data.finally
assert(type(try) == "function", "invalid argument(try).")
assert(type(catch) == "function" or type(catch) == "nil", "invalid argument(catch).")
assert(type(finally) == "function" or type(finally) == "nil", "invalid argument(finally).")
local num, result = packageResult(xpcall(try, innerFunc, ...))
if result[1] then
if finally then
finally()
end
return unpack(result, 2, num)
else
if cret[1] == true then
return unpack(cret, 2)
if catch then
num, result = packageResult(xpcall(catch, innerCatchFunc, result[2]))
end
if finally then
finally()
end
if not (catch) then
error("unhandled error: " .. result[2], 2)
elseif result[1] then
return unpack(result, 2, num)
else
error(cret[2])
error(result[2], 2)
end
end
end
plus.TryCatch = tryCatch
end

local BIT_NUMBERS = {
Expand Down