From e0ab4106fa0707d3ac01a3c80c63fa933e77765e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 11 Nov 2022 17:18:07 +0000 Subject: [PATCH] Implemented the timer library --- repl/lib_standard.c | 2 +- repl/lib_timer.c | 325 +++++++++++++++++++++++++++++++++++-- repl/repl_tools.c | 2 + test/scripts/lib/timer.toy | 62 +++---- test/test_libraries.c | 2 +- 5 files changed, 352 insertions(+), 41 deletions(-) diff --git a/repl/lib_standard.c b/repl/lib_standard.c index 5ad4bee..8061941 100644 --- a/repl/lib_standard.c +++ b/repl/lib_standard.c @@ -2,7 +2,7 @@ #include "memory.h" -#include +#include static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) { //no arguments diff --git a/repl/lib_timer.c b/repl/lib_timer.c index 2211977..010d643 100644 --- a/repl/lib_timer.c +++ b/repl/lib_timer.c @@ -2,24 +2,322 @@ #include "memory.h" +#include #include +#include /* -//using sys/time.h -var timer: opaque = createTimer(); +//using time.h +var timer: opaque = startTimer(); +var diff: opaque = timer.stopTimer(); -timer.startTimer(); -timer.stopTimer(); +... -timer.setTimer(seconds, microseconds); -timer.getTimerSeconds(); -timer.getTimerMicroseconds(); +var timer = createTimer(seconds, microseconds); +print timer.getTimerSeconds(); +print timer.getTimerMicroseconds(); -var diffTimer: opaque = timer.compareTimer(rhs); //expects a stopped timer for both arguments +... -timer.timerToString(); //string representation of the timer +var diff: opaque = timer.compareTimers(rhs); //expects another timer + +... + +print timer.timerToString(); //string representation of the timer + +timer.destroyTimer(); //needed to free the memory */ +//god damn it +static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) { + struct timeval* d = ALLOCATE(struct timeval, 1); + + d->tv_sec = rhs->tv_sec - lhs->tv_sec; + d->tv_usec = rhs->tv_usec - lhs->tv_usec; + + if (d->tv_usec < 0) { + d->tv_sec--; + d->tv_usec += 1000 * 1000; + } + + return d; +} + +static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 0) { + interpreter->errorOutput("Incorrect number of arguments to startTimer\n"); + return -1; + } + + //get the timeinfo from C + struct timeval* timeinfo = ALLOCATE(struct timeval, 1); + gettimeofday(timeinfo, NULL); + + //wrap in an opaque literal for Toy + Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1); + pushLiteralArray(&interpreter->stack, timeLiteral); + + freeLiteral(timeLiteral); + + return 1; +} + +static int nativeStopTimer(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n"); + return -1; + } + + //get the timeinfo from C + struct timeval timerStop; + gettimeofday(&timerStop, NULL); + + //unwrap the opaque literal + Literal timeLiteral = popLiteralArray(arguments); + + Literal timeLiteralIdn = timeLiteral; + if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) { + freeLiteral(timeLiteralIdn); + } + + if (!IS_OPAQUE(timeLiteral)) { + freeLiteral(timeLiteral); + return -1; + } + + struct timeval* timerStart = AS_OPAQUE(timeLiteral); + + //determine the difference, and wrap it + struct timeval* d = diff(timerStart, &timerStop); + Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1); + pushLiteralArray(&interpreter->stack, diffLiteral); + + //cleanup + freeLiteral(timeLiteral); + freeLiteral(diffLiteral); + + return 1; +} + +static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to createTimer\n"); + return -1; + } + + //get the args + Literal microsecondLiteral = popLiteralArray(arguments); + Literal secondLiteral = popLiteralArray(arguments); + + Literal secondLiteralIdn = secondLiteral; + if (IS_IDENTIFIER(secondLiteral) && parseIdentifierToValue(interpreter, &secondLiteral)) { + freeLiteral(secondLiteralIdn); + } + + Literal microsecondLiteralIdn = microsecondLiteral; + if (IS_IDENTIFIER(microsecondLiteral) && parseIdentifierToValue(interpreter, µsecondLiteral)) { + freeLiteral(microsecondLiteralIdn); + } + + if (!IS_INTEGER(secondLiteral) || !IS_INTEGER(microsecondLiteral)) { + freeLiteral(secondLiteral); + freeLiteral(microsecondLiteral); + return -1; + } + + //get the timeinfo from toy + struct timeval* timeinfo = ALLOCATE(struct timeval, 1); + timeinfo->tv_sec = AS_INTEGER(secondLiteral); + timeinfo->tv_usec = AS_INTEGER(microsecondLiteral); + + //wrap in an opaque literal for Toy + Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1); + pushLiteralArray(&interpreter->stack, timeLiteral); + + freeLiteral(timeLiteral); + freeLiteral(secondLiteral); + freeLiteral(microsecondLiteral); + + return 1; +} + +static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to getTimerSeconds\n"); + return -1; + } + + //unwrap the opaque literal + Literal timeLiteral = popLiteralArray(arguments); + + Literal timeLiteralIdn = timeLiteral; + if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) { + freeLiteral(timeLiteralIdn); + } + + if (!IS_OPAQUE(timeLiteral)) { + freeLiteral(timeLiteral); + return -1; + } + + struct timeval* timer = AS_OPAQUE(timeLiteral); + + //create the result literal + Literal result = TO_INTEGER_LITERAL(timer->tv_sec); + pushLiteralArray(&interpreter->stack, result); + + //cleanup + freeLiteral(timeLiteral); + freeLiteral(result); + + return 1; +} + +static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to getTimerSeconds\n"); + return -1; + } + + //unwrap the opaque literal + Literal timeLiteral = popLiteralArray(arguments); + + Literal timeLiteralIdn = timeLiteral; + if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) { + freeLiteral(timeLiteralIdn); + } + + if (!IS_OPAQUE(timeLiteral)) { + freeLiteral(timeLiteral); + return -1; + } + + struct timeval* timer = AS_OPAQUE(timeLiteral); + + //create the result literal + Literal result = TO_INTEGER_LITERAL(timer->tv_usec); + pushLiteralArray(&interpreter->stack, result); + + //cleanup + freeLiteral(timeLiteral); + freeLiteral(result); + + return 1; +} + +static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n"); + return -1; + } + + //unwrap the opaque literals + Literal rhsLiteral = popLiteralArray(arguments); + Literal lhsLiteral = popLiteralArray(arguments); + + Literal lhsLiteralIdn = lhsLiteral; + if (IS_IDENTIFIER(lhsLiteral) && parseIdentifierToValue(interpreter, &lhsLiteral)) { + freeLiteral(lhsLiteralIdn); + } + + Literal rhsLiteralIdn = rhsLiteral; + if (IS_IDENTIFIER(rhsLiteral) && parseIdentifierToValue(interpreter, &rhsLiteral)) { + freeLiteral(rhsLiteralIdn); + } + + if (!IS_OPAQUE(lhsLiteral) || !IS_OPAQUE(rhsLiteral)) { + freeLiteral(lhsLiteral); + freeLiteral(rhsLiteral); + return -1; + } + + struct timeval* lhsTimer = AS_OPAQUE(lhsLiteral); + struct timeval* rhsTimer = AS_OPAQUE(rhsLiteral); + + //determine the difference, and wrap it + struct timeval* d = diff(lhsTimer, rhsTimer); + Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1); + pushLiteralArray(&interpreter->stack, diffLiteral); + + //cleanup + freeLiteral(lhsLiteral); + freeLiteral(rhsLiteral); + freeLiteral(diffLiteral); + + return 1; +} + +static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to _timerToString\n"); + return -1; + } + + //unwrap in an opaque literal + Literal timeLiteral = popLiteralArray(arguments); + + Literal timeLiteralIdn = timeLiteral; + if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) { + freeLiteral(timeLiteralIdn); + } + + if (!IS_OPAQUE(timeLiteral)) { + freeLiteral(timeLiteral); + return -1; + } + + struct timeval* timer = AS_OPAQUE(timeLiteral); + + //create the string literal + char buffer[128]; + snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec); + Literal resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer)); + + pushLiteralArray(&interpreter->stack, resultLiteral); + + //cleanup + freeLiteral(timeLiteral); + freeLiteral(resultLiteral); + + return 1; +} + +static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to _desroyTimer\n"); + return -1; + } + + //unwrap in an opaque literal + Literal timeLiteral = popLiteralArray(arguments); + + Literal timeLiteralIdn = timeLiteral; + if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) { + freeLiteral(timeLiteralIdn); + } + + if (!IS_OPAQUE(timeLiteral)) { + freeLiteral(timeLiteral); + return -1; + } + + struct timeval* timer = AS_OPAQUE(timeLiteral); + + FREE(struct timeval, timer); + + freeLiteral(timeLiteral); + + return 0; +} + //call the hook typedef struct Natives { char* name; @@ -29,7 +327,14 @@ typedef struct Natives { int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) { //build the natives list Natives natives[] = { - // {"clock", nativeClock}, + {"startTimer", nativeStartTimer}, + {"_stopTimer", nativeStopTimer}, + {"createTimer", nativeCreateTimer}, + {"_getTimerSeconds", nativeGetTimerSeconds}, + {"_getTimerMicroseconds", nativeGetTimerMicroseconds}, + {"_compareTimer", nativeCompareTimer}, + {"_timerToString", nativeTimerToString}, + {"_destroyTimer", nativeDestroyTimer}, {NULL, NULL} }; diff --git a/repl/repl_tools.c b/repl/repl_tools.c index a115525..b9bf20d 100644 --- a/repl/repl_tools.c +++ b/repl/repl_tools.c @@ -1,5 +1,6 @@ #include "repl_tools.h" #include "lib_standard.h" +#include "lib_timer.h" #include "console_colors.h" @@ -108,6 +109,7 @@ void runBinary(unsigned char* tb, size_t size) { //inject the libs injectNativeHook(&interpreter, "standard", hookStandard); + injectNativeHook(&interpreter, "timer", hookTimer); runInterpreter(&interpreter, tb, size); freeInterpreter(&interpreter); diff --git a/test/scripts/lib/timer.toy b/test/scripts/lib/timer.toy index fa723d9..c54d80e 100644 --- a/test/scripts/lib/timer.toy +++ b/test/scripts/lib/timer.toy @@ -1,55 +1,59 @@ //test the timer library { - //create a timer, manipulate it's values + //create a timer, run it for a short period 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 - import timer; - - var timerA: opaque = createTimer(); - - timerA.startTimer(); + var timerA: opaque = startTimer(); for (var i: int = 0; i < 1000 * 1000; i++); - timerA.stopTimer(); + var diffA: opaque = timerA.stopTimer(); - //create another timer, run it for a longer time - var timerB: opaque = createTimer(); - - timerB.startTimer(); + //create another timer, run it for a longer period + var timerB: opaque = startTimer(); for (var i: int = 0; i < 1000 * 1000 * 10; i++); - timerB.stopTimer(); + var diffB: opaque = 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); + var difference: opaque = diffA.compareTimer(diffB); assert difference.getTimerSeconds() >= 0, "compareTimer() (seconds) failed"; if (difference.getTimerSeconds() == 0) { assert difference.getTimerMicroseconds() >= 0, "compareTimer() (microseconds) failed"; } + + //all timers must be destroyed after use + timerA.destroyTimer(); + timerB.destroyTimer(); + diffA.destroyTimer(); + diffB.destroyTimer(); + difference.destroyTimer(); +} + +{ + //create a timer, manipulate it's values + import timer; + + //set the timer values manually + var timer: opaque = createTimer(42, 8891); + + //check the timer values + assert timer.getTimerSeconds() == 42, "getTimerSeconds() failed"; + assert timer.getTimerMicroseconds() == 8891, "getTimerMicroseconds() failed"; + + //all timers must be destroyed after use + timer.destroyTimer(); } { //set a timer to check string representation import timer; - var timer: opaque = createTimer(); + var timer: opaque = createTimer(42, 999); - timer.setTimer(42, 999); + assert timer.timerToString() == "42.000999", "timerToString() failed"; - assert timer.timerToString() == "42.999", "timerToString() failed"; + //all timers must be destroyed after use + timer.destroyTimer(); } diff --git a/test/test_libraries.c b/test/test_libraries.c index 15b92d5..f096a76 100644 --- a/test/test_libraries.c +++ b/test/test_libraries.c @@ -132,7 +132,7 @@ int main() { Payload payloads[] = { {"interactions.toy", "standard", hookStandard}, //interactions needs standard {"standard.toy", "standard", hookStandard}, - // {"timer.toy", "timer", hookTimer}, + {"timer.toy", "timer", hookTimer}, {NULL, NULL, NULL} };