diff --git a/build.bat b/build.bat index c9ec3a9..9e77f5c 100644 --- a/build.bat +++ b/build.bat @@ -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 diff --git a/dqn_base.cpp b/dqn_base.cpp index 486c287..5c845f4 100644 --- a/dqn_base.cpp +++ b/dqn_base.cpp @@ -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)); } } diff --git a/dqn_base.h b/dqn_base.h index 38c6c28..77144d2 100644 --- a/dqn_base.h +++ b/dqn_base.h @@ -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, ...); diff --git a/dqn_cgen.cpp b/dqn_cgen.cpp index a466c0b..0b50fca 100644 --- a/dqn_cgen.cpp +++ b/dqn_cgen.cpp @@ -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; diff --git a/dqn_cgen.h b/dqn_cgen.h index a004851..08ed922 100644 --- a/dqn_cgen.h +++ b/dqn_cgen.h @@ -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; diff --git a/dqn_docs.cpp b/dqn_docs.cpp index c269bca..ee25610 100644 --- a/dqn_docs.cpp +++ b/dqn_docs.cpp @@ -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, ""); }