Allow exiting on error from the creation of an error sink
This commit is contained in:
parent
963d911d9d
commit
7f2a0152e0
@ -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
|
||||||
|
|
||||||
|
29
dqn_base.cpp
29
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 /////////////////////////////////////////////////////////////////////
|
// 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,7 +489,9 @@ 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)
|
||||||
|
return;
|
||||||
|
|
||||||
Dqn_ErrorSinkNode *node = error->stack;
|
Dqn_ErrorSinkNode *node = error->stack;
|
||||||
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
|
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
|
||||||
if (!node->error) { // NOTE: Only preserve the first error
|
if (!node->error) { // NOTE: Only preserve the first error
|
||||||
@ -487,7 +499,8 @@ DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQ
|
|||||||
node->error_code = error_code;
|
node->error_code = error_code;
|
||||||
node->error = true;
|
node->error = true;
|
||||||
node->call_site = Dqn_ThreadContext_Get()->call_site;
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
dqn_base.h
10
dqn_base.h
@ -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, ...);
|
||||||
|
19
dqn_cgen.cpp
19
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);
|
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;
|
||||||
|
@ -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;
|
||||||
|
@ -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, "");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user