diff --git a/repl/lib_timer.c b/repl/lib_timer.c new file mode 100644 index 0000000..2211977 --- /dev/null +++ b/repl/lib_timer.c @@ -0,0 +1,85 @@ +#include "lib_timer.h" + +#include "memory.h" + +#include + +/* +//using sys/time.h +var timer: opaque = createTimer(); + +timer.startTimer(); +timer.stopTimer(); + +timer.setTimer(seconds, microseconds); +timer.getTimerSeconds(); +timer.getTimerMicroseconds(); + +var diffTimer: opaque = timer.compareTimer(rhs); //expects a stopped timer for both arguments + +timer.timerToString(); //string representation of the timer +*/ + +//call the hook +typedef struct Natives { + char* name; + NativeFn fn; +} Natives; + +int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) { + //build the natives list + Natives natives[] = { + // {"clock", nativeClock}, + {NULL, NULL} + }; + + //store the library in an aliased dictionary + if (!IS_NULL(alias)) { + //make sure the name isn't taken + if (isDelcaredScopeVariable(interpreter->scope, alias)) { + interpreter->errorOutput("Can't override an existing variable\n"); + freeLiteral(alias); + return false; + } + + //create the dictionary to load up with functions + LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); + initLiteralDictionary(dictionary); + + //load the dict with functions + for (int i = 0; natives[i].name; i++) { + Literal name = TO_STRING_LITERAL(copyString(natives[i].name, strlen(natives[i].name)), strlen(natives[i].name)); + Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0); + func.type = LITERAL_FUNCTION_NATIVE; + + setLiteralDictionary(dictionary, name, func); + + freeLiteral(name); + freeLiteral(func); + } + + //build the type + Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true); + Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true); + Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true); + TYPE_PUSH_SUBTYPE(&type, strType); + TYPE_PUSH_SUBTYPE(&type, fnType); + + //set scope + Literal dict = TO_DICTIONARY_LITERAL(dictionary); + declareScopeVariable(interpreter->scope, alias, type); + setScopeVariable(interpreter->scope, alias, dict, false); + + //cleanup + freeLiteral(dict); + freeLiteral(type); + return 0; + } + + //default + for (int i = 0; natives[i].name; i++) { + injectNativeFn(interpreter, natives[i].name, natives[i].fn); + } + + return 0; +} diff --git a/repl/lib_timer.h b/repl/lib_timer.h new file mode 100644 index 0000000..4fa99e7 --- /dev/null +++ b/repl/lib_timer.h @@ -0,0 +1,6 @@ +#pragma once + +#include "interpreter.h" + +int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias); + diff --git a/repl/repl_main.c b/repl/repl_main.c index 3a64209..cf2b80d 100644 --- a/repl/repl_main.c +++ b/repl/repl_main.c @@ -1,5 +1,6 @@ #include "repl_tools.h" #include "lib_standard.h" +#include "lib_timer.h" #include "console_colors.h" @@ -25,6 +26,7 @@ void repl() { //inject the libs injectNativeHook(&interpreter, "standard", hookStandard); + injectNativeHook(&interpreter, "timer", hookTimer); for(;;) { printf("> "); diff --git a/scripts/test/lib/timer.toy b/scripts/test/lib/timer.toy new file mode 100644 index 0000000..31defe1 --- /dev/null +++ b/scripts/test/lib/timer.toy @@ -0,0 +1,52 @@ +//test the timer library +{ + //create a timer, manipulate it's values + import timer; + + //create a timer + var timer: opaque = createTimer(); + + //set the timer + timer.setTimer(42, 8891); + + //check the timer values + assert timer.getTimerSeconds() == 42, "getTimerSeconds() failed"; + assert timer.getTimerMicroseconds() == 42, "getTimerMicroseconds() failed"; +} + +{ + //create a timer, run it for a short time + var timerA: opaque = createTimer(); + + timerA.startTimer(); + for (var i: int = 0; i < 1000 * 1000; i++); + timerA.stopTimer(); + + //create another timer, run it for a longer time + var timerB: opaque = createTimer(); + + timerB.startTimer(); + for (var i: int = 0; i < 1000 * 1000 * 10; i++); + timerB.stopTimer(); + + //check to ensure that the second timer took longer than the first + //WARNING: this has the small possibility of failing due to external factors + var difference: opaque = timerA.compareTimer(timerB); + + assert difference.getTimerSeconds() >= 0, "compareTimer() (seconds) failed"; + if (difference.getTimerSeconds() == 0) { + assert difference.getTimerMicroseconds() >= 0, "compareTimer() (microseconds) failed"; + } +} + +{ + //set a timer to check string representation + var timer: opaque = createTimer(); + + timer.setTimer(42, 999); + + assert timer.timerToString() == "42.999", "timerToString() failed"; +} + + +print "All good"; diff --git a/test/test_libraries.c b/test/test_libraries.c index 1f87fcb..19183b1 100644 --- a/test/test_libraries.c +++ b/test/test_libraries.c @@ -12,12 +12,26 @@ #include #include "../repl/lib_standard.h" +#include "../repl/lib_timer.h" //supress the print output static void noPrintFn(const char* output) { //NO OP } +static int failedAsserts = 0; +static void assertWrapper(const char* output) { + failedAsserts++; + fprintf(stderr, ERROR "Assertion failure: "); + fprintf(stderr, "%s", output); + fprintf(stderr, "\n" RESET); //default new line +} + +static void errorWrapper(const char* output) { + failedAsserts++; + fprintf(stderr, ERROR "%s" RESET, output); +} + //compilation functions char* readFile(char* path, size_t* fileSize) { FILE* file = fopen(path, "rb"); @@ -90,56 +104,65 @@ unsigned char* compileString(char* source, size_t* size) { return tb; } -void runBinary(unsigned char* tb, size_t size) { +void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, HookFn hook) { Interpreter interpreter; initInterpreter(&interpreter); //NOTE: supress print output for testing setInterpreterPrint(&interpreter, noPrintFn); + setInterpreterAssert(&interpreter, assertWrapper); + setInterpreterError(&interpreter, errorWrapper); //inject the standard libraries into this interpreter - injectNativeHook(&interpreter, "standard", hookStandard); + injectNativeHook(&interpreter, library, hook); runInterpreter(&interpreter, tb, size); freeInterpreter(&interpreter); } -void runSource(char* source) { - size_t size = 0; - unsigned char* tb = compileString(source, &size); - if (!tb) { - return; - } - runBinary(tb, size); -} - -void runSourceFile(char* fname) { - size_t size = 0; //not used - char* source = readFile(fname, &size); - runSource(source); - free((void*)source); -} +typedef struct Payload { + char* fname; + char* libname; + HookFn hook; +} Payload; int main() { { //run each file in ../scripts/test/ - char* filenames[] = { - "interactions.toy", - "standard.toy", - NULL + Payload payloads[] = { + {"interactions.toy", "standard", hookStandard}, //interactions needs standard + {"standard.toy", "standard", hookStandard}, + // {"timer.toy", "timer", hookTimer}, + {NULL, NULL, NULL} }; - for (int i = 0; filenames[i]; i++) { - printf("Running %s\n", filenames[i]); + for (int i = 0; payloads[i].fname; i++) { + printf("Running %s\n", payloads[i].fname); - char buffer[128]; - snprintf(buffer, 128, "../scripts/test/lib/%s", filenames[i]); + char fname[128]; + snprintf(fname, 128, "../scripts/test/lib/%s", payloads[i].fname); - runSourceFile(buffer); + //compile the source + size_t size = 0; + char* source = readFile(fname, &size); + unsigned char* tb = compileString(source, &size); + free((void*)source); + + if (!tb) { + printf(ERROR "Failed to compile file: %s" RESET, fname); + } + + runBinaryWithLibrary(tb, size, payloads[i].libname, payloads[i].hook); } } - printf(NOTICE "All good\n" RESET); - return 0; + if (!failedAsserts) { + printf(NOTICE "All good\n" RESET); + } + else { + printf(WARN "Problems detected in libraries\n" RESET); + } + + return failedAsserts; }