tlibc/include/tlibc/errors.h

97 lines
2.7 KiB
C
Executable File

#pragma once
#include "std.h"
#include "string/str.h"
#include "collections/List.h"
#include "defer.h"
typedef struct ErrorCallPos {
i32 line;
cstr file;
cstr func;
} ErrorCallPos;
#define ErrorCallPos_here() (ErrorCallPos){\
.line = __LINE__,\
.file = __FILE__,\
.func = __func__\
}
typedef struct Error {
str msg;
bool is_msg_on_heap;
List(ErrorCallPos) call_stack;
} Error;
Error* Error_create(const char* msg, bool is_msg_on_heap, ErrorCallPos p);
void Error_free(Error* e);
void Error_addCallPos(Error* e, ErrorCallPos p);
str Error_toStr(Error* e);
void Error_printAndExit(Error* e) __attribute__ ((__noreturn__));
typedef struct Result_ {
Error* error;
union {
u64 u;
i64 i;
f32 f;
f64 d;
void* p;
};
} Result_;
#define Result(T) Result_
#define RESULT_ERROR(MSG, IS_MSG_ON_HEAP) (Result_){ .error = Error_create(MSG, IS_MSG_ON_HEAP, ErrorCallPos_here()) }
#define RESULT_ERROR_FMT(FORMAT, ARGS...) RESULT_ERROR(sprintf_malloc(4096, FORMAT ,##ARGS), true)
#define RESULT_ERROR_ERRNO() RESULT_ERROR(strerror(errno), false)
#define RESULT_VOID (Result_){ .error = NULL, .u = 0 }
#define RESULT_VALUE(FIELD, V) (Result_){ .error = NULL, .FIELD = V }
#define _rname(N) __r_##N
#define try(VAR, RESULT_FIELD, RSLT_CALL) _try(VAR, RESULT_FIELD, RSLT_CALL, __LINE__)
#define try_void(RSLT_CALL) _try_void(RSLT_CALL, __LINE__)
#define try_fatal(VAR, RESULT_FIELD, RSLT_CALL) _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, __LINE__)
#define try_fatal_void(RSLT_CALL) _try_fatal_void(RSLT_CALL, __LINE__)
#define _try(VAR, RESULT_FIELD, RSLT_CALL, N) \
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Return _rname(N);\
};\
VAR = _rname(N).RESULT_FIELD;
#define _try_void(RSLT_CALL, N) do {\
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Return _rname(N);\
};\
} while(0)
#define _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, N) \
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Error_printAndExit(_rname(N).error);\
};\
VAR = _rname(N).RESULT_FIELD;
#define _try_fatal_void(RSLT_CALL, N) do {\
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Error_printAndExit(_rname(N).error);\
};\
} while(0)
#define try_stderrcode(CALL) do {\
int r = CALL;\
if(r != 0){\
Return RESULT_ERROR(strerror(r), false);\
}\
} while(0)
#define try_assert(EXPR) if(!(EXPR)) { Return RESULT_ERROR((#EXPR), false); }