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 Oi Use CPU Intrinsics
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

View File

@ -407,13 +407,14 @@ DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN
}
// 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_ErrorSink *result = &thread_context->error_sink;
Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes);
node->next = result->stack;
node->arena_pos = Dqn_Arena_Pos(result->arena);
node->mode = mode;
result->stack = node;
return result;
}
@ -438,14 +439,13 @@ DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End(Dqn_Arena *arena, Dqn_ErrorSink *err
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_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.arena, error);
if (node.error) {
Dqn_Str8 line = Dqn_Str8_InitFV(scratch.arena, fmt, args);
if (Dqn_Str8_HasData(line)) {
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s. %.*s", DQN_STR_FMT(line), DQN_STR_FMT(node.msg));
if (Dqn_Str8_HasData(error_msg)) {
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s. %.*s", DQN_STR_FMT(error_msg), DQN_STR_FMT(node.msg));
} else {
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;
}
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, ...)
{
va_list args;
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);
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)
{
if (error) {
Dqn_ErrorSinkNode *node = error->stack;
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
if (!node->error) { // NOTE: Only preserve the first error
node->msg = Dqn_Str8_InitFV(error->arena, fmt, args);
node->error_code = error_code;
node->error = true;
node->call_site = Dqn_ThreadContext_Get()->call_site;
}
if (!error)
return;
Dqn_ErrorSinkNode *node = error->stack;
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
if (!node->error) { // NOTE: Only preserve the first error
node->msg = Dqn_Str8_InitFV(error->arena, fmt, args);
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__}
// NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
enum Dqn_ErrorSinkMode
{
Dqn_ErrorSinkMode_Nil,
Dqn_ErrorSinkMode_ExitOnError,
};
struct Dqn_ErrorSinkNode
{
Dqn_ErrorSinkMode mode;
bool error;
int32_t error_code;
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, ...);
// 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 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_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, ...);

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);
table->node = node;
table->name = table_tag->first_child->first_child->string;
MD_MapInsert(cgen->arena, &cgen->table_map, MD_MapKeyStr(table->name), table);
table->name = Dqn_CGen_MDToDqnStr8(table_tag->first_child->first_child->string);
MD_MapInsert(cgen->arena, &cgen->table_map, MD_MapKeyStr(Dqn_CGen_DqnToMDStr8(table->name)), table);
MD_QueuePush(cgen->first_table, cgen->last_table, table);
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_Name: {
table->name = key->first_child->string;
table->name = Dqn_CGen_MDToDqnStr8(key->first_child->string);
} break;
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(header_type_str8),
DQN_STR_FMT(column.string),
MD_S8VArg(it.table->name),
MD_S8VArg(it.table->name),
DQN_STR_FMT(it.table->name),
DQN_STR_FMT(it.table->name),
DQN_STR_FMT(header_type_str8),
MD_S8VArg(it.table->name),
DQN_STR_FMT(it.table->name),
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) {
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;

View File

@ -103,7 +103,7 @@ struct Dqn_CGenTableRow
struct Dqn_CGenTable
{
Dqn_CGenTableType type;
MD_String8 name;
Dqn_Str8 name;
MD_Map headers_map;
Dqn_CGenTableHeader *headers;
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
// produce errors take in the error sink as a parameter.
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_OS_FileWrite(&file, DQN_STR8("abc"), error);
Dqn_OS_FileClose(&file);
@ -296,7 +296,7 @@ void Dqn_Docs_Demo()
// be populated by the first error encountered in that scope.
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_OS_FileWrite(&file, DQN_STR8("abc"), error);
Dqn_OS_FileClose(&file);
@ -304,7 +304,7 @@ void Dqn_Docs_Demo()
{
// NOTE: My error sinks are thread-local, so the returned 'error' is
// 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_ErrorSink_EndAndLogErrorF(error, "Failed to write to another file");
}
@ -449,7 +449,7 @@ void Dqn_Docs_Demo()
// 'path'.
if (0) {
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_ErrorSink_EndAndLogErrorF(error, "");
}