mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Implemented the timer library
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
|
|||||||
325
repl/lib_timer.c
325
repl/lib_timer.c
@@ -2,24 +2,322 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//using sys/time.h
|
//using time.h
|
||||||
var timer: opaque = createTimer();
|
var timer: opaque = startTimer();
|
||||||
|
var diff: opaque = timer.stopTimer();
|
||||||
|
|
||||||
timer.startTimer();
|
...
|
||||||
timer.stopTimer();
|
|
||||||
|
|
||||||
timer.setTimer(seconds, microseconds);
|
var timer = createTimer(seconds, microseconds);
|
||||||
timer.getTimerSeconds();
|
print timer.getTimerSeconds();
|
||||||
timer.getTimerMicroseconds();
|
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
|
//call the hook
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
@@ -29,7 +327,14 @@ typedef struct Natives {
|
|||||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
||||||
//build the natives list
|
//build the natives list
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
// {"clock", nativeClock},
|
{"startTimer", nativeStartTimer},
|
||||||
|
{"_stopTimer", nativeStopTimer},
|
||||||
|
{"createTimer", nativeCreateTimer},
|
||||||
|
{"_getTimerSeconds", nativeGetTimerSeconds},
|
||||||
|
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
|
||||||
|
{"_compareTimer", nativeCompareTimer},
|
||||||
|
{"_timerToString", nativeTimerToString},
|
||||||
|
{"_destroyTimer", nativeDestroyTimer},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "repl_tools.h"
|
#include "repl_tools.h"
|
||||||
#include "lib_standard.h"
|
#include "lib_standard.h"
|
||||||
|
#include "lib_timer.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "console_colors.h"
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ void runBinary(unsigned char* tb, size_t size) {
|
|||||||
|
|
||||||
//inject the libs
|
//inject the libs
|
||||||
injectNativeHook(&interpreter, "standard", hookStandard);
|
injectNativeHook(&interpreter, "standard", hookStandard);
|
||||||
|
injectNativeHook(&interpreter, "timer", hookTimer);
|
||||||
|
|
||||||
runInterpreter(&interpreter, tb, size);
|
runInterpreter(&interpreter, tb, size);
|
||||||
freeInterpreter(&interpreter);
|
freeInterpreter(&interpreter);
|
||||||
|
|||||||
@@ -1,55 +1,59 @@
|
|||||||
//test the timer library
|
//test the timer library
|
||||||
{
|
{
|
||||||
//create a timer, manipulate it's values
|
//create a timer, run it for a short period
|
||||||
import timer;
|
import timer;
|
||||||
|
|
||||||
//create a timer
|
var timerA: opaque = startTimer();
|
||||||
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();
|
|
||||||
for (var i: int = 0; i < 1000 * 1000; i++);
|
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
|
//create another timer, run it for a longer period
|
||||||
var timerB: opaque = createTimer();
|
var timerB: opaque = startTimer();
|
||||||
|
|
||||||
timerB.startTimer();
|
|
||||||
for (var i: int = 0; i < 1000 * 1000 * 10; i++);
|
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
|
//check to ensure that the second timer took longer than the first
|
||||||
//WARNING: this has the small possibility of failing due to external factors
|
//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";
|
assert difference.getTimerSeconds() >= 0, "compareTimer() (seconds) failed";
|
||||||
if (difference.getTimerSeconds() == 0) {
|
if (difference.getTimerSeconds() == 0) {
|
||||||
assert difference.getTimerMicroseconds() >= 0, "compareTimer() (microseconds) failed";
|
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
|
//set a timer to check string representation
|
||||||
import timer;
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ int main() {
|
|||||||
Payload payloads[] = {
|
Payload payloads[] = {
|
||||||
{"interactions.toy", "standard", hookStandard}, //interactions needs standard
|
{"interactions.toy", "standard", hookStandard}, //interactions needs standard
|
||||||
{"standard.toy", "standard", hookStandard},
|
{"standard.toy", "standard", hookStandard},
|
||||||
// {"timer.toy", "timer", hookTimer},
|
{"timer.toy", "timer", hookTimer},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user