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.
* 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 number: An error number appropriate for the condition,
@ -14,24 +17,47 @@
* the values to insert which will become the error message.
*/
__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) ({ \
if (errptr) \
*(errptr) = nil; \
})
void neat(error *err);
/**
* 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)
/** 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)
/*

View file

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

View file

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