Allow exiting on error from the creation of an error sink

This commit is contained in:
doylet 2024-02-29 21:30:06 +11:00
parent 963d911d9d
commit 7f2a0152e0
6 changed files with 55 additions and 29 deletions

View File

@ -13,7 +13,7 @@ pushd Build
REM O2 Optimisation Level 2 REM O2 Optimisation Level 2
REM Oi Use CPU Intrinsics REM Oi Use CPU Intrinsics
REM Z7 Combine multi-debug files to one debug file REM Z7 Combine multi-debug files to one debug file
set common_flags=-D DQN_UNIT_TESTS_WITH_MAIN -D DQN_UNIT_TESTS_WITH_KECCAK -D DQN_IMPLEMENTATION -D DQN_WITH_JSON -D DQN_USE_STD_PRINTF /Tp %script_dir%\dqn.h set common_flags=-D DQN_UNIT_TESTS_WITH_MAIN -D DQN_UNIT_TESTS_WITH_KECCAK -D DQN_IMPLEMENTATION -D DQN_USE_STD_PRINTF /Tp %script_dir%\dqn.h
set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo

View File

@ -407,13 +407,14 @@ DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN
} }
// NOTE: [$ERRS] Dqn_ErrorSink ///////////////////////////////////////////////////////////////////// // NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
DQN_API Dqn_ErrorSink *Dqn_ErrorSink_Begin() DQN_API Dqn_ErrorSink *Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode mode)
{ {
Dqn_ThreadContext *thread_context = Dqn_ThreadContext_Get(); Dqn_ThreadContext *thread_context = Dqn_ThreadContext_Get();
Dqn_ErrorSink *result = &thread_context->error_sink; Dqn_ErrorSink *result = &thread_context->error_sink;
Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes); Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes);
node->next = result->stack; node->next = result->stack;
node->arena_pos = Dqn_Arena_Pos(result->arena); node->arena_pos = Dqn_Arena_Pos(result->arena);
node->mode = mode;
result->stack = node; result->stack = node;
return result; return result;
} }
@ -438,14 +439,13 @@ DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End(Dqn_Arena *arena, Dqn_ErrorSink *err
return result; return result;
} }
DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args) DQN_API bool Dqn_ErrorSink_EndAndLogError(Dqn_ErrorSink *error, Dqn_Str8 error_msg)
{ {
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.arena, error); Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.arena, error);
if (node.error) { if (node.error) {
Dqn_Str8 line = Dqn_Str8_InitFV(scratch.arena, fmt, args); if (Dqn_Str8_HasData(error_msg)) {
if (Dqn_Str8_HasData(line)) { Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s. %.*s", DQN_STR_FMT(error_msg), DQN_STR_FMT(node.msg));
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s. %.*s", DQN_STR_FMT(line), DQN_STR_FMT(node.msg));
} else { } else {
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s", DQN_STR_FMT(node.msg)); Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s", DQN_STR_FMT(node.msg));
} }
@ -454,11 +454,21 @@ DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV(Dqn_ErrorSink *error, DQN_FMT_ATTRIB
return result; return result;
} }
DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
return result;
}
DQN_API bool Dqn_ErrorSink_EndAndLogErrorF(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...) DQN_API bool Dqn_ErrorSink_EndAndLogErrorF(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
bool result = Dqn_ErrorSink_EndAndLogErrorFV(error, fmt, args); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
va_end(args); va_end(args);
return result; return result;
} }
@ -479,15 +489,18 @@ DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF(Dqn_ErrorSink *error, uint32_t exi
DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, va_list args) DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, va_list args)
{ {
if (error) { if (!error)
Dqn_ErrorSinkNode *node = error->stack; return;
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
if (!node->error) { // NOTE: Only preserve the first error Dqn_ErrorSinkNode *node = error->stack;
node->msg = Dqn_Str8_InitFV(error->arena, fmt, args); DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
node->error_code = error_code; if (!node->error) { // NOTE: Only preserve the first error
node->error = true; node->msg = Dqn_Str8_InitFV(error->arena, fmt, args);
node->call_site = Dqn_ThreadContext_Get()->call_site; node->error_code = error_code;
} node->error = true;
node->call_site = Dqn_ThreadContext_Get()->call_site;
if (node->mode == Dqn_ErrorSinkMode_ExitOnError)
Dqn_ErrorSink_EndAndExitIfErrorF(error, error_code, "Fatal error encountered: (%u) %.*s", error_code, DQN_STR_FMT(node->msg));
} }
} }

