Updated Toy, added repl_tools and lib copying to the build
This commit is contained in:
2
Toy
2
Toy
Submodule Toy updated: 8498864dde...7bf18a744c
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//no arguments
|
||||
|
||||
411
core/lib_timer.c
Normal file
411
core/lib_timer.c
Normal file
@@ -0,0 +1,411 @@
|
||||
#include "lib_timer.h"
|
||||
|
||||
#include "toy_common.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
|
||||
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
|
||||
//normallize
|
||||
if (x->tv_usec > 999999) {
|
||||
x->tv_sec += x->tv_usec / 1000000;
|
||||
x->tv_usec %= 1000000;
|
||||
}
|
||||
|
||||
if (y->tv_usec > 999999) {
|
||||
y->tv_sec += y->tv_usec / 1000000;
|
||||
y->tv_usec %= 1000000;
|
||||
}
|
||||
|
||||
//calc
|
||||
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||
|
||||
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0) {
|
||||
if (result->tv_sec != 0) { //only works far from 0
|
||||
result->tv_usec += 1000000;
|
||||
result->tv_sec--; // borrow
|
||||
}
|
||||
}
|
||||
|
||||
return result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0);
|
||||
}
|
||||
|
||||
//god damn it
|
||||
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
||||
struct timeval* d = ALLOCATE(struct timeval, 1);
|
||||
|
||||
//I gave up, copied from SO
|
||||
timeval_subtract(d, rhs, lhs);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
//callbacks
|
||||
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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
|
||||
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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
|
||||
freeLiteral(secondLiteral);
|
||||
freeLiteral(microsecondLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (AS_INTEGER(secondLiteral) != 0 && AS_INTEGER(microsecondLiteral) < 0) ) {
|
||||
interpreter->errorOutput("Microseconds out of range in createTimer\n");
|
||||
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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
|
||||
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 _getTimerMicroseconds\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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
|
||||
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 _compareTimer\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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
|
||||
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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
|
||||
freeLiteral(timeLiteral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
||||
|
||||
//create the string literal
|
||||
Literal resultLiteral = TO_NULL_LITERAL;
|
||||
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
|
||||
char buffer[128];
|
||||
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
|
||||
resultLiteral = TO_STRING_LITERAL( copyString(buffer, strlen(buffer)), strlen(buffer));
|
||||
}
|
||||
else { //normal case
|
||||
char buffer[128];
|
||||
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
||||
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 _destroyTimer\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)) {
|
||||
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
|
||||
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;
|
||||
NativeFn fn;
|
||||
} Natives;
|
||||
|
||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
||||
//build the natives list
|
||||
Natives natives[] = {
|
||||
{"startTimer", nativeStartTimer},
|
||||
{"_stopTimer", nativeStopTimer},
|
||||
{"createTimer", nativeCreateTimer},
|
||||
{"_getTimerSeconds", nativeGetTimerSeconds},
|
||||
{"_getTimerMicroseconds", nativeGetTimerMicroseconds},
|
||||
{"_compareTimer", nativeCompareTimer},
|
||||
{"_timerToString", nativeTimerToString},
|
||||
{"_destroyTimer", nativeDestroyTimer},
|
||||
{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;
|
||||
}
|
||||
6
core/lib_timer.h
Normal file
6
core/lib_timer.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias);
|
||||
|
||||
@@ -25,12 +25,16 @@ else
|
||||
exit 1
|
||||
endif
|
||||
|
||||
library: $(OBJ)
|
||||
library: libs $(OBJ)
|
||||
$(CC) -DCORE_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE) -L../$(LIBDIR) $(LIBS)
|
||||
|
||||
static: $(OBJ)
|
||||
static: libs $(OBJ)
|
||||
ar crs $(CORE_OUTDIR)/lib$(OUTNAME).a $(OBJ) -L../$(LIBDIR) $(LIBS)
|
||||
|
||||
libs:
|
||||
cp ../Toy/repl/lib* .
|
||||
cp ../Toy/repl/repl_tools.* .
|
||||
|
||||
$(OBJ): | $(ODIR)
|
||||
|
||||
$(ODIR):
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "core_common.h"
|
||||
#include "toy_common.h"
|
||||
|
||||
char* readFile(char* path, size_t* fileSize);
|
||||
void writeFile(char* path, unsigned char* bytes, size_t size);
|
||||
|
||||
Reference in New Issue
Block a user