diff --git a/repl/main.c b/repl/main.c index 3413edd..b195e1f 100644 --- a/repl/main.c +++ b/repl/main.c @@ -1,4 +1,5 @@ #include "toy.h" +#include "toy_print.h" #include #include @@ -156,8 +157,17 @@ CmdLine parseCmdLine(int argc, const char* argv[]) { return cmd; } +//callback +static void errorAndExit(const char* msg) { + fprintf(stderr, "%s", msg); + exit(-1); +} + //main file int main(int argc, const char* argv[]) { + Toy_setErrorCallback(errorAndExit); + Toy_setAssertFailureCallback(errorAndExit); + CmdLine cmd = parseCmdLine(argc, argv); if (cmd.error) { diff --git a/source/toy_print.c b/source/toy_print.c new file mode 100644 index 0000000..d57eb18 --- /dev/null +++ b/source/toy_print.c @@ -0,0 +1,51 @@ +#include "toy_print.h" + +#include + +static void outDefault(const char* msg) { + fprintf(stdout, "%s", msg); +} + +static void errDefault(const char* msg) { + fprintf(stderr, "%s", msg); +} + +static Toy_callbackType printCallback = outDefault; +static Toy_callbackType errorCallback = errDefault; +static Toy_callbackType assertCallback = errDefault; + +void Toy_print(const char* msg) { + printCallback(msg); +} + +void Toy_error(const char* msg) { + errorCallback(msg); +} + +void Toy_assertFailure(const char* msg) { + assertCallback(msg); +} + +void Toy_setPrintCallback(Toy_callbackType cb) { + printCallback = cb; +} + +void Toy_setErrorCallback(Toy_callbackType cb) { + errorCallback = cb; +} +void Toy_setAssertFailureCallback(Toy_callbackType cb) { + assertCallback = cb; +} + +void Toy_resetPrintCallback() { + printCallback = outDefault; +} + +void Toy_resetErrorCallback() { + errorCallback = errDefault; +} + +void Toy_resetAssertFailureCallback() { + assertCallback = errDefault; +} + diff --git a/source/toy_print.h b/source/toy_print.h new file mode 100644 index 0000000..5f67676 --- /dev/null +++ b/source/toy_print.h @@ -0,0 +1,17 @@ +#include "toy_common.h" + +//handle callbacks for printing to the terminal, or elsewhere +typedef void (*Toy_callbackType)(const char*); + +TOY_API void Toy_print(const char* msg); //print keyword +TOY_API void Toy_error(const char* msg); //runtime errors +TOY_API void Toy_assertFailure(const char* msg); //assert keyword failures + +TOY_API void Toy_setPrintCallback(Toy_callbackType cb); +TOY_API void Toy_setErrorCallback(Toy_callbackType cb); +TOY_API void Toy_setAssertFailureCallback(Toy_callbackType cb); + +TOY_API void Toy_resetPrintCallback(); +TOY_API void Toy_resetErrorCallback(); +TOY_API void Toy_resetAssertFailureCallback(); + diff --git a/source/toy_table.c b/source/toy_table.c index 52b004a..b9f26e3 100644 --- a/source/toy_table.c +++ b/source/toy_table.c @@ -1,5 +1,6 @@ #include "toy_table.h" #include "toy_console_colors.h" +#include "toy_print.h" #include #include @@ -58,8 +59,7 @@ static Toy_Table* adjustTableCapacity(Toy_Table* oldTable, unsigned int newCapac Toy_Table* newTable = malloc(newCapacity * sizeof(Toy_TableEntry) + sizeof(Toy_Table)); if (newTable == NULL) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_Table' of %u capacity\n" TOY_CC_RESET, newCapacity); - exit(-1); + Toy_error(TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_Table'\n" TOY_CC_RESET); } newTable->capacity = newCapacity; @@ -99,8 +99,7 @@ void Toy_freeTable(Toy_Table* table) { void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value) { if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques - fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); - exit(-1); //TODO: #127 + Toy_error(TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); } //expand the capacity @@ -113,8 +112,7 @@ void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value) { Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) { if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques - fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); - exit(-1); //TODO: #127 + Toy_error(TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); } //lookup @@ -138,8 +136,7 @@ Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) { void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) { if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques - fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); - exit(-1); //TODO: #127 + Toy_error(TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET); } //lookup @@ -179,4 +176,4 @@ void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) { //finally, wipe the removed entry (*tableHandle)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 }; (*tableHandle)->count--; -} \ No newline at end of file +} diff --git a/source/toy_value.c b/source/toy_value.c index ba2d451..5e5d771 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -1,14 +1,13 @@ #include "toy_value.h" #include "toy_console_colors.h" +#include "toy_print.h" #include -#include bool Toy_private_isTruthy(Toy_Value value) { //null is an error if (TOY_VALUE_IS_NULL(value)) { - fprintf(stderr, TOY_CC_ERROR "ERROR: 'null' is neither true nor false\n" TOY_CC_RESET); - exit(-1); //TODO: #127 + Toy_error(TOY_CC_ERROR "ERROR: 'null' is neither true nor false\n" TOY_CC_RESET); } //only 'false' is falsy @@ -23,8 +22,7 @@ bool Toy_private_isTruthy(Toy_Value value) { bool Toy_private_isEqual(Toy_Value left, Toy_Value right) { //temp check if (right.type > TOY_VALUE_FLOAT) { - fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown types %d and %d in equality\n" TOY_CC_RESET, left.type, right.type); - exit(-1); + Toy_error(TOY_CC_ERROR "ERROR: Unknown types in value equality comparison\n" TOY_CC_RESET); //TODO: varargs } switch(left.type) { @@ -58,9 +56,10 @@ bool Toy_private_isEqual(Toy_Value left, Toy_Value right) { case TOY_VALUE_FUNCTION: case TOY_VALUE_OPAQUE: default: - fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown types %d and %d in equality\n" TOY_CC_RESET, left.type, right.type); - exit(-1); + Toy_error(TOY_CC_ERROR "ERROR: Unknown types in value equality comparison\n" TOY_CC_RESET); //TODO: varargs } + + return 0; } //hash utils @@ -103,7 +102,8 @@ unsigned int Toy_hashValue(Toy_Value value) { case TOY_VALUE_FUNCTION: case TOY_VALUE_OPAQUE: default: - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't hash an unknown type %d\n" TOY_CC_RESET, value.type); - exit(-1); + Toy_error(TOY_CC_ERROR "ERROR: Can't hash an unknown type\n" TOY_CC_RESET); } + + return 0; } diff --git a/tests/cases/test_print.c b/tests/cases/test_print.c new file mode 100644 index 0000000..f1e74ca --- /dev/null +++ b/tests/cases/test_print.c @@ -0,0 +1,111 @@ +#include "toy_print.h" +#include "toy_console_colors.h" + +#include + +int counter = 0; + +void count(const char* msg) { + counter++; +} + +int test_callbacks() { + //set a custom print callback, invoke it, and reset + { + //setup + Toy_setPrintCallback(count); + + //invoke + Toy_print(""); + + //check + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set print callback\n" TOY_CC_RESET); + return -1; + } + + //reset and retry + Toy_resetPrintCallback(); + Toy_print(""); + + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset print callback\n" TOY_CC_RESET); + return -1; + } + + //cleanup + counter = 0; + } + + //set a custom error callback, invoke it, and reset + { + //setup + Toy_setErrorCallback(count); + + //invoke + Toy_error(""); + + //check + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set error callback\n" TOY_CC_RESET); + return -1; + } + + //reset and retry + Toy_resetErrorCallback(); + Toy_error(""); + + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset error callback\n" TOY_CC_RESET); + return -1; + } + + //cleanup + counter = 0; + } + + //set a custom assert failure callback, invoke it, and reset + { + //setup + Toy_setAssertFailureCallback(count); + + //invoke + Toy_assertFailure(""); + + //check + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set assert failure callback\n" TOY_CC_RESET); + return -1; + } + + //reset and retry + Toy_resetAssertFailureCallback(); + Toy_assertFailure(""); + + if (counter != 1) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset assert failure callback\n" TOY_CC_RESET); + return -1; + } + + //cleanup + counter = 0; + } + + return 0; +} + +int main() { + //run each test set, returning the total errors given + int total = 0, res = 0; + + { + res = test_callbacks(); + if (res == 0) { + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + } + total += res; + } + + return total; +} +