102 lines
3.0 KiB
C
Executable File
102 lines
3.0 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_;
|
|
|
|
///Use this macro only to specify function return type.
|
|
/// To declare variable, use ResultVar().
|
|
/// Warning can be suppressed by IGNORE_RESULT
|
|
#define Result(T) Result_ ATTRIBUTE_WARN_UNUSED_RESULT
|
|
#define ResultVar(T) Result_
|
|
///USAGE: IGNORE_RESULT trySomething();
|
|
#define IGNORE_RESULT Result_ __ignored_##__LINE__ ATTRIBUTE_UNUSED =
|
|
|
|
#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(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(("try_assert(" #EXPR ")"), false); }
|