View File

@ -386,8 +386,15 @@ struct Dqn_CallSite
#define DQN_CALL_SITE Dqn_CallSite{DQN_STR8(__FILE__), DQN_STR8(__func__), __LINE__} #define DQN_CALL_SITE Dqn_CallSite{DQN_STR8(__FILE__), DQN_STR8(__func__), __LINE__}
// NOTE: [$ERRS] Dqn_ErrorSink ///////////////////////////////////////////////////////////////////// // NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
enum Dqn_ErrorSinkMode
{
Dqn_ErrorSinkMode_Nil,
Dqn_ErrorSinkMode_ExitOnError,
};
struct Dqn_ErrorSinkNode struct Dqn_ErrorSinkNode
{ {
Dqn_ErrorSinkMode mode;
bool error; bool error;
int32_t error_code; int32_t error_code;
Dqn_Str8 msg; Dqn_Str8 msg;
@ -613,8 +620,9 @@ DQN_API void Dqn_Log_FVCallSite
DQN_API void Dqn_Log_FCallSite (Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API void Dqn_Log_FCallSite (Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...);
// NOTE: [$ERRS] Dqn_ErrorSink ///////////////////////////////////////////////////////////////////// // NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
DQN_API Dqn_ErrorSink * Dqn_ErrorSink_Begin (); DQN_API Dqn_ErrorSink * Dqn_ErrorSink_Begin (Dqn_ErrorSinkMode mode);
DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End (Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End (Dqn_Arena *arena, Dqn_ErrorSink *error);
DQN_API bool Dqn_ErrorSink_EndAndLogError (Dqn_ErrorSink *error, Dqn_Str8 error_msg);
DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV (Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args); DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV (Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API bool Dqn_ErrorSink_EndAndLogErrorF (Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API bool Dqn_ErrorSink_EndAndLogErrorF (Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF (Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, ...); DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF (Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, ...);

View File

@ -82,8 +82,8 @@ static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error)
Dqn_CGenTable *table = MD_PushArray(cgen->arena, Dqn_CGenTable, 1); Dqn_CGenTable *table = MD_PushArray(cgen->arena, Dqn_CGenTable, 1);
table->node = node; table->node = node;
table->name = table_tag->first_child->first_child->string; table->name = Dqn_CGen_MDToDqnStr8(table_tag->first_child->first_child->string);
MD_MapInsert(cgen->arena, &cgen->table_map, MD_MapKeyStr(table->name), table); MD_MapInsert(cgen->arena, &cgen->table_map, MD_MapKeyStr(Dqn_CGen_DqnToMDStr8(table->name)), table);
MD_QueuePush(cgen->first_table, cgen->last_table, table); MD_QueuePush(cgen->first_table, cgen->last_table, table);
for (MD_EachNode(key, table_tag->first_child)) { for (MD_EachNode(key, table_tag->first_child)) {
@ -95,7 +95,7 @@ static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error)
case Dqn_CGenTableKeyType_Nil: DQN_INVALID_CODE_PATH; case Dqn_CGenTableKeyType_Nil: DQN_INVALID_CODE_PATH;
case Dqn_CGenTableKeyType_Name: { case Dqn_CGenTableKeyType_Name: {
table->name = key->first_child->string; table->name = Dqn_CGen_MDToDqnStr8(key->first_child->string);
} break; } break;
case Dqn_CGenTableKeyType_Type: { case Dqn_CGenTableKeyType_Type: {
@ -270,10 +270,10 @@ static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error)
DQN_STR_FMT(column.string), DQN_STR_FMT(column.string),
DQN_STR_FMT(header_type_str8), DQN_STR_FMT(header_type_str8),
DQN_STR_FMT(column.string), DQN_STR_FMT(column.string),
MD_S8VArg(it.table->name), DQN_STR_FMT(it.table->name),
MD_S8VArg(it.table->name), DQN_STR_FMT(it.table->name),
DQN_STR_FMT(header_type_str8), DQN_STR_FMT(header_type_str8),
MD_S8VArg(it.table->name), DQN_STR_FMT(it.table->name),
DQN_STR_FMT(header_type_str8)); DQN_STR_FMT(header_type_str8));
} }
} }
@ -403,7 +403,12 @@ DQN_API bool Dqn_CGen_TableHasHeaders(Dqn_CGenTable const *table, Dqn_Str8 const
if (!result) { if (!result) {
Dqn_Str8 missing_headers = Dqn_Str8Builder_Build(&builder, scratch.arena); Dqn_Str8 missing_headers = Dqn_Str8Builder_Build(&builder, scratch.arena);
Dqn_CGen_LogF(MD_MessageKind_Error, table->headers_node, error, "Table '%.*s' is missing the header(s): %.*s", MD_S8VArg(table->name), DQN_STR_FMT(missing_headers)); Dqn_CGen_LogF(MD_MessageKind_Error,
table->headers_node,
error,
"Table '%.*s' is missing the header(s): %.*s",
DQN_STR_FMT(table->name),
DQN_STR_FMT(missing_headers));
} }
return result; return result;

View File

@ -103,7 +103,7 @@ struct Dqn_CGenTableRow
struct Dqn_CGenTable struct Dqn_CGenTable
{ {
Dqn_CGenTableType type; Dqn_CGenTableType type;
MD_String8 name; Dqn_Str8 name;
MD_Map headers_map; MD_Map headers_map;
Dqn_CGenTableHeader *headers; Dqn_CGenTableHeader *headers;
Dqn_CGenTableRow *rows; Dqn_CGenTableRow *rows;

View File

@ -272,7 +272,7 @@ void Dqn_Docs_Demo()
// (B) Error handling using pipelining and and error proof APIs. APIs that // (B) Error handling using pipelining and and error proof APIs. APIs that
// produce errors take in the error sink as a parameter. // produce errors take in the error sink as a parameter.
if (0) { if (0) {
Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(); Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
Dqn_OSFile file = Dqn_OS_FileOpen(DQN_STR8("/path/to/file"), Dqn_OSFileOpen_OpenIfExist, Dqn_OSFileAccess_ReadWrite, error); Dqn_OSFile file = Dqn_OS_FileOpen(DQN_STR8("/path/to/file"), Dqn_OSFileOpen_OpenIfExist, Dqn_OSFileAccess_ReadWrite, error);
Dqn_OS_FileWrite(&file, DQN_STR8("abc"), error); Dqn_OS_FileWrite(&file, DQN_STR8("abc"), error);
Dqn_OS_FileClose(&file); Dqn_OS_FileClose(&file);
@ -296,7 +296,7 @@ void Dqn_Docs_Demo()
// be populated by the first error encountered in that scope. // be populated by the first error encountered in that scope.
if (0) { if (0) {
Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(); Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
Dqn_OSFile file = Dqn_OS_FileOpen(DQN_STR8("/path/to/file"), Dqn_OSFileOpen_OpenIfExist, Dqn_OSFileAccess_ReadWrite, error); Dqn_OSFile file = Dqn_OS_FileOpen(DQN_STR8("/path/to/file"), Dqn_OSFileOpen_OpenIfExist, Dqn_OSFileAccess_ReadWrite, error);
Dqn_OS_FileWrite(&file, DQN_STR8("abc"), error); Dqn_OS_FileWrite(&file, DQN_STR8("abc"), error);
Dqn_OS_FileClose(&file); Dqn_OS_FileClose(&file);
@ -304,7 +304,7 @@ void Dqn_Docs_Demo()
{ {
// NOTE: My error sinks are thread-local, so the returned 'error' is // NOTE: My error sinks are thread-local, so the returned 'error' is
// the same as the 'error' value above. // the same as the 'error' value above.
Dqn_ErrorSink_Begin(); Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
Dqn_OS_WriteAll(DQN_STR8("/path/to/another/file"), DQN_STR8("123"), error); Dqn_OS_WriteAll(DQN_STR8("/path/to/another/file"), DQN_STR8("123"), error);
Dqn_ErrorSink_EndAndLogErrorF(error, "Failed to write to another file"); Dqn_ErrorSink_EndAndLogErrorF(error, "Failed to write to another file");
} }
@ -449,7 +449,7 @@ void Dqn_Docs_Demo()
// 'path'. // 'path'.
if (0) { if (0) {
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(); Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
Dqn_OS_WriteAllSafe(/*path*/ DQN_STR8("C:/Home/my.txt"), /*buffer*/ DQN_STR8("Hello world"), error); Dqn_OS_WriteAllSafe(/*path*/ DQN_STR8("C:/Home/my.txt"), /*buffer*/ DQN_STR8("Hello world"), error);
Dqn_ErrorSink_EndAndLogErrorF(error, ""); Dqn_ErrorSink_EndAndLogErrorF(error, "");
} }