Renamed everything to fit the new naming scheme

This commit is contained in:
2023-01-26 21:12:44 +00:00
parent 3e18baeec0
commit f7f9e75ad9
21 changed files with 1883 additions and 580 deletions

View File

@@ -1,4 +1,4 @@
#include "core_common.h"
#include "box_common.h"
STATIC_ASSERT(sizeof(char) == 1);
STATIC_ASSERT(sizeof(short) == 2);

View File

@@ -9,10 +9,10 @@
//platform exports/imports
#if defined(__linux__)
#define CORE_API extern
#define BOX_API extern
#else
#define CORE_API
#define BOX_API
#endif

View File

@@ -1,4 +1,4 @@
#include "engine.h"
#include "box_engine.h"
#include "lib_engine.h"
#include "lib_input.h"
@@ -8,31 +8,31 @@
#include "lib_runner.h"
#include "repl_tools.h"
#include "memory.h"
#include "lexer.h"
#include "parser.h"
#include "compiler.h"
#include "interpreter.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include "toy_memory.h"
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
#include "console_colors.h"
#include "toy_console_colors.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define the extern engine object
Engine engine;
Box_Engine engine;
//errors here should be fatal
static void fatalError(char* message) {
fprintf(stderr, "%s", message);
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, message);
exit(-1);
}
//exposed functions
void initEngine() {
void Box_initEngine() {
//clear
engine.rootNode = NULL;
engine.running = false;
@@ -45,45 +45,45 @@ void initEngine() {
}
//init events
initLiteralArray(&engine.keyDownEvents);
initLiteralDictionary(&engine.symKeyDownEvents);
initLiteralArray(&engine.keyUpEvents);
initLiteralDictionary(&engine.symKeyUpEvents);
Toy_initLiteralArray(&engine.keyDownEvents);
Toy_initLiteralDictionary(&engine.symKeyDownEvents);
Toy_initLiteralArray(&engine.keyUpEvents);
Toy_initLiteralDictionary(&engine.symKeyUpEvents);
//init Toy
initInterpreter(&engine.interpreter);
injectNativeHook(&engine.interpreter, "engine", hookEngine);
injectNativeHook(&engine.interpreter, "node", hookNode);
injectNativeHook(&engine.interpreter, "input", hookInput);
injectNativeHook(&engine.interpreter, "standard", hookStandard);
injectNativeHook(&engine.interpreter, "timer", hookTimer);
injectNativeHook(&engine.interpreter, "runner", hookRunner);
Toy_initInterpreter(&engine.interpreter);
Toy_injectNativeHook(&engine.interpreter, "engine", Box_hookEngine);
Toy_injectNativeHook(&engine.interpreter, "node", Box_hookNode);
Toy_injectNativeHook(&engine.interpreter, "input", Box_hookInput);
Toy_injectNativeHook(&engine.interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&engine.interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&engine.interpreter, "runner", Toy_hookRunner);
size_t size = 0;
char* source = readFile("./assets/scripts/init.toy", &size);
unsigned char* tb = compileString(source, &size);
char* source = Toy_readFile("./assets/scripts/init.toy", &size);
unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
runInterpreter(&engine.interpreter, tb, size);
Toy_runInterpreter(&engine.interpreter, tb, size);
}
void freeEngine() {
void Box_freeEngine() {
//clear existing root node
if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode);
Box_freeEngineNode(engine.rootNode);
engine.rootNode = NULL;
}
freeInterpreter(&engine.interpreter);
Toy_freeInterpreter(&engine.interpreter);
//free events
freeLiteralArray(&engine.keyDownEvents);
freeLiteralDictionary(&engine.symKeyDownEvents);
freeLiteralArray(&engine.keyUpEvents);
freeLiteralDictionary(&engine.symKeyUpEvents);
Toy_freeLiteralArray(&engine.keyDownEvents);
Toy_freeLiteralDictionary(&engine.symKeyDownEvents);
Toy_freeLiteralArray(&engine.keyUpEvents);
Toy_freeLiteralDictionary(&engine.symKeyUpEvents);
//free SDL
SDL_DestroyRenderer(engine.renderer);
@@ -97,13 +97,13 @@ void freeEngine() {
static void execEvents() {
//clear event lists
if (engine.keyDownEvents.count > 0) {
freeLiteralArray(&engine.keyDownEvents);
Toy_freeLiteralArray(&engine.keyDownEvents);
//NOTE: this is likely memory intensive - a more bespoke linked list designed for this task would be better
//NOTE: alternatively - manual memory-wipes, skipping the free step could be better
}
if (engine.keyUpEvents.count > 0) {
freeLiteralArray(&engine.keyUpEvents);
Toy_freeLiteralArray(&engine.keyUpEvents);
}
//poll all events
@@ -136,16 +136,16 @@ static void execEvents() {
}
//determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral)) {
Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!Toy_existsLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral)) {
break;
}
//get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral);
Toy_Literal eventLiteral = Toy_getLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral);
//push to the event list
pushLiteralArray(&engine.keyDownEvents, eventLiteral);
Toy_pushLiteralArray(&engine.keyDownEvents, eventLiteral);
}
break;
@@ -156,16 +156,16 @@ static void execEvents() {
}
//determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral)) {
Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!Toy_existsLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral)) {
break;
}
//get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral);
Toy_Literal eventLiteral = Toy_getLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral);
//push to the event list
pushLiteralArray(&engine.keyUpEvents, eventLiteral);
Toy_pushLiteralArray(&engine.keyUpEvents, eventLiteral);
}
break;
}
@@ -175,20 +175,20 @@ static void execEvents() {
if (engine.rootNode != NULL) {
//key down events
for (int i = 0; i < engine.keyDownEvents.count; i++) { //TODO: could pass in the whole array?
LiteralArray args;
initLiteralArray(&args);
pushLiteralArray(&args, engine.keyDownEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyDown", &args);
freeLiteralArray(&args);
Toy_LiteralArray args;
Toy_initLiteralArray(&args);
Toy_pushLiteralArray(&args, engine.keyDownEvents.literals[i]);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyDown", &args);
Toy_freeLiteralArray(&args);
}
//key up events
for (int i = 0; i < engine.keyUpEvents.count; i++) {
LiteralArray args;
initLiteralArray(&args);
pushLiteralArray(&args, engine.keyUpEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyUp", &args);
freeLiteralArray(&args);
Toy_LiteralArray args;
Toy_initLiteralArray(&args);
Toy_pushLiteralArray(&args, engine.keyUpEvents.literals[i]);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyUp", &args);
Toy_freeLiteralArray(&args);
}
}
}
@@ -196,12 +196,12 @@ static void execEvents() {
void execStep() {
if (engine.rootNode != NULL) {
//steps
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep", NULL);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep", NULL);
}
}
//the heart of the engine
void execEngine() {
void Box_execEngine() {
if (!engine.running) {
fatalError("Can't execute the engine (did you forget to initialize the screen?)");
}
@@ -236,7 +236,7 @@ void execEngine() {
SDL_SetRenderDrawColor(engine.renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later
SDL_RenderClear(engine.renderer); //NOTE: This line can be disabled later
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw", NULL);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw", NULL);
SDL_RenderPresent(engine.renderer);
}

View File

@@ -1,26 +1,24 @@
#pragma once
#include "core_common.h"
#include "engine_node.h"
#include "interpreter.h"
#include "box_common.h"
#include "box_engine_node.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include "core_common.h"
#include "toy_interpreter.h"
#include "toy_literal_array.h"
#include "toy_literal_dictionary.h"
#include <sys/time.h>
//the base engine object, which represents the state of the game
typedef struct _engine {
typedef struct Box_private_engine {
//engine stuff
EngineNode* rootNode;
Box_EngineNode* rootNode;
struct timeval simTime;
struct timeval realTime;
bool running;
//Toy stuff
Interpreter interpreter;
Toy_Interpreter interpreter;
//SDL stuff
SDL_Window* window;
@@ -29,18 +27,18 @@ typedef struct _engine {
int screenHeight;
//input syms mapped to events
LiteralArray keyDownEvents; //list of events that occurred this frame
LiteralDictionary symKeyDownEvents; //keysym -> event names
Toy_LiteralArray keyDownEvents; //list of events that occurred this frame
Toy_LiteralDictionary symKeyDownEvents; //keysym -> event names
LiteralArray keyUpEvents; //list of events that occurred this frame
LiteralDictionary symKeyUpEvents; //keysym -> event names
} Engine;
Toy_LiteralArray keyUpEvents; //list of events that occurred this frame
Toy_LiteralDictionary symKeyUpEvents; //keysym -> event names
} Box_Engine;
//extern singleton - used by various libraries
extern Engine engine;
extern Box_Engine engine;
//APIs for running the engine in main()
CORE_API void initEngine();
CORE_API void execEngine();
CORE_API void freeEngine();
BOX_API void Box_initEngine();
BOX_API void Box_execEngine();
BOX_API void Box_freeEngine();

View File

@@ -1,22 +1,21 @@
#include "engine_node.h"
#include "box_engine_node.h"
#include "box_engine.h"
#include "engine.h"
#include "memory.h"
#include "toy_memory.h"
static void freeMemory(void* ptr) {
EngineNode* node = (EngineNode*)ptr;
Box_EngineNode* node = (Box_EngineNode*)ptr;
//SDL stuff
SDL_DestroyTexture(node->texture);
//free this node type's memory
FREE(EngineNode, ptr);
TOY_FREE(Box_EngineNode, ptr);
}
void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size) {
void Box_initEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, void* tb, size_t size) {
//init
// node->freeMemory = freeMemory;
node->functions = ALLOCATE(LiteralDictionary, 1);
node->functions = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
node->parent = NULL;
node->tag = OPAQUE_TAG_ENGINE_NODE;
node->children = NULL;
@@ -24,36 +23,36 @@ void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t
node->count = 0;
node->texture = NULL;
initLiteralDictionary(node->functions);
Toy_initLiteralDictionary(node->functions);
//run bytecode
runInterpreter(interpreter, tb, size);
Toy_runInterpreter(interpreter, tb, size);
//grab all top-level functions from the dirty interpreter
LiteralDictionary* variablesPtr = &interpreter->scope->variables;
Toy_LiteralDictionary* variablesPtr = &interpreter->scope->variables;
for (int i = 0; i < variablesPtr->capacity; i++) {
//skip empties and tombstones
if (IS_NULL(variablesPtr->entries[i].key)) {
if (TOY_IS_NULL(variablesPtr->entries[i].key)) {
continue;
}
//if this variable is a function (this outmodes import and export)
_entry* entry = &variablesPtr->entries[i];
if (IS_FUNCTION(entry->value)) {
Toy_private_entry* entry = &variablesPtr->entries[i];
if (TOY_IS_FUNCTION(entry->value)) {
//save a copy
setLiteralDictionary(node->functions, entry->key, entry->value);
Toy_setLiteralDictionary(node->functions, entry->key, entry->value);
}
}
}
void pushEngineNode(EngineNode* node, EngineNode* child) {
void Box_pushEngineNode(Box_EngineNode* node, Box_EngineNode* child) {
//push to the array (prune tombstones when expanding/copying)
if (node->count + 1 > node->capacity) {
int oldCapacity = node->capacity;
node->capacity = GROW_CAPACITY(oldCapacity);
node->children = GROW_ARRAY(EngineNode*, node->children, oldCapacity, node->capacity);
node->capacity = TOY_GROW_CAPACITY(oldCapacity);
node->children = TOY_GROW_ARRAY(Box_EngineNode*, node->children, oldCapacity, node->capacity);
}
//prune tombstones (experimental)
@@ -77,22 +76,22 @@ void pushEngineNode(EngineNode* node, EngineNode* child) {
child->parent = node;
}
void freeEngineNode(EngineNode* node) {
void Box_freeEngineNode(Box_EngineNode* node) {
if (node == NULL) {
return; //NO-OP
}
//free and tombstone this node
for (int i = 0; i < node->count; i++) {
freeEngineNode(node->children[i]);
Box_freeEngineNode(node->children[i]);
}
//free the pointer array to the children
FREE_ARRAY(EngineNode*, node->children, node->capacity);
TOY_FREE_ARRAY(Box_EngineNode*, node->children, node->capacity);
if (node->functions != NULL) {
freeLiteralDictionary(node->functions);
FREE(LiteralDictionary, node->functions);
Toy_freeLiteralDictionary(node->functions);
TOY_FREE(Toy_LiteralDictionary, node->functions);
}
//free this node's memory
@@ -100,100 +99,100 @@ void freeEngineNode(EngineNode* node) {
freeMemory(node);
}
Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) {
Literal ret = TO_NULL_LITERAL;
Toy_Literal Box_callEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args) {
Toy_Literal ret = TOY_TO_NULL_LITERAL;
//if this fn exists
if (existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key);
Literal n = TO_OPAQUE_LITERAL(node, node->tag);
if (Toy_existsLiteralDictionary(node->functions, key)) {
Toy_Literal fn = Toy_getLiteralDictionary(node->functions, key);
Toy_Literal n = TOY_TO_OPAQUE_LITERAL(node, node->tag);
LiteralArray arguments;
LiteralArray returns;
initLiteralArray(&arguments);
initLiteralArray(&returns);
Toy_LiteralArray arguments;
Toy_LiteralArray returns;
Toy_initLiteralArray(&arguments);
Toy_initLiteralArray(&returns);
//feed the arguments in backwards!
if (args) {
for (int i = args->count -1; i >= 0; i--) {
pushLiteralArray(&arguments, args->literals[i]);
Toy_pushLiteralArray(&arguments, args->literals[i]);
}
}
pushLiteralArray(&arguments, n);
Toy_pushLiteralArray(&arguments, n);
callLiteralFn(interpreter, fn, &arguments, &returns);
Toy_callLiteralFn(interpreter, fn, &arguments, &returns);
ret = popLiteralArray(&returns);
ret = Toy_popLiteralArray(&returns);
freeLiteralArray(&arguments);
freeLiteralArray(&returns);
Toy_freeLiteralArray(&arguments);
Toy_freeLiteralArray(&returns);
freeLiteral(n);
freeLiteral(fn);
Toy_freeLiteral(n);
Toy_freeLiteral(fn);
}
return ret;
}
Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) {
Toy_Literal Box_callEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(createRefString(fnName));
Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(fnName));
Literal ret = callEngineNodeLiteral(node, interpreter, key, args);
Toy_Literal ret = Box_callEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key);
Toy_freeLiteral(key);
return ret;
}
void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) {
void Box_callRecursiveEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args) {
//if this fn exists
if (existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key);
Literal n = TO_OPAQUE_LITERAL(node, node->tag);
if (Toy_existsLiteralDictionary(node->functions, key)) {
Toy_Literal fn = Toy_getLiteralDictionary(node->functions, key);
Toy_Literal n = TOY_TO_OPAQUE_LITERAL(node, node->tag);
LiteralArray arguments;
LiteralArray returns;
initLiteralArray(&arguments);
initLiteralArray(&returns);
Toy_LiteralArray arguments;
Toy_LiteralArray returns;
Toy_initLiteralArray(&arguments);
Toy_initLiteralArray(&returns);
//feed the arguments in backwards!
if (args) {
for (int i = args->count -1; i >= 0; i--) {
pushLiteralArray(&arguments, args->literals[i]);
Toy_pushLiteralArray(&arguments, args->literals[i]);
}
}
pushLiteralArray(&arguments, n);
Toy_pushLiteralArray(&arguments, n);
callLiteralFn(interpreter, fn, &arguments, &returns);
Toy_callLiteralFn(interpreter, fn, &arguments, &returns);
freeLiteralArray(&arguments);
freeLiteralArray(&returns);
Toy_freeLiteralArray(&arguments);
Toy_freeLiteralArray(&returns);
freeLiteral(n);
freeLiteral(fn);
Toy_freeLiteral(n);
Toy_freeLiteral(fn);
}
//recurse to the (non-tombstone) children
for (int i = 0; i < node->count; i++) {
if (node->children[i] != NULL) {
callRecursiveEngineNodeLiteral(node->children[i], interpreter, key, args);
Box_callRecursiveEngineNodeLiteral(node->children[i], interpreter, key, args);
}
}
}
void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) {
void Box_callRecursiveEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(createRefString(fnName));
Toy_Literal key = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(fnName));
callRecursiveEngineNodeLiteral(node, interpreter, key, args);
Box_callRecursiveEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key);
Toy_freeLiteral(key);
}
int loadTextureEngineNode(EngineNode* node, char* fname) {
int Box_loadTextureEngineNode(Box_EngineNode* node, char* fname) {
SDL_Surface* surface = IMG_Load(fname);
if (surface == NULL) {
@@ -211,22 +210,22 @@ int loadTextureEngineNode(EngineNode* node, char* fname) {
int w, h;
SDL_QueryTexture(node->texture, NULL, NULL, &w, &h);
SDL_Rect r = { 0, 0, w, h };
setRectEngineNode(node, r);
Box_setRectEngineNode(node, r);
return 0;
}
void freeTextureEngineNode(EngineNode* node) {
void Box_freeTextureEngineNode(Box_EngineNode* node) {
if (node->texture != NULL) {
SDL_DestroyTexture(node->texture);
node->texture = NULL;
}
}
void setRectEngineNode(EngineNode* node, SDL_Rect rect) {
void Box_setRectEngineNode(Box_EngineNode* node, SDL_Rect rect) {
node->rect = rect;
}
void drawEngineNode(EngineNode* node, SDL_Rect dest) {
void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest) {
SDL_RenderCopy(engine.renderer, node->texture, &node->rect, &dest);
}

View File

@@ -1,33 +1,33 @@
#pragma once
#include "core_common.h"
#include "box_common.h"
#include "literal_dictionary.h"
#include "interpreter.h"
#include "toy_literal_dictionary.h"
#include "toy_interpreter.h"
#define OPAQUE_TAG_ENGINE_NODE 1001
//forward declare
typedef struct _engineNode EngineNode;
typedef struct Box_private_engineNode Box_EngineNode;
// typedef void (*EngineNodeCallback)(void*);
//the node object, which forms a tree
typedef struct _engineNode {
typedef struct Box_private_engineNode {
//function for releasing memory NOTE: removed, because it's not needed with only 1 node type - I've left them commented out because I might need them soon
// EngineNodeCallback freeMemory;
//toy functions, stored in a dict for flexibility
LiteralDictionary* functions;
Toy_LiteralDictionary* functions;
//point to the parent
EngineNode* parent;
Box_EngineNode* parent;
//my opaque type tag
int tag;
int _unused0;
//use Toy's memory model
EngineNode** children;
Box_EngineNode** children;
int capacity;
int count; //includes tombstones
@@ -35,21 +35,21 @@ typedef struct _engineNode {
SDL_Texture* texture;
SDL_Rect rect;
//TODO: depth
} EngineNode;
} Box_EngineNode;
CORE_API void initEngineNode(EngineNode* node, Interpreter* interpreter, void* tb, size_t size); //run bytecode, then grab all top-level function literals
CORE_API void pushEngineNode(EngineNode* node, EngineNode* child); //push to the array (prune tombstones when expanding/copying)
CORE_API void freeEngineNode(EngineNode* node); //free and tombstone this node
BOX_API void Box_initEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, void* tb, size_t size); //run bytecode, then grab all top-level function literals
BOX_API void Box_pushEngineNode(Box_EngineNode* node, Box_EngineNode* child); //push to the array (prune tombstones when expanding/copying)
BOX_API void Box_freeEngineNode(Box_EngineNode* node); //free and tombstone this node
CORE_API Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args);
CORE_API Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and only this node, if it exists
BOX_API Toy_Literal Box_callEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args);
BOX_API Toy_Literal Box_callEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args); //call "fnName" on this node, and only this node, if it exists
CORE_API void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args);
CORE_API void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and all children, if it exists
BOX_API void Box_callRecursiveEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* interpreter, Toy_Literal key, Toy_LiteralArray* args);
BOX_API void Box_callRecursiveEngineNode(Box_EngineNode* node, Toy_Interpreter* interpreter, char* fnName, Toy_LiteralArray* args); //call "fnName" on this node, and all children, if it exists
CORE_API int loadTextureEngineNode(EngineNode* node, char* fname);
CORE_API void freeTextureEngineNode(EngineNode* node);
BOX_API int Box_loadTextureEngineNode(Box_EngineNode* node, char* fname);
BOX_API void Box_freeTextureEngineNode(Box_EngineNode* node);
CORE_API void setRectEngineNode(EngineNode* node, SDL_Rect rect);
BOX_API void Box_setRectEngineNode(Box_EngineNode* node, SDL_Rect rect);
//TODO: getRect
CORE_API void drawEngineNode(EngineNode* node, SDL_Rect dest);
BOX_API void Box_drawEngineNode(Box_EngineNode* node, SDL_Rect dest);

View File

@@ -1,19 +1,21 @@
#include "lib_engine.h"
#include "engine.h"
#include "repl_tools.h"
#include "box_engine.h"
#include "memory.h"
#include "literal_array.h"
#include "repl_tools.h"
#include "toy_memory.h"
#include "toy_literal_array.h"
#include "toy_console_colors.h"
//errors here should be fatal
static void fatalError(char* message) {
fprintf(stderr, "%s", message);
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, message);
exit(-1);
}
//native functions to be called
static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeInitWindow(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (engine.window != NULL) {
fatalError("Can't re-initialize the window\n");
}
@@ -23,24 +25,24 @@ static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
}
//extract the arguments
Literal fscreen = popLiteralArray(arguments);
Literal screenHeight = popLiteralArray(arguments);
Literal screenWidth = popLiteralArray(arguments);
Literal caption = popLiteralArray(arguments);
Toy_Literal fscreen = Toy_popLiteralArray(arguments);
Toy_Literal screenHeight = Toy_popLiteralArray(arguments);
Toy_Literal screenWidth = Toy_popLiteralArray(arguments);
Toy_Literal caption = Toy_popLiteralArray(arguments);
//check argument types
if (!IS_STRING(caption) || !IS_INTEGER(screenWidth) || !IS_INTEGER(screenHeight) || !IS_BOOLEAN(fscreen)) {
if (!TOY_IS_STRING(caption) || !TOY_IS_INTEGER(screenWidth) || !TOY_IS_INTEGER(screenHeight) || !TOY_IS_BOOLEAN(fscreen)) {
fatalError("Incorrect argument type passed to initEngine\n");
}
//init the window
engine.window = SDL_CreateWindow(
toCString(AS_STRING(caption)),
Toy_toCString(TOY_AS_STRING(caption)),
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
engine.screenWidth = AS_INTEGER(screenWidth),
engine.screenHeight = AS_INTEGER(screenHeight),
IS_TRUTHY(fscreen) ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE
engine.screenWidth = TOY_AS_INTEGER(screenWidth),
engine.screenHeight = TOY_AS_INTEGER(screenHeight),
TOY_IS_TRUTHY(fscreen) ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE
);
if (engine.window == NULL) {
@@ -66,81 +68,81 @@ static int nativeInitWindow(Interpreter* interpreter, LiteralArray* arguments) {
//only run with a window
engine.running = true;
freeLiteral(caption);
freeLiteral(screenWidth);
freeLiteral(screenHeight);
freeLiteral(fscreen);
Toy_freeLiteral(caption);
Toy_freeLiteral(screenWidth);
Toy_freeLiteral(screenHeight);
Toy_freeLiteral(fscreen);
return 0;
}
//TODO: perhaps a returns argument would be better?
static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeLoadRootNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to loadRootNode\n");
return -1;
}
//extract the arguments
Literal fname = popLiteralArray(arguments);
Toy_Literal fname = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn);
Toy_Literal fnameIdn = fname;
if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
Toy_freeLiteral(fnameIdn);
}
//check argument types
if (!IS_STRING(fname)) {
if (!TOY_IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n");
freeLiteral(fname);
Toy_freeLiteral(fname);
return -1;
}
//clear existing root node
if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
Box_callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode);
FREE(EngineNode, engine.rootNode);
Box_freeEngineNode(engine.rootNode);
TOY_FREE(Box_EngineNode, engine.rootNode);
engine.rootNode = NULL;
}
//load the new root node
size_t size = 0;
char* source = readFile(toCString(AS_STRING(fname)), &size);
unsigned char* tb = compileString(source, &size);
char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size);
unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
engine.rootNode = ALLOCATE(EngineNode, 1);
engine.rootNode = TOY_ALLOCATE(Box_EngineNode, 1);
//BUGFIX: make an inner-interpreter
Interpreter inner;
Toy_Interpreter inner;
//init the inner interpreter manually
initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL);
Toy_initLiteralArray(&inner.literalCache);
inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb;
inner.length = size;
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
inner.panic = false;
initLiteralArray(&inner.stack);
Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput);
Toy_setInterpreterPrint(&inner, interpreter->printOutput);
Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
Toy_setInterpreterError(&inner, interpreter->errorOutput);
initEngineNode(engine.rootNode, &inner, tb, size);
Box_initEngineNode(engine.rootNode, &inner, tb, size);
//init the new node (and ONLY this node)
callEngineNode(engine.rootNode, &engine.interpreter, "onInit", NULL);
Box_callEngineNode(engine.rootNode, &engine.interpreter, "onInit", NULL);
//cleanup
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
freeLiteral(fname);
Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache);
Toy_freeLiteral(fname);
return 0;
}
@@ -148,10 +150,10 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
Toy_NativeFn fn;
} Natives;
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
int Box_hookEngine(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"initWindow", nativeInitWindow},
@@ -160,51 +162,51 @@ int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias) {
};
//store the library in an aliased dictionary
if (!IS_NULL(alias)) {
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias);
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_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;
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func);
Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name);
freeLiteral(func);
Toy_freeLiteral(name);
Toy_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);
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false);
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
freeLiteral(dict);
freeLiteral(type);
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "interpreter.h"
#include "toy_interpreter.h"
int hookEngine(Interpreter* interpreter, Literal identifier, Literal alias);
int Box_hookEngine(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

View File

@@ -1,11 +1,11 @@
#include "lib_input.h"
#include "memory.h"
#include "box_common.h"
#include "box_engine.h"
#include "engine.h"
#include "core_common.h"
#include "toy_memory.h"
static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* arguments, LiteralDictionary* symKeyEventsPtr, char* fnName) {
static int nativeMapInputEventToKey(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments, Toy_LiteralDictionary* symKeyEventsPtr, char* fnName) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to ");
@@ -14,26 +14,26 @@ static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* argu
return -1;
}
Literal symLiteral = popLiteralArray(arguments);
Literal evtLiteral = popLiteralArray(arguments);
Toy_Literal symLiteral = Toy_popLiteralArray(arguments);
Toy_Literal evtLiteral = Toy_popLiteralArray(arguments);
Literal evtLiteralIdn = evtLiteral;
if (IS_IDENTIFIER(evtLiteral) && parseIdentifierToValue(interpreter, &evtLiteral)) {
freeLiteral(evtLiteralIdn);
Toy_Literal evtLiteralIdn = evtLiteral;
if (TOY_IS_IDENTIFIER(evtLiteral) && Toy_parseIdentifierToValue(interpreter, &evtLiteral)) {
Toy_freeLiteral(evtLiteralIdn);
}
Literal symLiteralIdn = symLiteral;
if (IS_IDENTIFIER(symLiteral) && parseIdentifierToValue(interpreter, &symLiteral)) {
freeLiteral(symLiteralIdn);
Toy_Literal symLiteralIdn = symLiteral;
if (TOY_IS_IDENTIFIER(symLiteral) && Toy_parseIdentifierToValue(interpreter, &symLiteral)) {
Toy_freeLiteral(symLiteralIdn);
}
if (!IS_STRING(symLiteral) || !IS_STRING(evtLiteral)) {
if (!TOY_IS_STRING(symLiteral) || !TOY_IS_STRING(evtLiteral)) {
interpreter->errorOutput("Incorrect type of arguments passed to mapInputEventToKey\n");
return -1;
}
//use the keycode for faster lookups
SDL_Keycode keycode = SDL_GetKeyFromName( toCString(AS_STRING(symLiteral)) );
SDL_Keycode keycode = SDL_GetKeyFromName( Toy_toCString(TOY_AS_STRING(symLiteral)) );
if (keycode == SDLK_UNKNOWN) {
interpreter->errorOutput("Unknown key found: ");
@@ -42,35 +42,35 @@ static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* argu
return -1;
}
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)keycode );
Toy_Literal keycodeLiteral = TOY_TO_INTEGER_LITERAL( (int)keycode );
//save the sym-event pair
setLiteralDictionary(symKeyEventsPtr, keycodeLiteral, evtLiteral); //I could possibly map multiple events to one sym
Toy_setLiteralDictionary(symKeyEventsPtr, keycodeLiteral, evtLiteral); //I could possibly map multiple events to one sym
//cleanup
freeLiteral(symLiteral);
freeLiteral(evtLiteral);
freeLiteral(keycodeLiteral);
Toy_freeLiteral(symLiteral);
Toy_freeLiteral(evtLiteral);
Toy_freeLiteral(keycodeLiteral);
return 0;
}
//dry wrappers
static int nativeMapInputEventToKeyDown(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeMapInputEventToKeyDown(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyDownEvents, "mapInputEventToKeyDown");
}
static int nativeMapInputEventToKeyUp(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeMapInputEventToKeyUp(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyUpEvents, "mapInputEventToKeyUp");
}
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
Toy_NativeFn fn;
} Natives;
int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) {
int Box_hookInput(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"mapInputEventToKeyDown", nativeMapInputEventToKeyDown},
@@ -80,51 +80,51 @@ int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) {
};
//store the library in an aliased dictionary
if (!IS_NULL(alias)) {
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias);
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_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;
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func);
Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name);
freeLiteral(func);
Toy_freeLiteral(name);
Toy_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);
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false);
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
freeLiteral(dict);
freeLiteral(type);
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "interpreter.h"
#include "toy_interpreter.h"
int hookInput(Interpreter* interpreter, Literal identifier, Literal alias);
int Box_hookInput(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

View File

@@ -1,604 +1,604 @@
#include "lib_node.h"
#include "engine.h"
#include "engine_node.h"
#include "repl_tools.h"
#include "box_engine_node.h"
#include "box_engine.h"
#include "memory.h"
#include "literal_array.h"
#include "repl_tools.h"
#include "toy_literal_array.h"
#include "toy_memory.h"
#include <stdlib.h>
static int nativeLoadNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to loadNode\n");
return -1;
}
//extract the arguments
Literal fname = popLiteralArray(arguments);
Toy_Literal fname = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn);
Toy_Literal fnameIdn = fname;
if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
Toy_freeLiteral(fnameIdn);
}
//check argument types
if (!IS_STRING(fname)) {
if (!TOY_IS_STRING(fname)) {
interpreter->errorOutput("Incorrect argument type passed to loadNode\n");
freeLiteral(fname);
Toy_freeLiteral(fname);
return -1;
}
//load the new node
size_t size = 0;
char* source = readFile(toCString(AS_STRING(fname)), &size);
unsigned char* tb = compileString(source, &size);
char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size);
unsigned char* tb = Toy_compileString(source, &size);
free((void*)source);
EngineNode* node = ALLOCATE(EngineNode, 1);
Box_EngineNode* node = TOY_ALLOCATE(Box_EngineNode, 1);
//BUGFIX: make an inner-interpreter
Interpreter inner;
Toy_Interpreter inner;
//init the inner interpreter manually
initLiteralArray(&inner.literalCache);
inner.scope = pushScope(NULL);
Toy_initLiteralArray(&inner.literalCache);
inner.scope = Toy_pushScope(NULL);
inner.bytecode = tb;
inner.length = size;
inner.count = 0;
inner.codeStart = -1;
inner.depth = interpreter->depth + 1;
inner.panic = false;
initLiteralArray(&inner.stack);
Toy_initLiteralArray(&inner.stack);
inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput);
Toy_setInterpreterPrint(&inner, interpreter->printOutput);
Toy_setInterpreterAssert(&inner, interpreter->assertOutput);
Toy_setInterpreterError(&inner, interpreter->errorOutput);
initEngineNode(node, &inner, tb, size);
Box_initEngineNode(node, &inner, tb, size);
// return the node
Literal nodeLiteral = TO_OPAQUE_LITERAL(node, node->tag);
pushLiteralArray(&interpreter->stack, nodeLiteral);
Toy_Literal nodeLiteral = TOY_TO_OPAQUE_LITERAL(node, node->tag);
Toy_pushLiteralArray(&interpreter->stack, nodeLiteral);
//cleanup
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
freeLiteral(fname);
freeLiteral(nodeLiteral);
Toy_freeLiteralArray(&inner.stack);
Toy_freeLiteralArray(&inner.literalCache);
Toy_freeLiteral(fname);
Toy_freeLiteral(nodeLiteral);
return 1;
}
static int nativeInitNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeInitNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to initNode\n");
return -1;
}
Literal node = popLiteralArray(arguments);
Toy_Literal node = Toy_popLiteralArray(arguments);
Literal nodeIdn = node;
if (IS_IDENTIFIER(node) && parseIdentifierToValue(interpreter, &node)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = node;
if (TOY_IS_IDENTIFIER(node) && Toy_parseIdentifierToValue(interpreter, &node)) {
Toy_freeLiteral(nodeIdn);
}
//check argument types
if (!IS_OPAQUE(node)) {
if (!TOY_IS_OPAQUE(node)) {
interpreter->errorOutput("Incorrect argument type passed to initNode\n");
freeLiteral(node);
Toy_freeLiteral(node);
return -1;
}
EngineNode* engineNode = AS_OPAQUE(node);
Box_EngineNode* engineNode = TOY_AS_OPAQUE(node);
//init the new node (and ONLY this node)
callEngineNode(engineNode, &engine.interpreter, "onInit", NULL);
Box_callEngineNode(engineNode, &engine.interpreter, "onInit", NULL);
//cleanup
freeLiteral(node);
Toy_freeLiteral(node);
return 0;
}
static int nativeFreeChildNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeFreeChildNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to freeChildNode\n");
return -1;
}
Literal index = popLiteralArray(arguments);
Literal node = popLiteralArray(arguments);
Toy_Literal index = Toy_popLiteralArray(arguments);
Toy_Literal node = Toy_popLiteralArray(arguments);
Literal nodeIdn = node; //annoying
if (IS_IDENTIFIER(node) && parseIdentifierToValue(interpreter, &node)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = node; //annoying
if (TOY_IS_IDENTIFIER(node) && Toy_parseIdentifierToValue(interpreter, &node)) {
Toy_freeLiteral(nodeIdn);
}
//check argument types
if (!IS_OPAQUE(node) || !IS_INTEGER(index)) {
if (!TOY_IS_OPAQUE(node) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to freeChildNode\n");
freeLiteral(node);
Toy_freeLiteral(node);
return -1;
}
EngineNode* parentNode = AS_OPAQUE(node);
int idx = AS_INTEGER(index);
Box_EngineNode* parentNode = TOY_AS_OPAQUE(node);
int idx = TOY_AS_INTEGER(index);
//check bounds
if (idx < 0 || idx >= parentNode->count) {
interpreter->errorOutput("Node index out of bounds in freeChildNode\n");
freeLiteral(node);
freeLiteral(index);
Toy_freeLiteral(node);
Toy_freeLiteral(index);
return -1;
}
//get the child node
EngineNode* childNode = parentNode->children[idx];
Box_EngineNode* childNode = parentNode->children[idx];
//free the node
if (childNode != NULL) {
callRecursiveEngineNode(childNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(childNode);
Box_callRecursiveEngineNode(childNode, &engine.interpreter, "onFree", NULL);
Box_freeEngineNode(childNode);
}
parentNode->children[idx] = NULL;
//cleanup
freeLiteral(node);
freeLiteral(index);
Toy_freeLiteral(node);
Toy_freeLiteral(index);
return 0;
}
static int nativePushNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativePushNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to pushNode\n");
return -1;
}
Literal child = popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments);
Toy_Literal child = Toy_popLiteralArray(arguments);
Toy_Literal parent = Toy_popLiteralArray(arguments);
Literal parentIdn = parent;
if (IS_IDENTIFIER(parent) && parseIdentifierToValue(interpreter, &parent)) {
freeLiteral(parentIdn);
Toy_Literal parentIdn = parent;
if (TOY_IS_IDENTIFIER(parent) && Toy_parseIdentifierToValue(interpreter, &parent)) {
Toy_freeLiteral(parentIdn);
}
Literal childIdn = child;
if (IS_IDENTIFIER(child) && parseIdentifierToValue(interpreter, &child)) {
freeLiteral(childIdn);
Toy_Literal childIdn = child;
if (TOY_IS_IDENTIFIER(child) && Toy_parseIdentifierToValue(interpreter, &child)) {
Toy_freeLiteral(childIdn);
}
if (!IS_OPAQUE(parent) || !IS_OPAQUE(child)) {
if (!TOY_IS_OPAQUE(parent) || !TOY_IS_OPAQUE(child)) {
interpreter->errorOutput("Incorrect argument type passed to pushNode\n");
freeLiteral(parent);
freeLiteral(child);
Toy_freeLiteral(parent);
Toy_freeLiteral(child);
return -1;
}
//push the node
EngineNode* parentNode = AS_OPAQUE(parent);
EngineNode* childNode = AS_OPAQUE(child);
Box_EngineNode* parentNode = TOY_AS_OPAQUE(parent);
Box_EngineNode* childNode = TOY_AS_OPAQUE(child);
pushEngineNode(parentNode, childNode);
Box_pushEngineNode(parentNode, childNode);
//no return value
freeLiteral(parent);
freeLiteral(child);
Toy_freeLiteral(parent);
Toy_freeLiteral(child);
return 0;
}
static int nativeGetNodeChild(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to getNode\n");
return -1;
}
Literal index = popLiteralArray(arguments);
Literal parent = popLiteralArray(arguments);
Toy_Literal index = Toy_popLiteralArray(arguments);
Toy_Literal parent = Toy_popLiteralArray(arguments);
Literal parentIdn = parent;
if (IS_IDENTIFIER(parent) && parseIdentifierToValue(interpreter, &parent)) {
freeLiteral(parentIdn);
Toy_Literal parentIdn = parent;
if (TOY_IS_IDENTIFIER(parent) && Toy_parseIdentifierToValue(interpreter, &parent)) {
Toy_freeLiteral(parentIdn);
}
if (!IS_OPAQUE(parent) || !IS_INTEGER(index)) {
if (!TOY_IS_OPAQUE(parent) || !TOY_IS_INTEGER(index)) {
interpreter->errorOutput("Incorrect argument type passed to getNode\n");
freeLiteral(parent);
freeLiteral(index);
Toy_freeLiteral(parent);
Toy_freeLiteral(index);
return -1;
}
//push the node
EngineNode* parentNode = AS_OPAQUE(parent);
int intIndex = AS_INTEGER(index);
Box_EngineNode* parentNode = TOY_AS_OPAQUE(parent);
int intIndex = TOY_AS_INTEGER(index);
if (intIndex < 0 || intIndex >= parentNode->count) {
interpreter->errorOutput("index out of bounds in getNode\n");
freeLiteral(parent);
freeLiteral(index);
Toy_freeLiteral(parent);
Toy_freeLiteral(index);
return -1;
}
EngineNode* childNode = parentNode->children[intIndex];
Literal child = TO_OPAQUE_LITERAL(childNode, childNode->tag);
Box_EngineNode* childNode = parentNode->children[intIndex];
Toy_Literal child = TOY_TO_OPAQUE_LITERAL(childNode, childNode->tag);
pushLiteralArray(&interpreter->stack, child);
Toy_pushLiteralArray(&interpreter->stack, child);
//no return value
freeLiteral(parent);
freeLiteral(child);
freeLiteral(index);
Toy_freeLiteral(parent);
Toy_freeLiteral(child);
Toy_freeLiteral(index);
return 1;
}
static int nativeGetNodeParent(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeGetNodeParent(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to getNodeParent\n");
return -1;
}
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
if (!IS_OPAQUE(nodeLiteral)) {
if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeParent\n");
freeLiteral(nodeLiteral);
Toy_freeLiteral(nodeLiteral);
return -1;
}
//push the node
EngineNode* node = AS_OPAQUE(nodeLiteral);
EngineNode* parent = node->parent;
Box_EngineNode* node = TOY_AS_OPAQUE(nodeLiteral);
Box_EngineNode* parent = node->parent;
Literal parentLiteral = TO_NULL_LITERAL;
Toy_Literal parentLiteral = TOY_TO_NULL_LITERAL;
if (parent != NULL) {
parentLiteral = TO_OPAQUE_LITERAL(parent, parent->tag);
parentLiteral = TOY_TO_OPAQUE_LITERAL(parent, parent->tag);
}
pushLiteralArray(&interpreter->stack, parentLiteral);
Toy_pushLiteralArray(&interpreter->stack, parentLiteral);
//cleanup
freeLiteral(parentLiteral);
freeLiteral(nodeLiteral);
Toy_freeLiteral(parentLiteral);
Toy_freeLiteral(nodeLiteral);
return 1;
}
static int nativeLoadTexture(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeLoadTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to loadTextureEngineNode\n");
return -1;
}
//extract the arguments
Literal fname = popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal fname = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal fnameIdn = fname;
if (IS_IDENTIFIER(fname) && parseIdentifierToValue(interpreter, &fname)) {
freeLiteral(fnameIdn);
Toy_Literal fnameIdn = fname;
if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) {
Toy_freeLiteral(fnameIdn);
}
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
//check argument types
if (!IS_STRING(fname) || !IS_OPAQUE(nodeLiteral)) {
if (!TOY_IS_STRING(fname) || !TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to loadTextureEngineNode\n");
freeLiteral(fname);
freeLiteral(nodeLiteral);
Toy_freeLiteral(fname);
Toy_freeLiteral(nodeLiteral);
return -1;
}
//actually load TODO: number the opaques, and check the numbers
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral);
Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
if (node->texture != NULL) {
freeTextureEngineNode(node);
Box_freeTextureEngineNode(node);
}
if (loadTextureEngineNode(node, toCString(AS_STRING(fname))) != 0) {
if (Box_loadTextureEngineNode(node, Toy_toCString(TOY_AS_STRING(fname))) != 0) {
interpreter->errorOutput("Failed to load the texture into the EngineNode\n");
freeLiteral(fname);
freeLiteral(nodeLiteral);
Toy_freeLiteral(fname);
Toy_freeLiteral(nodeLiteral);
return -1;
}
//cleanup
freeLiteral(fname);
freeLiteral(nodeLiteral);
Toy_freeLiteral(fname);
Toy_freeLiteral(nodeLiteral);
return 0;
}
static int nativeFreeTexture(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeFreeTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to freeTextureEngineNode\n");
return -1;
}
//extract the arguments
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
//check argument types
if (!IS_OPAQUE(nodeLiteral)) {
if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to freeTextureEngineNode\n");
freeLiteral(nodeLiteral);
Toy_freeLiteral(nodeLiteral);
return -1;
}
//actually load TODO: number the opaques, and check the numbers
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral);
Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
if (node->texture != NULL) {
freeTextureEngineNode(node);
Box_freeTextureEngineNode(node);
}
//cleanup
freeLiteral(nodeLiteral);
Toy_freeLiteral(nodeLiteral);
return 0;
}
static int nativeSetRect(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeSetRect(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 5) {
interpreter->errorOutput("Incorrect number of arguments passed to setRectEngineNode\n");
return -1;
}
//extract the arguments
Literal h = popLiteralArray(arguments);
Literal w = popLiteralArray(arguments);
Literal y = popLiteralArray(arguments);
Literal x = popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal h = Toy_popLiteralArray(arguments);
Toy_Literal w = Toy_popLiteralArray(arguments);
Toy_Literal y = Toy_popLiteralArray(arguments);
Toy_Literal x = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
Literal xi = x;
if (IS_IDENTIFIER(x) && parseIdentifierToValue(interpreter, &x)) {
freeLiteral(xi);
Toy_Literal xi = x;
if (TOY_IS_IDENTIFIER(x) && Toy_parseIdentifierToValue(interpreter, &x)) {
Toy_freeLiteral(xi);
}
Literal yi = y;
if (IS_IDENTIFIER(y) && parseIdentifierToValue(interpreter, &y)) {
freeLiteral(yi);
Toy_Literal yi = y;
if (TOY_IS_IDENTIFIER(y) && Toy_parseIdentifierToValue(interpreter, &y)) {
Toy_freeLiteral(yi);
}
Literal wi = w;
if (IS_IDENTIFIER(w) && parseIdentifierToValue(interpreter, &w)) {
freeLiteral(wi);
Toy_Literal wi = w;
if (TOY_IS_IDENTIFIER(w) && Toy_parseIdentifierToValue(interpreter, &w)) {
Toy_freeLiteral(wi);
}
Literal hi = h;
if (IS_IDENTIFIER(h) && parseIdentifierToValue(interpreter, &h)) {
freeLiteral(hi);
Toy_Literal hi = h;
if (TOY_IS_IDENTIFIER(h) && Toy_parseIdentifierToValue(interpreter, &h)) {
Toy_freeLiteral(hi);
}
//check argument types
if (!IS_OPAQUE(nodeLiteral) || !IS_INTEGER(x) || !IS_INTEGER(y) || !IS_INTEGER(w) || !IS_INTEGER(h)) {
if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_INTEGER(x) || !TOY_IS_INTEGER(y) || !TOY_IS_INTEGER(w) || !TOY_IS_INTEGER(h)) {
interpreter->errorOutput("Incorrect argument type passed to setRectEngineNode\n");
freeLiteral(nodeLiteral);
freeLiteral(x);
freeLiteral(y);
freeLiteral(w);
freeLiteral(h);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(x);
Toy_freeLiteral(y);
Toy_freeLiteral(w);
Toy_freeLiteral(h);
return -1;
}
//actually set
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral);
Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
SDL_Rect r = {AS_INTEGER(x), AS_INTEGER(y), AS_INTEGER(w), AS_INTEGER(h)};
setRectEngineNode(node, r);
SDL_Rect r = {TOY_AS_INTEGER(x), TOY_AS_INTEGER(y), TOY_AS_INTEGER(w), TOY_AS_INTEGER(h)};
Box_setRectEngineNode(node, r);
//cleanup
freeLiteral(nodeLiteral);
freeLiteral(x);
freeLiteral(y);
freeLiteral(w);
freeLiteral(h);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(x);
Toy_freeLiteral(y);
Toy_freeLiteral(w);
Toy_freeLiteral(h);
return 0;
}
//TODO: get x, y, w, h
static int nativeDrawNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 3 && arguments->count != 5) {
interpreter->errorOutput("Incorrect number of arguments passed to drawEngineNode\n");
return -1;
}
//extract the arguments
Literal w = TO_NULL_LITERAL, h = TO_NULL_LITERAL;
Toy_Literal w = TOY_TO_NULL_LITERAL, h = TOY_TO_NULL_LITERAL;
if (arguments->count == 5) {
h = popLiteralArray(arguments);
w = popLiteralArray(arguments);
h = Toy_popLiteralArray(arguments);
w = Toy_popLiteralArray(arguments);
}
Literal y = popLiteralArray(arguments);
Literal x = popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal y = Toy_popLiteralArray(arguments);
Toy_Literal x = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
Literal xi = x;
if (IS_IDENTIFIER(x) && parseIdentifierToValue(interpreter, &x)) {
freeLiteral(xi);
Toy_Literal xi = x;
if (TOY_IS_IDENTIFIER(x) && Toy_parseIdentifierToValue(interpreter, &x)) {
Toy_freeLiteral(xi);
}
Literal yi = y;
if (IS_IDENTIFIER(y) && parseIdentifierToValue(interpreter, &y)) {
freeLiteral(yi);
Toy_Literal yi = y;
if (TOY_IS_IDENTIFIER(y) && Toy_parseIdentifierToValue(interpreter, &y)) {
Toy_freeLiteral(yi);
}
Literal wi = w;
if (IS_IDENTIFIER(w) && parseIdentifierToValue(interpreter, &w)) {
freeLiteral(wi);
Toy_Literal wi = w;
if (TOY_IS_IDENTIFIER(w) && Toy_parseIdentifierToValue(interpreter, &w)) {
Toy_freeLiteral(wi);
}
Literal hi = h;
if (IS_IDENTIFIER(h) && parseIdentifierToValue(interpreter, &h)) {
freeLiteral(hi);
Toy_Literal hi = h;
if (TOY_IS_IDENTIFIER(h) && Toy_parseIdentifierToValue(interpreter, &h)) {
Toy_freeLiteral(hi);
}
//check argument types
if (!IS_OPAQUE(nodeLiteral) || !IS_INTEGER(x) || !IS_INTEGER(y) || (!IS_INTEGER(w) && !IS_NULL(w)) || (!IS_INTEGER(h) && !IS_NULL(h))) {
if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_INTEGER(x) || !TOY_IS_INTEGER(y) || (!TOY_IS_INTEGER(w) && !TOY_IS_NULL(w)) || (!TOY_IS_INTEGER(h) && !TOY_IS_NULL(h))) {
interpreter->errorOutput("Incorrect argument type passed to drawEngineNode\n");
freeLiteral(nodeLiteral);
freeLiteral(x);
freeLiteral(y);
freeLiteral(w);
freeLiteral(h);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(x);
Toy_freeLiteral(y);
Toy_freeLiteral(w);
Toy_freeLiteral(h);
return -1;
}
//actually render
EngineNode* node = (EngineNode*)AS_OPAQUE(nodeLiteral);
Box_EngineNode* node = (Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral);
SDL_Rect r = {AS_INTEGER(x), AS_INTEGER(y), 0, 0};
if (IS_INTEGER(w) && IS_INTEGER(h)) {
r.w = AS_INTEGER(w);
r.h = AS_INTEGER(h);
SDL_Rect r = {TOY_AS_INTEGER(x), TOY_AS_INTEGER(y), 0, 0};
if (TOY_IS_INTEGER(w) && TOY_IS_INTEGER(h)) {
r.w = TOY_AS_INTEGER(w);
r.h = TOY_AS_INTEGER(h);
}
else {
r.w = node->rect.w;
r.h = node->rect.h;
}
drawEngineNode(node, r);
Box_drawEngineNode(node, r);
//cleanup
freeLiteral(nodeLiteral);
freeLiteral(x);
freeLiteral(y);
freeLiteral(w);
freeLiteral(h);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(x);
Toy_freeLiteral(y);
Toy_freeLiteral(w);
Toy_freeLiteral(h);
return 0;
}
static int nativeGetNodeTag(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeGetNodeTag(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments passed to getNodeTag\n");
return -1;
}
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
if (!IS_OPAQUE(nodeLiteral)) {
if (!TOY_IS_OPAQUE(nodeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to getNodeTag\n");
freeLiteral(nodeLiteral);
Toy_freeLiteral(nodeLiteral);
return -1;
}
//push the tag
Literal tagLiteral = TO_INTEGER_LITERAL( ((EngineNode*)AS_OPAQUE(nodeLiteral))->tag );
Toy_Literal tagLiteral = TOY_TO_INTEGER_LITERAL( ((Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral))->tag );
pushLiteralArray(&interpreter->stack, tagLiteral);
Toy_pushLiteralArray(&interpreter->stack, tagLiteral);
//cleanup
freeLiteral(nodeLiteral);
freeLiteral(tagLiteral);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(tagLiteral);
return 1;
}
static int nativeCallNode(Interpreter* interpreter, LiteralArray* arguments) {
static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//checks
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments passed to callEngineNode\n");
return -1;
}
LiteralArray extraArgs;
initLiteralArray(&extraArgs);
Toy_LiteralArray extraArgs;
Toy_initLiteralArray(&extraArgs);
LiteralArray flippedExtraArgs;
initLiteralArray(&flippedExtraArgs);
Toy_LiteralArray flippedExtraArgs;
Toy_initLiteralArray(&flippedExtraArgs);
//extract the extra arg values
while (arguments->count > 2) {
Literal tmp = popLiteralArray(arguments);
Toy_Literal tmp = Toy_popLiteralArray(arguments);
Literal idn = tmp; //there's almost certainly a better way of doing all of this stuff
if (IS_IDENTIFIER(tmp) && parseIdentifierToValue(interpreter, &tmp)) {
freeLiteral(idn);
Toy_Literal idn = tmp; //there's almost certainly a better way of doing all of this stuff
if (TOY_IS_IDENTIFIER(tmp) && Toy_parseIdentifierToValue(interpreter, &tmp)) {
Toy_freeLiteral(idn);
}
pushLiteralArray(&flippedExtraArgs, tmp);
freeLiteral(tmp);
Toy_pushLiteralArray(&flippedExtraArgs, tmp);
Toy_freeLiteral(tmp);
}
//correct the order
while (flippedExtraArgs.count) {
Literal tmp = popLiteralArray(&flippedExtraArgs);
pushLiteralArray(&extraArgs, tmp);
freeLiteral(tmp);
Toy_Literal tmp = Toy_popLiteralArray(&flippedExtraArgs);
Toy_pushLiteralArray(&extraArgs, tmp);
Toy_freeLiteral(tmp);
}
freeLiteralArray(&flippedExtraArgs);
Toy_freeLiteralArray(&flippedExtraArgs);
//back on track
Literal fnName = popLiteralArray(arguments);
Literal nodeLiteral = popLiteralArray(arguments);
Toy_Literal fnName = Toy_popLiteralArray(arguments);
Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments);
Literal nodeIdn = nodeLiteral;
if (IS_IDENTIFIER(nodeLiteral) && parseIdentifierToValue(interpreter, &nodeLiteral)) {
freeLiteral(nodeIdn);
Toy_Literal nodeIdn = nodeLiteral;
if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) {
Toy_freeLiteral(nodeIdn);
}
Literal fnNameIdn = fnName;
if (IS_IDENTIFIER(fnName) && parseIdentifierToValue(interpreter, &fnName)) {
freeLiteral(fnNameIdn);
Toy_Literal fnNameIdn = fnName;
if (TOY_IS_IDENTIFIER(fnName) && Toy_parseIdentifierToValue(interpreter, &fnName)) {
Toy_freeLiteral(fnNameIdn);
}
if (!IS_OPAQUE(nodeLiteral) || !IS_STRING(fnName)) {
if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_STRING(fnName)) {
interpreter->errorOutput("Incorrect argument type passed to callEngineNode\n");
freeLiteral(nodeLiteral);
freeLiteral(fnName);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(fnName);
return -1;
}
//allow refstring to do it's magic
Literal fnNameIdentifier = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(fnName)));
Toy_Literal fnNameIdentifier = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(fnName)));
//call the function
Literal result = callEngineNodeLiteral(AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier, &extraArgs);
Toy_Literal result = Box_callEngineNodeLiteral(TOY_AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier, &extraArgs);
pushLiteralArray(&interpreter->stack, result);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
freeLiteralArray(&extraArgs);
freeLiteral(nodeLiteral);
freeLiteral(fnName);
freeLiteral(result);
Toy_freeLiteralArray(&extraArgs);
Toy_freeLiteral(nodeLiteral);
Toy_freeLiteral(fnName);
Toy_freeLiteral(result);
return 1;
}
@@ -606,10 +606,10 @@ static int nativeCallNode(Interpreter* interpreter, LiteralArray* arguments) {
//call the hook
typedef struct Natives {
char* name;
NativeFn fn;
Toy_NativeFn fn;
} Natives;
int hookNode(Interpreter* interpreter, Literal identifier, Literal alias) {
int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"loadNode", nativeLoadNode},
@@ -628,51 +628,51 @@ int hookNode(Interpreter* interpreter, Literal identifier, Literal alias) {
};
//store the library in an aliased dictionary
if (!IS_NULL(alias)) {
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
freeLiteral(alias);
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_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;
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
setLiteralDictionary(dictionary, name, func);
Toy_setLiteralDictionary(dictionary, name, func);
freeLiteral(name);
freeLiteral(func);
Toy_freeLiteral(name);
Toy_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);
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
declareScopeVariable(interpreter->scope, alias, type);
setScopeVariable(interpreter->scope, alias, dict, false);
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
freeLiteral(dict);
freeLiteral(type);
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "interpreter.h"
#include "toy_interpreter.h"
int hookNode(Interpreter* interpreter, Literal identifier, Literal alias);
int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

613
box/lib_runner.c Normal file
View File

@@ -0,0 +1,613 @@
#include "lib_runner.h"
#include "toy_memory.h"
#include "toy_interpreter.h"
#include "repl_tools.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct Toy_Runner {
Toy_Interpreter interpreter;
unsigned char* bytecode;
size_t size;
bool dirty;
} Toy_Runner;
//Toy native functions
static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_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 (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_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");
TOY_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");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load and compile the bytecode
size_t fileSize = 0;
char* source = Toy_readFile(filePath, &fileSize);
if (!source) {
interpreter->errorOutput("Failed to load source file\n");
return -1;
}
unsigned char* bytecode = Toy_compileString(source, &fileSize);
free((void*)source);
if (!bytecode) {
interpreter->errorOutput("Failed to compile source file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
return -1;
}
//get the argument
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
Toy_RefString* drivePath = Toy_copyRefString(TOY_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 (Toy_toCString(drivePath)[driveLength] != ':') {
if (driveLength >= Toy_lengthRefString(drivePath)) {
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
driveLength++;
}
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
//get the real drive file path
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
if (!TOY_IS_STRING(realDriveLiteral)) {
interpreter->errorOutput("Incorrect literal type found for drive: ");
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_freeLiteral(drivePathLiteral);
return -1;
}
//get the final real file path (concat) TODO: move this concat to refstring library
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
//clean up the drivepath stuff
Toy_deleteRefString(realDrive);
Toy_freeLiteral(realDriveLiteral);
Toy_freeLiteral(driveLiteral);
Toy_deleteRefString(path);
Toy_deleteRefString(drivePath);
Toy_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");
TOY_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");
TOY_FREE_ARRAY(char, filePath, realLength);
return -1;
}
}
//load the bytecode
size_t fileSize = 0;
unsigned char* bytecode = (unsigned char*)Toy_readFile(filePath, &fileSize);
if (!bytecode) {
interpreter->errorOutput("Failed to load bytecode file\n");
return -1;
}
//build the runner object
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
runner->interpreter.hooks = interpreter->hooks;
runner->interpreter.scope = NULL;
Toy_resetInterpreter(&runner->interpreter);
runner->bytecode = bytecode;
runner->size = fileSize;
runner->dirty = false;
//build the opaque object, and push it to the stack
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
TOY_FREE_ARRAY(char, filePath, realLength);
return 1;
}
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
if (runner->dirty) {
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
unsigned char* bytecodeCopy = TOY_ALLOCATE(unsigned char, runner->size);
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
Toy_runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
runner->dirty = true;
//cleanup
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
return -1;
}
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal result = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &result);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
return 1;
}
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count < 2) {
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
return -1;
}
//get the rest args
Toy_LiteralArray tmp;
Toy_initLiteralArray(&tmp);
while (arguments->count > 2) {
Toy_Literal lit = Toy_popLiteralArray(arguments);
Toy_pushLiteralArray(&tmp, lit);
Toy_freeLiteral(lit);
}
Toy_LiteralArray rest;
Toy_initLiteralArray(&rest);
while (tmp.count) { //correct the order of the rest args
Toy_Literal lit = Toy_popLiteralArray(&tmp);
Toy_pushLiteralArray(&rest, lit);
Toy_freeLiteral(lit);
}
Toy_freeLiteralArray(&tmp);
//get the runner object
Toy_Literal varName = Toy_popLiteralArray(arguments);
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal varNameIdn = varName;
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
Toy_freeLiteral(varNameIdn);
}
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//dirty check
if (!runner->dirty) {
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return -1;
}
//get the desired variable
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
Toy_Literal fn = TOY_TO_NULL_LITERAL;
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &fn);
if (!TOY_IS_FUNCTION(fn)) {
interpreter->errorOutput("Can't run a non-function literal\n");
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
}
//call
Toy_LiteralArray resultArray;
Toy_initLiteralArray(&resultArray);
Toy_callLiteralFn(interpreter, fn, &rest, &resultArray);
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (resultArray.count > 0) {
result = Toy_popLiteralArray(&resultArray);
}
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteralArray(&resultArray);
Toy_freeLiteral(result);
Toy_freeLiteral(fn);
Toy_freeLiteral(varIdn);
Toy_freeLiteral(varName);
Toy_freeLiteral(runnerLiteral);
Toy_freeLiteralArray(&rest);
return 1;
}
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//reset
if (!runner->dirty) {
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
Toy_freeLiteral(runnerLiteral);
return -1;
}
Toy_resetInterpreter(&runner->interpreter);
runner->dirty = false;
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//clear out the runner object
runner->interpreter.hooks = NULL;
Toy_freeInterpreter(&runner->interpreter);
TOY_FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
TOY_FREE(Toy_Runner, runner);
Toy_freeLiteral(runnerLiteral);
return 0;
}
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
return -1;
}
//get the runner object
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
Toy_Literal runnerIdn = runnerLiteral;
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
Toy_freeLiteral(runnerIdn);
}
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
return -1;
}
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
//run
Toy_Literal result = TOY_TO_BOOLEAN_LITERAL(runner->dirty);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(result);
Toy_freeLiteral(runnerLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_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 (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}
//file system API
static Toy_LiteralDictionary Toy_driveDictionary;
void Toy_initDriveDictionary() {
Toy_initLiteralDictionary(&Toy_driveDictionary);
}
void Toy_freeDriveDictionary() {
Toy_freeLiteralDictionary(&Toy_driveDictionary);
}
Toy_LiteralDictionary* Toy_getDriveDictionary() {
return &Toy_driveDictionary;
}

12
box/lib_runner.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
//file system API - these need to be set by the host
void Toy_initDriveDictionary();
void Toy_freeDriveDictionary();
Toy_LiteralDictionary* Toy_getDriveDictionary();
#define TOY_OPAQUE_TAG_RUNNER 100

95
box/lib_standard.c Normal file
View File

@@ -0,0 +1,95 @@
#include "lib_standard.h"
#include "toy_memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Toy_Interpreter* interpreter, Toy_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
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
//push to the stack
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
return 1;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
//build the natives list
Natives natives[] = {
{"clock", nativeClock},
{NULL, NULL}
};
//store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}

6
box/lib_standard.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

412
box/lib_timer.c Normal file
View File

@@ -0,0 +1,412 @@
#include "lib_timer.h"
#include "toy_memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
static 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 = TOY_ALLOCATE(struct timeval, 1);
//I gave up, copied from SO
timeval_subtract(d, rhs, lhs);
return d;
}
//callbacks
static int nativeStartTimer(Toy_Interpreter* interpreter, Toy_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 = TOY_ALLOCATE(struct timeval, 1);
gettimeofday(timeinfo, NULL);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
return 1;
}
static int nativeStopTimer(Toy_Interpreter* interpreter, Toy_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
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timerStart = TOY_AS_OPAQUE(timeLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(timerStart, &timerStop);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeCreateTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
return -1;
}
//get the args
Toy_Literal microsecondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteral = Toy_popLiteralArray(arguments);
Toy_Literal secondLiteralIdn = secondLiteral;
if (TOY_IS_IDENTIFIER(secondLiteral) && Toy_parseIdentifierToValue(interpreter, &secondLiteral)) {
Toy_freeLiteral(secondLiteralIdn);
}
Toy_Literal microsecondLiteralIdn = microsecondLiteral;
if (TOY_IS_IDENTIFIER(microsecondLiteral) && Toy_parseIdentifierToValue(interpreter, &microsecondLiteral)) {
Toy_freeLiteral(microsecondLiteralIdn);
}
if (!TOY_IS_INTEGER(secondLiteral) || !TOY_IS_INTEGER(microsecondLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
if (TOY_AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || TOY_AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (TOY_AS_INTEGER(secondLiteral) != 0 && TOY_AS_INTEGER(microsecondLiteral) < 0) ) {
interpreter->errorOutput("Microseconds out of range in createTimer\n");
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return -1;
}
//get the timeinfo from toy
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
timeinfo->tv_sec = TOY_AS_INTEGER(secondLiteral);
timeinfo->tv_usec = TOY_AS_INTEGER(microsecondLiteral);
//wrap in an opaque literal for Toy
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(secondLiteral);
Toy_freeLiteral(microsecondLiteral);
return 1;
}
static int nativeGetTimerSeconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_sec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeGetTimerMicroseconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
return -1;
}
//unwrap the opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the result literal
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_usec);
Toy_pushLiteralArray(&interpreter->stack, result);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(result);
return 1;
}
static int nativeCompareTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
return -1;
}
//unwrap the opaque literals
Toy_Literal rhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteral = Toy_popLiteralArray(arguments);
Toy_Literal lhsLiteralIdn = lhsLiteral;
if (TOY_IS_IDENTIFIER(lhsLiteral) && Toy_parseIdentifierToValue(interpreter, &lhsLiteral)) {
Toy_freeLiteral(lhsLiteralIdn);
}
Toy_Literal rhsLiteralIdn = rhsLiteral;
if (TOY_IS_IDENTIFIER(rhsLiteral) && Toy_parseIdentifierToValue(interpreter, &rhsLiteral)) {
Toy_freeLiteral(rhsLiteralIdn);
}
if (!TOY_IS_OPAQUE(lhsLiteral) || !TOY_IS_OPAQUE(rhsLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
return -1;
}
struct timeval* lhsTimer = TOY_AS_OPAQUE(lhsLiteral);
struct timeval* rhsTimer = TOY_AS_OPAQUE(rhsLiteral);
//determine the difference, and wrap it
struct timeval* d = diff(lhsTimer, rhsTimer);
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
//cleanup
Toy_freeLiteral(lhsLiteral);
Toy_freeLiteral(rhsLiteral);
Toy_freeLiteral(diffLiteral);
return 1;
}
static int nativeTimerToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
//create the string literal
Toy_Literal resultLiteral = TOY_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 = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
else { //normal case
char buffer[128];
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
}
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
//cleanup
Toy_freeLiteral(timeLiteral);
Toy_freeLiteral(resultLiteral);
return 1;
}
static int nativeDestroyTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//no arguments
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
return -1;
}
//unwrap in an opaque literal
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal timeLiteralIdn = timeLiteral;
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
Toy_freeLiteral(timeLiteralIdn);
}
if (!TOY_IS_OPAQUE(timeLiteral)) {
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
Toy_freeLiteral(timeLiteral);
return -1;
}
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
TOY_FREE(struct timeval, timer);
Toy_freeLiteral(timeLiteral);
return 0;
}
//call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_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 (!TOY_IS_NULL(alias)) {
//make sure the name isn't taken
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return false;
}
//create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = TOY_LITERAL_FUNCTION_NATIVE;
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
//build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
//set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
//cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
//default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
return 0;
}

6
box/lib_timer.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);

146
box/repl_tools.c Normal file
View File

@@ -0,0 +1,146 @@
#include "repl_tools.h"
#include "lib_standard.h"
#include "lib_timer.h"
#include "lib_runner.h"
#include "toy_console_colors.h"
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_compiler.h"
#include "toy_interpreter.h"
#include <stdio.h>
#include <stdlib.h>
//IO functions
char* Toy_readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_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, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_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, TOY_CC_ERROR "Could not read file \"%s\"\n" TOY_CC_RESET, path);
return NULL;
}
fclose(file);
return buffer;
}
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
FILE* file = fopen(path, "wb");
if (file == NULL) {
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
int written = fwrite(bytes, size, 1, file);
if (written != 1) {
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
return -1;
}
fclose(file);
return 0;
}
//repl functions
unsigned char* Toy_compileString(char* source, size_t* size) {
Toy_Lexer lexer;
Toy_Parser parser;
Toy_Compiler compiler;
Toy_initLexer(&lexer, source);
Toy_initParser(&parser, &lexer);
Toy_initCompiler(&compiler);
//run the parser until the end of the source
Toy_ASTNode* node = Toy_scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == TOY_AST_NODE_ERROR) {
Toy_freeASTNode(node);
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
return NULL;
}
Toy_writeCompiler(&compiler, node);
Toy_freeASTNode(node);
node = Toy_scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
//cleanup
Toy_freeCompiler(&compiler);
Toy_freeParser(&parser);
//no lexer to clean up
//finally
return tb;
}
void Toy_runBinary(unsigned char* tb, size_t size) {
Toy_Interpreter interpreter;
Toy_initInterpreter(&interpreter);
//inject the libs
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_runInterpreter(&interpreter, tb, size);
Toy_freeInterpreter(&interpreter);
}
void Toy_runBinaryFile(char* fname) {
size_t size = 0; //not used
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
//interpreter takes ownership of the binary data
}
void Toy_runSource(char* source) {
size_t size = 0;
unsigned char* tb = Toy_compileString(source, &size);
if (!tb) {
return;
}
Toy_runBinary(tb, size);
}
void Toy_runSourceFile(char* fname) {
size_t size = 0; //not used
char* source = Toy_readFile(fname, &size);
Toy_runSource(source);
free((void*)source);
}

14
box/repl_tools.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "toy_common.h"
char* Toy_readFile(char* path, size_t* fileSize);
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
unsigned char* Toy_compileString(char* source, size_t* size);
void Toy_runBinary(unsigned char* tb, size_t size);
void Toy_runBinaryFile(char* fname);
void Toy_runSource(char* source);
void Toy_runSourceFile(char* fname);