1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-25 22:53:22 +00:00

Allow coroutine managers to integrate with error reporting

The original runtime error reporting PR[^1] added a "cc.exception"
module, which allowed coroutine managers (such as parallel) to throw
rich errors, detailing the original context where the error was thrown.

Unfortunately, the change to parallel broke some programs (>_>, don't do
string pattern matching on your errors!), and so had to be reverted,
along with the cc.exception module.

As a minimal replacement for this, we add support for user-thrown
exceptions within our internal code. If an error object "looks" like an
exception ("exception" __name, and a message and thread field), then we
use that as our error information instead.

This is currently undocumented (at least in user-facing documentation),
mostly because I couldn't figure out where to put it - the interface
should remain stable.

[^1]: https://github.com/cc-tweaked/CC-Tweaked/pull/1320
This commit is contained in:
Jonathan Coates 2024-03-12 20:43:26 +00:00
parent b7df91349a
commit 7ee821e9c9
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06

View File

@ -26,13 +26,51 @@ local function find_frame(thread, file, line)
end
end
--[[- Check whether this error is an exception.
Currently we don't provide a stable API for throwing (and propogating) rich
errors, like those supported by this module. In lieu of that, we describe the
exception protocol, which may be used by user-written coroutine managers to
throw exceptions which are pretty-printed by the shell:
An exception is any table with:
- The `"exception"` type
- A string `message` field,
- And a coroutine `thread` fields.
To throw such an exception, the inner loop of your coroutine manager may look
something like this:
```lua
local ok, result = coroutine.resume(co, table.unpack(event, 1, event.n))
if not ok then
-- Rethrow non-string errors directly
if type(result) ~= "string" then error(result, 0) end
-- Otherwise, wrap it into an exception.
error(setmetatable({ message = result, thread = co }, {
__name = "exception",
__tostring = function(self) return self.message end,
}))
end
```
@param exn Some error object
@treturn boolean Whether this error is an exception.
]]
local function is_exception(exn)
if type(exn) ~= "table" then return false end
local mt = getmetatable(exn)
return mt and mt.__name == "exception" and type(rawget(exn, "message")) == "string" and type(rawget(exn, "thread")) == "thread"
end
--[[- Attempt to call the provided function `func` with the provided arguments.
@tparam function func The function to call.
@param ... Arguments to this function.
@treturn[1] true If the function ran successfully.
@return[1] ... The return values of the function.
@return[1] ... The return values of the function.
@treturn[2] false If the function failed.
@return[2] The error message
@ -51,8 +89,14 @@ local function try(func, ...)
end
end
if not result[1] then return false, result[2], co end
return table.unpack(result, 1, result.n)
if result[1] then
return table.unpack(result, 1, result.n)
elseif is_exception(result[2]) then
local exn = result[2]
return false, rawget(exn, "message"), rawget(exn, "thread")
else
return false, result[2], co
end
end
--[[- Report additional context about an error.