Structured errors: the Err class, tag taxonomy, errno translation.
The structured-error convention: tag + message + data over the untyped C error prim. See the header comment for the tag vocabulary and the guard/match idiom.
ErrStructured error value: tag symbol + message string + data alist.
The tag vocabulary is blessed but open: ‘type ‘value ‘index ‘io ‘state ‘user (see contributing.md). Raise with (Err raise …) or (error (Err make …)); discriminate in a guard with (Err tag e) – total over all error values, legacy bare strings answer ‘user.
tagMember: data carried by a Err instance.
msgMember: data carried by a Err instance.
dataMember: data carried by a Err instance.
(tag? k)Test this error’s tag.
Instance method: called on a Err instance.
Parameters:
SYMBOL — Tag to test againstReturns: BOOL — True when the error’s tag is k
Examples:
((Err make 'io "x" ()) tag? 'io) => #t(%repr)Inspection form: #
Instance method: called on a Err instance.
Returns: STRING — The repr string
%engine-typeMember: data carried by a Err instance.
(Err %str a)Lift an ERR slot to a real STRING.
An ERR’s code and subject are static-string ATOMS – the engine repoints their string pointers per raise, which is what keeps a raise allocation-free – so they carry no STRING type and Str8 refuses them. Appending to “” copies the bytes out, the same lift the printer always used on a raw error atom.
Parameters:
ANY — An ERR slot: a static-string atomReturns: STRING — The slot’s bytes
(Err make tag msg data)Construct an Err value.
Parameters:
SYMBOL — Error tag, e.g. ‘ioSTRING — Human-readable messageALIST — Context alist (or ())Returns: OBJECT — The Err instance
Examples:
(Err make 'value "bad" ()) => #<err:value bad>(Err raise tag msg data)Construct an Err and raise it: (error (Err make tag msg data) “tag: msg”).
Parameters:
SYMBOL — Error tag, e.g. ‘ioSTRING — Human-readable messageALIST — Context alist (or ())Returns: ANY — Does not return
(Err err? v)Test whether v is an Err instance.
Parameters:
ANY — Any valueReturns: BOOL — True for Err instances only
Examples:
(Err err? 42) => #f(Err tag v)The tag of any error value – TOTAL, so one match discriminates every error the system can raise: an Err answers its own tag, an engine-raised ERR answers ‘engine, and anything else (a legacy bare string) answers ‘user.
Parameters:
ANY — Any error valueReturns: SYMBOL — The Err’s tag, ‘engine, or ‘user
Examples:
(Err tag "bare string") => 'user
(Err tag (Err make 'index "oops" ())) => 'index
(guard (e (Err tag e)) (no-such-binding)) => 'engine(Err engine? v)Test whether v is an ERR – the value the ENGINE raises (an unbound symbol, a failed include), as opposed to an Err the library raised or a bare string.
Parameters:
ANY — Any error valueReturns: BOOL — True for engine-raised errors only
Examples:
(guard (e (Err engine? e)) (no-such-binding)) => #t(Err code-of v)The raise site’s message literal, as a STRING – “Unbound SYMBOL”, “include: cannot open”. The engine’s whole vocabulary is five of these; a lang keys its own wording off them.
Parameters:
ANY — An ERR valueReturns: STRING — The code, or “” for a non-ERR
Examples:
(guard (e (Err code-of e)) (no-such-binding)) => "Unbound SYMBOL"(Err subject-of v)What the raise was about – the unbound symbol’s name, the path that would not open – as a STRING, separate from the code rather than quoted into it. Empty when the raise named no subject.
Parameters:
ANY — An ERR valueReturns: STRING — The subject, or “”
Examples:
(guard (e (Err subject-of e)) (no-such-binding)) => "no-such-binding"(Err stop? v)Test whether v is the interrupt error – ctrl-c, which the engine raises with the code STOP.
Total, and deliberately accepts both spellings: an engine raise arrives as an ERR whose code is STOP, while a bare (error “STOP”) arrives as the string. The REPL’s ctrl-c path tests this rather than lifting bytes out of the value – reading an error’s memory as a symbol name is what printed garbage for every structured error in #46, and an ERR is atom? too, so the same lift would have failed the same way.
Parameters:
ANY — Any error valueReturns: BOOL — True for an interrupt, however it was delivered
Examples:
(guard (e (Err stop? e)) (error "STOP")) => #t(Err errno-of r)Recover the CURRENT errno after a failed libc/syscall call. The syscall prim routes through libc on both OSes, returning a bare -1 with the reason parked behind the per-thread errno location – __error() on Darwin, __errno_location() on Linux; this derefs it (lazily resolving the symbol once). Falls back to (- 0 r) on a libc without the symbol. Fetch BEFORE any intervening call (a close on the error path clobbers errno).
Parameters:
INT — A failed call’s raw return value (negative)Returns: INT — The positive errno
(Err from-errno n op . detail)Translate an errno into a tag ‘io Err. The message is strerror-style prefixed with op; data carries ((errno . N) (sym . ENOENT-style-symbol) (op . OP) (detail . D)). Numbers are per-OS (picked at load via os-darwin?); unknown numbers get sym ‘unknown.
Parameters:
INT — errno, positive or the syscall layer’s negative -errnoSYMBOL — The operation, e.g. ‘openANY — Optional context value, e.g. the pathReturns: OBJECT — The Err instance
Examples:
((Err from-errno 2 'open "/nope") msg) => "open: No such file or directory"
(Assoc get 'errno ((Err from-errno -2 'open ()) data)) => 2