Renamed files

This commit is contained in:
2023-01-26 20:41:23 +00:00
parent 54d417b3fc
commit 3e18baeec0
25 changed files with 28 additions and 1339 deletions

2
Toy

Submodule Toy updated: 6d961cea78...b2c3dd894c

View File

@@ -5,7 +5,7 @@
#include "literal_dictionary.h"
#include "interpreter.h"
#define OPAQUE_TAG_ENGINE_NODE 1
#define OPAQUE_TAG_ENGINE_NODE 1001
//forward declare
typedef struct _engineNode EngineNode;

View File

@@ -10,28 +10,28 @@ OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
TOYLIBS = $(wildcard ../Toy/repl/lib*) $(wildcard ../Toy/repl/repl_tools.*)
OUTNAME=core
OUTNAME=box
ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN)
LIBLINE =-Wl,--out-implib=$(CORE_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=$(CORE_OUTDIR)/$(OUTNAME).dll
LIBLINE =-Wl,--out-implib=$(BOX_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=$(BOX_OUTDIR)/$(OUTNAME).dll
else ifeq ($(shell uname),Linux)
LIBLINE=-Wl,--out-implib=./$(CORE_OUTDIR)/lib$(OUTNAME).a -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=./$(CORE_OUTDIR)/lib$(OUTNAME).so
LIBLINE=-Wl,--out-implib=./$(BOX_OUTDIR)/lib$(OUTNAME).a -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=./$(BOX_OUTDIR)/lib$(OUTNAME).so
CFLAGS += -fPIC
else ifeq ($(OS),Windows_NT)
LIBLINE =-Wl,--out-implib=$(CORE_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=$(CORE_OUTDIR)/$(OUTNAME).dll
LIBLINE =-Wl,--out-implib=$(BOX_OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
OUT=$(BOX_OUTDIR)/$(OUTNAME).dll
else
@echo "Platform test failed - what platform is this?"
exit 1
endif
library: libs $(OBJ)
$(CC) -DCORE_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE) -L../$(LIBDIR) $(LIBS)
$(CC) -DBOX_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE) -L../$(LIBDIR) $(LIBS)
static: libs $(OBJ)
ar crs $(CORE_OUTDIR)/lib$(OUTNAME).a $(OBJ) -L../$(LIBDIR) $(LIBS)
ar crs $(BOX_OUTDIR)/lib$(OUTNAME).a $(OBJ) -L../$(LIBDIR) $(LIBS)
#copy the stuff from Toy/repl that is needed
libs:

View File

@@ -1,620 +0,0 @@
#include "lib_runner.h"
#include "memory.h"
#include "interpreter.h"
#include "repl_tools.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct Runner {
Interpreter interpreter;
unsigned char* bytecode;
size_t size;
bool dirty;
} Runner;
//Toy native functions
static int nativeLoadScript(Interpreter* interpreter, LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
return -1;
}
//get the argument
Literal drivePathLiteral = popLiteralArray(arguments);
RefString* drivePath = copyRefString(AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (toCString(drivePath)[driveLength] != ':') {
if (driveLength >= lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
RefString* drive = createRefStringLength(toCString(drivePath), driveLength);
RefString* path = createRefStringLength( &toCString(drivePath)[driveLength + 1], lengthRefString(drivePath) - driveLength );
//get the real drive file path
Literal driveLiteral = TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Literal realDriveLiteral = getLiteralDictionary(getDriveDictionary(), driveLiteral);
if (!IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(realDriveLiteral);
freeLiteral(driveLiteral);
deleteRefString(path);
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
RefString* realDrive = copyRefString(AS_STRING(realDriveLiteral));
int realLength = lengthRefString(realDrive) + lengthRefString(path);
char* filePath = ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", toCString(realDrive), toCString(path));
//clean up the drivepath stuff
deleteRefString(realDrive);
freeLiteral(realDriveLiteral);
freeLiteral(driveLiteral);
deleteRefString(path);
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) {
interpreter->errorOutput("Bad script file extension (expected .toy)\n");
FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load and compile the bytecode
size_t fileSize = 0;
char* source = readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
return -1;
}
unsigned char* bytecode = compileString(source, &fileSize);
free((void*)source);
if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n");
return -1;
}
//build the runner object
Runner* runner = ALLOCATE(Runner, 1);
setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Literal runnerLiteral = TO_OPAQUE_LITERAL(runner, OPAQUE_TAG_RUNNER);
pushLiteralArray(&interpreter->stack, runnerLiteral);
FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeLoadScriptBytecode(Interpreter* interpreter, LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
return -1;
}
//get the argument
Literal drivePathLiteral = popLiteralArray(arguments);
RefString* drivePath = copyRefString(AS_STRING(drivePathLiteral));
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
int driveLength = 0;
while (toCString(drivePath)[driveLength] != ':') {
if (driveLength >= lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
RefString* drive = createRefStringLength(toCString(drivePath), driveLength);
RefString* path = createRefStringLength( &toCString(drivePath)[driveLength + 1], lengthRefString(drivePath) - driveLength );
//get the real drive file path
Literal driveLiteral = TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Literal realDriveLiteral = getLiteralDictionary(getDriveDictionary(), driveLiteral);
if (!IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(realDriveLiteral);
freeLiteral(driveLiteral);
deleteRefString(path);
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
RefString* realDrive = copyRefString(AS_STRING(realDriveLiteral));
int realLength = lengthRefString(realDrive) + lengthRefString(path);
char* filePath = ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", toCString(realDrive), toCString(path));
//clean up the drivepath stuff
deleteRefString(realDrive);
freeLiteral(realDriveLiteral);
freeLiteral(driveLiteral);
deleteRefString(path);
deleteRefString(drivePath);
freeLiteral(drivePathLiteral);
//check for file extensions
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
FREE_ARRAY(char, filePath, realLength);
return -1;
}
//check for break-out attempts
for (int i = 0; i < realLength - 1; i++) {
if (filePath[i] == '.' && filePath[i + 1] == '.') {
interpreter->errorOutput("Parent directory access not allowed\n");
FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load the bytecode
size_t fileSize = 0;
unsigned char* bytecode = (unsigned char*)readFile(filePath, &fileSize);
if (!bytecode) {
interpreter->errorOutput("Failed to load bytecode file\n");
return -1;
}
//build the runner object
Runner* runner = ALLOCATE(Runner, 1);
setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Literal runnerLiteral = TO_OPAQUE_LITERAL(runner, OPAQUE_TAG_RUNNER);
pushLiteralArray(&interpreter->stack, runnerLiteral);
FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeRunScript(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Literal runnerLiteral = popLiteralArray(arguments);
Literal idn = runnerLiteral;
if (parseIdentifierToValue(interpreter, &runnerLiteral)) {
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//run
if (runner->dirty) {
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
freeLiteral(runnerLiteral);
return -1;
}
unsigned char* bytecodeCopy = ALLOCATE(unsigned char, runner->size);
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
runner->dirty = true;
//cleanup
freeLiteral(runnerLiteral);
return 0;
}
static int nativeGetScriptVar(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
return -1;
}
//get the runner object
Literal varName = popLiteralArray(arguments);
Literal runnerLiteral = popLiteralArray(arguments);
if (IS_IDENTIFIER(varName)) {
Literal idn = varName;
parseIdentifierToValue(interpreter, &varName);
freeLiteral(idn);
}
if (IS_IDENTIFIER(runnerLiteral)) {
Literal idn = runnerLiteral;
parseIdentifierToValue(interpreter, &runnerLiteral);
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
freeLiteral(runnerLiteral);
return -1;
}
//get the desired variable
Literal varIdn = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(varName)));
Literal result = TO_NULL_LITERAL;
getScopeVariable(runner->interpreter.scope, varIdn, &result);
pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteral(result);
freeLiteral(varIdn);
freeLiteral(varName);
freeLiteral(runnerLiteral);
return 1;
}
static int nativeCallScriptFn(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
return -1;
}
//get the rest args
LiteralArray tmp;
initLiteralArray(&tmp);
while (arguments->count > 2) {
Literal lit = popLiteralArray(arguments);
pushLiteralArray(&tmp, lit);
freeLiteral(lit);
}
LiteralArray rest;
initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
Literal lit = popLiteralArray(&tmp);
pushLiteralArray(&rest, lit);
freeLiteral(lit);
}
freeLiteralArray(&tmp);
//get the runner object
Literal varName = popLiteralArray(arguments);
Literal runnerLiteral = popLiteralArray(arguments);
if (IS_IDENTIFIER(varName)) {
Literal idn = varName;
parseIdentifierToValue(interpreter, &varName);
freeLiteral(idn);
}
if (IS_IDENTIFIER(runnerLiteral)) {
Literal idn = runnerLiteral;
parseIdentifierToValue(interpreter, &runnerLiteral);
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
freeLiteral(runnerLiteral);
freeLiteralArray(&rest);
return -1;
}
//get the desired variable
Literal varIdn = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(varName)));
Literal fn = TO_NULL_LITERAL;
getScopeVariable(runner->interpreter.scope, varIdn, &fn);
if (!IS_FUNCTION(fn)) {
interpreter->errorOutput("Can't run a non-function literal\n");
freeLiteral(fn);
freeLiteral(varIdn);
freeLiteral(varName);
freeLiteral(runnerLiteral);
freeLiteralArray(&rest);
}
//call
LiteralArray resultArray;
initLiteralArray(&resultArray);
callLiteralFn(interpreter, fn, &rest, &resultArray);
Literal result = TO_NULL_LITERAL;
if (resultArray.count > 0) {
result = popLiteralArray(&resultArray);
}
pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteralArray(&resultArray);
freeLiteral(result);
freeLiteral(fn);
freeLiteral(varIdn);
freeLiteral(varName);
freeLiteral(runnerLiteral);
freeLiteralArray(&rest);
return 1;
}
static int nativeResetScript(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
return -1;
}
//get the runner object
Literal runnerLiteral = popLiteralArray(arguments);
if (IS_IDENTIFIER(runnerLiteral)) {
Literal idn = runnerLiteral;
parseIdentifierToValue(interpreter, &runnerLiteral);
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//reset
if (!runner->dirty) {
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
freeLiteral(runnerLiteral);
return -1;
}
resetInterpreter(&runner->interpreter);
runner->dirty = false;
freeLiteral(runnerLiteral);
return 0;
}
static int nativeFreeScript(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
return -1;
}
//get the runner object
Literal runnerLiteral = popLiteralArray(arguments);
if (IS_IDENTIFIER(runnerLiteral)) {
Literal idn = runnerLiteral;
parseIdentifierToValue(interpreter, &runnerLiteral);
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//clear out the runner object
runner->interpreter.hooks = NULL;
freeInterpreter(&runner->interpreter);
FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
FREE(Runner, runner);
freeLiteral(runnerLiteral);
return 0;
}
static int nativeCheckScriptDirty(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Literal runnerLiteral = popLiteralArray(arguments);
if (IS_IDENTIFIER(runnerLiteral)) {
Literal idn = runnerLiteral;
parseIdentifierToValue(interpreter, &runnerLiteral);
freeLiteral(idn);
}
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Runner* runner = AS_OPAQUE(runnerLiteral);
//run
Literal result = TO_BOOLEAN_LITERAL(runner->dirty);
pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteral(result);
freeLiteral(runnerLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
} Natives;
int hookRunner(Interpreter* interpreter, Literal identifier, Literal alias) {
//build the natives list
Natives natives[] = {
{"loadScript", nativeLoadScript},
{"loadScriptBytecode", nativeLoadScriptBytecode},
{"_runScript", nativeRunScript},
{"_getScriptVar", nativeGetScriptVar},
{"_callScriptFn", nativeCallScriptFn},
{"_resetScript", nativeResetScript},
{"_freeScript", nativeFreeScript},
{"_checkScriptDirty", nativeCheckScriptDirty},
{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(createRefString(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;
}
//file system API
static LiteralDictionary driveDictionary;
void initDriveDictionary() {
initLiteralDictionary(&driveDictionary);
}
void freeDriveDictionary() {
freeLiteralDictionary(&driveDictionary);
}
LiteralDictionary* getDriveDictionary() {
return &driveDictionary;
}

View File

@@ -1,12 +0,0 @@
#pragma once
#include "interpreter.h"
int hookRunner(Interpreter* interpreter, Literal identifier, Literal alias);
//file system API - these need to be set by the host
void initDriveDictionary();
void freeDriveDictionary();
LiteralDictionary* getDriveDictionary();
#define OPAQUE_TAG_RUNNER 100

View File

@@ -1,95 +0,0 @@
#include "lib_standard.h"
#include "memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
//no arguments
if (arguments->count != 0) {
interpreter->errorOutput("Incorrect number of arguments to clock\n");
return -1;
}
//get the time from C (what a pain)
time_t rawtime = time(NULL);
struct tm* timeinfo = localtime( &rawtime );
char* timestr = asctime(timeinfo);
//push to the stack
int len = strlen(timestr) - 1; //-1 for the newline
Literal timeLiteral = TO_STRING_LITERAL(createRefStringLength(timestr, len));
//push to the stack
pushLiteralArray(&interpreter->stack, timeLiteral);
//cleanup
freeLiteral(timeLiteral);
return 1;
}
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
} Natives;
int hookStandard(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(createRefString(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;
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include "interpreter.h"
int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias);

View File

@@ -1,412 +0,0 @@
#include "lib_timer.h"
#include "memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.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, &microsecondLiteral)) {
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(createRefStringLength(buffer, strlen(buffer)));
}
else { //normal case
char buffer[128];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TO_STRING_LITERAL(createRefStringLength(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(createRefString(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;
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include "interpreter.h"
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias);

View File

@@ -1,146 +0,0 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "console_colors.h"
#include "lexer.h"
#include "parser.h"
#include "compiler.h"
#include "interpreter.h"
#include <stdio.h>
#include <stdlib.h>
//IO functions
char* readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
return NULL;
}
fseek(file, 0L, SEEK_END);
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
if (buffer == NULL) {
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
return NULL;
}
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
if (bytesRead < *fileSize) {
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
return NULL;
}
fclose(file);
return buffer;
}
int writeFile(char* path, unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb");
if (file == NULL) {
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
return -1;
}
int written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, ERROR "Could not write file \"%s\"\n" RESET, path);
return -1;
}
fclose(file);
return 0;
}
//repl functions
unsigned char* compileString(char* source, size_t* size) {
Lexer lexer;
Parser parser;
Compiler compiler;
initLexer(&lexer, source);
initParser(&parser, &lexer);
initCompiler(&compiler);
//run the parser until the end of the source
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODE_ERROR) {
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeASTNode(node);
node = scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
//cleanup
freeCompiler(&compiler);
freeParser(&parser);
//no lexer to clean up
//finally
return tb;
}
void runBinary(unsigned char* tb, size_t size) {
Interpreter interpreter;
initInterpreter(&interpreter);
//inject the libs
injectNativeHook(&interpreter, "standard", hookStandard);
injectNativeHook(&interpreter, "timer", hookTimer);
injectNativeHook(&interpreter, "runner", hookRunner);
runInterpreter(&interpreter, tb, size);
freeInterpreter(&interpreter);
}
void runBinaryFile(char* fname) {
size_t size = 0; //not used
unsigned char* tb = (unsigned char*)readFile(fname, &size);
if (!tb) {
return;
}
runBinary(tb, size);
//interpreter takes ownership of the binary data
}
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);
}

View File

@@ -1,14 +0,0 @@
#pragma once
#include "toy_common.h"
char* readFile(char* path, size_t* fileSize);
int writeFile(char* path, unsigned char* bytes, size_t size);
unsigned char* compileString(char* source, size_t* size);
void runBinary(unsigned char* tb, size_t size);
void runBinaryFile(char* fname);
void runSource(char* source);
void runSourceFile(char* fname);

View File

@@ -1,9 +1,9 @@
export OUTDIR = out
export LIBDIR = lib
export TOY_OUTDIR = ../$(LIBDIR)
export CORE_OUTDIR = ../$(LIBDIR)
export BOX_OUTDIR = ../$(LIBDIR)
all: $(OUTDIR) $(LIBDIR) toy core
all: $(OUTDIR) $(LIBDIR) toy box
$(MAKE) -j8 -C source
ifeq ($(findstring CYGWIN, $(shell uname)),CYGWIN)
cp $(LIBDIR)/*.dll $(OUTDIR)
@@ -13,14 +13,14 @@ else ifeq ($(OS),Windows_NT)
cp $(LIBDIR)/*.dll $(OUTDIR)
endif
test: clean $(OUTDIR) toy core
test: clean $(OUTDIR) toy box
$(MAKE) -C test
toy: $(LIBDIR)
$(MAKE) -j8 -C Toy/source
core: $(LIBDIR)
$(MAKE) -j8 -C core
box: $(LIBDIR)
$(MAKE) -j8 -C box
$(OUTDIR):
mkdir $(OUTDIR)
@@ -69,10 +69,10 @@ $(SOURCEDIR):
mkdir $(SOURCEDIR)
sourcelist:
@echo $(addprefix ../airport/,$(wildcard Toy/source/*.c) $(wildcard core/*.c) $(wildcard source/*.c)) > source.list
@echo $(addprefix ../airport/,$(wildcard Toy/source/*.c) $(wildcard box/*.c) $(wildcard source/*.c)) > source.list
bundleincludes: $(INCLUDEDIR)
cp $(addprefix ../airport/,$(wildcard Toy/source/*.h) $(wildcard core/*.h) $(wildcard source/*.h)) $(INCLUDEDIR)
cp $(addprefix ../airport/,$(wildcard Toy/source/*.h) $(wildcard box/*.h) $(wildcard source/*.h)) $(INCLUDEDIR)
bundlesource: $(SOURCEDIR)
cp $(addprefix ../airport/,$(wildcard Toy/source/*.c) $(wildcard core/*.c) $(wildcard source/*.c)) $(SOURCEDIR)
cp $(addprefix ../airport/,$(wildcard Toy/source/*.c) $(wildcard box/*.c) $(wildcard source/*.c)) $(SOURCEDIR)

View File

@@ -1,8 +1,8 @@
CC=gcc
IDIR+=. ../Toy/source ../core
IDIR+=. ../Toy/source ../box
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-lSDL2 -ltoy -lcore
LIBS+=-lSDL2 -ltoy -lbox
ODIR = obj
SRC = $(wildcard *.c)

View File

@@ -1,13 +1,13 @@
CC=gcc
IDIR+=. ../Toy/source ../core
IDIR+=. ../Toy/source ../box
CFLAGS+=$(addprefix -I,$(IDIR)) -DSDL_MAIN_HANDLED -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-lSDL2 -lSDL2_image -ltoy -lcore
LIBS+=-lSDL2 -lSDL2_image -ltoy -lbox
ODIR = obj
TARGETS = $(wildcard ../core/*.c)
TARGETS = $(wildcard ../box/*.c)
TESTS = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../core/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
OBJ = $(addprefix $(ODIR)/,$(TARGETS:../box/%.c=%.o)) $(addprefix $(ODIR)/,$(TESTS:.c=.o))
.PRECIOUS: $(TESTS:%.c=../$(OUTDIR)/%.exe)
@@ -15,11 +15,11 @@ all: $(OBJ) $(TESTS:%.c=../$(OUTDIR)/%.exe)
../$(OUTDIR)/%.exe: $(ODIR)/%.o
ifeq ($(shell uname),Linux)
@$(CC) -o $@ $< $(TARGETS:../core/%.c=$(ODIR)/%.o) $(CFLAGS) -Wl,-rpath,../out -L../$(LIBDIR) $(LIBS)
@$(CC) -o $@ $< $(TARGETS:../box/%.c=$(ODIR)/%.o) $(CFLAGS) -Wl,-rpath,../out -L../$(LIBDIR) $(LIBS)
cp ../$(LIBDIR)/*.so ../$(OUTDIR)
valgrind --leak-check=full --track-origins=yes $@
else
@$(CC) -o $@ $< $(TARGETS:../core/%.c=$(ODIR)/%.o) $(CFLAGS) -L../$(LIBDIR) $(LIBS)
@$(CC) -o $@ $< $(TARGETS:../box/%.c=$(ODIR)/%.o) $(CFLAGS) -L../$(LIBDIR) $(LIBS)
cp ../$(LIBDIR)/*.dll ../$(OUTDIR)
$@
endif
@@ -32,7 +32,7 @@ $(ODIR):
$(ODIR)/%.o: %.c
@$(CC) -c -o $@ $< $(CFLAGS)
$(ODIR)/%.o: ../core/%.c
$(ODIR)/%.o: ../box/%.c
@$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean