error: refactor the whole thing

a.k.a. make it more complicated.
This commit is contained in:
anna 2021-07-12 03:06:51 +02:00
parent 1d7d2a7b55
commit ec5ed1e352
Signed by: fef
GPG key ID: EC22E476DC2D3D84
3 changed files with 59 additions and 37 deletions

View file

@ -6,6 +6,9 @@
/** /**
* Throw an error. If `err` is `nil`, the program halts. * Throw an error. If `err` is `nil`, the program halts.
* Functions accepting an `err` object must call either `yeet` or `neat`
* on the object exactly once, or the behavior is undefined.
* If a function yeets an error, its return value is undefined.
* *
* @param err: The error pointer passed to the callee * @param err: The error pointer passed to the callee
* @param number: An error number appropriate for the condition, * @param number: An error number appropriate for the condition,
@ -14,24 +17,47 @@
* the values to insert which will become the error message. * the values to insert which will become the error message.
*/ */
__attribute__(( __format__(printf, 3, 4) )) __attribute__(( __format__(printf, 3, 4) ))
void yeet(error *err, int number, const char *restrict fmt, ...); void yeet(error *err, u32 number, const char *restrict fmt, ...);
/** /**
* Functions accepting an error pointer must call this to indicate success. * Indicate an operation has completed successfully.
* Functions accepting an `error` pointer must call either `yeet` or `neat`,
* or the begavior is undefined.
*
* @param err: Error object
*/ */
#define neat(errptr) ({ \ void neat(error *err);
if (errptr) \
*(errptr) = nil; \
})
/** /**
* Functions passing an error pointer must call this to acknowledge an error. * Release any resources allocated for an error.
* This must always be called within the catch block of the outermost calling
* function, i.e. the one that declared the error variable (not the ones just
* accepting an error * argument and passing it through to further calls).
*
* Put another way, you probably need to call this if you had to put an `&`
* before the error variable for passing it into `catch`.
*
* @param err: Error object to destroy
*/ */
void catch(error *err); void errput(error *err);
/** Get the error number */ /**
* Execute the expression after this macro call if the error pointed to
* by `err` is an actual error, i.e. it has been `yeet`ed to.
* Resources for the error must be released using `nput`.
*/
#define catch(err) if ((err) != nil && (err)->_number != 0)
/**
* Get the error number.
* Must only be used within a catch block and before `errput` is called.
*/
#define errnum(err) ((err)->_number) #define errnum(err) ((err)->_number)
/** Get an optional error message, this may be `nil` */
/**
* Get an optional error message, this may be `nil`
* Must only be used within a catch block and before `errput` is called.
*/
#define errmsg(err) ((err)->_message) #define errmsg(err) ((err)->_message)
/* /*

View file

@ -53,7 +53,7 @@ struct _neo_error {
u32 _number; u32 _number;
u32 _flags; /* see src/error.c */ u32 _flags; /* see src/error.c */
}; };
typedef struct _neo_error *error; typedef struct _neo_error error;
/* /*
* This file is part of libneo. * This file is part of libneo.

View file

@ -11,37 +11,26 @@
#include "neo/_nref.h" #include "neo/_nref.h"
#include "neo/_stddef.h" #include "neo/_stddef.h"
#include "neo/_string.h" #include "neo/_string.h"
#include "neo/_toolchain.h"
#include "neo/_types.h" #include "neo/_types.h"
/* flags for the error structure */ void yeet(error *err, u32 number, const char *restrict fmt, ...)
#define NEO_ERR_CAUGHT (1 << 0)
/* TODO: we need one of these for every thread */
static struct _neo_error _neo_error_instance = {
._number = 0,
._message = nil,
._flags = NEO_ERR_CAUGHT,
};
void yeet(error *err, int number, const char *restrict fmt, ...)
{ {
va_list vargs; va_list vargs;
usize msg_capacity = 64; usize msg_capacity = 64;
char *msg = nil; char *msg = nil;
int printf_ret; int vsnprintf_ret;
if (fmt != nil) { if (fmt != nil) {
do { do {
msg = nalloc(msg_capacity, nil); msg = nalloc(msg_capacity, nil);
va_start(vargs, fmt); va_start(vargs, fmt);
printf_ret = vsnprintf(msg, msg_capacity, fmt, vargs); vsnprintf_ret = vsnprintf(msg, msg_capacity, fmt, vargs);
va_end(vargs); va_end(vargs);
if (printf_ret > 0) { if (vsnprintf_ret > 0) {
msg_capacity += printf_ret; msg_capacity += vsnprintf_ret;
nfree(msg); nfree(msg);
msg = nil; msg = nil;
} else if (printf_ret < 0) { } else if (vsnprintf_ret < 0) {
write(1, "Runtime error\n", 14); write(1, "Runtime error\n", 14);
exit(1); exit(1);
} }
@ -55,18 +44,25 @@ void yeet(error *err, int number, const char *restrict fmt, ...)
exit(number); exit(number);
} }
*err = &_neo_error_instance; err->_number = number;
(*err)->_number = number; err->_message = nstr(msg, nil);
(*err)->_message = nstr(msg, nil);
(*err)->_flags &= ~NEO_ERR_CAUGHT;
} }
void catch(error *err) void neat(error *err)
{ {
if ((*err)->_message) if (err) {
nput((*err)->_message); err->_number = 0;
(*err)->_flags |= NEO_ERR_CAUGHT; err->_message = nil;
*err = nil; }
}
void errput(error *err)
{
if (err != nil) {
if (err->_message != nil)
nput(err->_message);
err->_number = 0xffffffff;
}
} }
/* /*