From f7f9e75ad972a301a39c289eebf981f0e5b84591 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Thu, 26 Jan 2023 21:12:44 +0000 Subject: [PATCH] Renamed everything to fit the new naming scheme --- box/box_common.c | 2 +- box/box_common.h | 4 +- box/box_engine.c | 114 ++++---- box/box_engine.h | 36 ++- box/box_engine_node.c | 137 +++++----- box/box_engine_node.h | 40 +-- box/lib_engine.c | 138 +++++----- box/lib_engine.h | 4 +- box/lib_input.c | 90 +++---- box/lib_input.h | 4 +- box/lib_node.c | 554 +++++++++++++++++++------------------- box/lib_node.h | 4 +- box/lib_runner.c | 613 ++++++++++++++++++++++++++++++++++++++++++ box/lib_runner.h | 12 + box/lib_standard.c | 95 +++++++ box/lib_standard.h | 6 + box/lib_timer.c | 412 ++++++++++++++++++++++++++++ box/lib_timer.h | 6 + box/repl_tools.c | 146 ++++++++++ box/repl_tools.h | 14 + source/main.c | 32 +-- 21 files changed, 1883 insertions(+), 580 deletions(-) create mode 100644 box/lib_runner.c create mode 100644 box/lib_runner.h create mode 100644 box/lib_standard.c create mode 100644 box/lib_standard.h create mode 100644 box/lib_timer.c create mode 100644 box/lib_timer.h create mode 100644 box/repl_tools.c create mode 100644 box/repl_tools.h diff --git a/box/box_common.c b/box/box_common.c index 232b8db..3371c20 100644 --- a/box/box_common.c +++ b/box/box_common.c @@ -1,4 +1,4 @@ -#include "core_common.h" +#include "box_common.h" STATIC_ASSERT(sizeof(char) == 1); STATIC_ASSERT(sizeof(short) == 2); diff --git a/box/box_common.h b/box/box_common.h index 00e5d4b..1589bb0 100644 --- a/box/box_common.h +++ b/box/box_common.h @@ -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 diff --git a/box/box_engine.c b/box/box_engine.c index 38abd70..2ff1515 100644 --- a/box/box_engine.c +++ b/box/box_engine.c @@ -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 #include #include //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); } diff --git a/box/box_engine.h b/box/box_engine.h index 134582b..49041f2 100644 --- a/box/box_engine.h +++ b/box/box_engine.h @@ -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 //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(); diff --git a/box/box_engine_node.c b/box/box_engine_node.c index 0109f82..7791ef6 100644 --- a/box/box_engine_node.c +++ b/box/box_engine_node.c @@ -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); } diff --git a/box/box_engine_node.h b/box/box_engine_node.h index a08a653..c4b029d 100644 --- a/box/box_engine_node.h +++ b/box/box_engine_node.h @@ -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); diff --git a/box/lib_engine.c b/box/lib_engine.c index bd204ff..0ce5ef4 100644 --- a/box/lib_engine.c +++ b/box/lib_engine.c @@ -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; diff --git a/box/lib_engine.h b/box/lib_engine.h index db6a5d5..02699b7 100644 --- a/box/lib_engine.h +++ b/box/lib_engine.h @@ -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); diff --git a/box/lib_input.c b/box/lib_input.c index 033c0d5..881b27d 100644 --- a/box/lib_input.c +++ b/box/lib_input.c @@ -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; diff --git a/box/lib_input.h b/box/lib_input.h index 1b92478..34e2bd4 100644 --- a/box/lib_input.h +++ b/box/lib_input.h @@ -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); diff --git a/box/lib_node.c b/box/lib_node.c index cca078e..8759ac3 100644 --- a/box/lib_node.c +++ b/box/lib_node.c @@ -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 -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; diff --git a/box/lib_node.h b/box/lib_node.h index b98c24d..febf912 100644 --- a/box/lib_node.h +++ b/box/lib_node.h @@ -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); diff --git a/box/lib_runner.c b/box/lib_runner.c new file mode 100644 index 0000000..9433873 --- /dev/null +++ b/box/lib_runner.c @@ -0,0 +1,613 @@ +#include "lib_runner.h" + +#include "toy_memory.h" +#include "toy_interpreter.h" + +#include "repl_tools.h" + +#include +#include + +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; +} \ No newline at end of file diff --git a/box/lib_runner.h b/box/lib_runner.h new file mode 100644 index 0000000..1912de4 --- /dev/null +++ b/box/lib_runner.h @@ -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 diff --git a/box/lib_standard.c b/box/lib_standard.c new file mode 100644 index 0000000..b253286 --- /dev/null +++ b/box/lib_standard.c @@ -0,0 +1,95 @@ +#include "lib_standard.h" + +#include "toy_memory.h" + +#include +#include + +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; +} diff --git a/box/lib_standard.h b/box/lib_standard.h new file mode 100644 index 0000000..d1b9816 --- /dev/null +++ b/box/lib_standard.h @@ -0,0 +1,6 @@ +#pragma once + +#include "toy_interpreter.h" + +int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); + diff --git a/box/lib_timer.c b/box/lib_timer.c new file mode 100644 index 0000000..60a4c28 --- /dev/null +++ b/box/lib_timer.c @@ -0,0 +1,412 @@ +#include "lib_timer.h" + +#include "toy_memory.h" + +#include +#include +#include + +//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, µsecondLiteral)) { + 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; +} diff --git a/box/lib_timer.h b/box/lib_timer.h new file mode 100644 index 0000000..90193e8 --- /dev/null +++ b/box/lib_timer.h @@ -0,0 +1,6 @@ +#pragma once + +#include "toy_interpreter.h" + +int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); + diff --git a/box/repl_tools.c b/box/repl_tools.c new file mode 100644 index 0000000..0b67a57 --- /dev/null +++ b/box/repl_tools.c @@ -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 +#include + +//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); +} diff --git a/box/repl_tools.h b/box/repl_tools.h new file mode 100644 index 0000000..57f5605 --- /dev/null +++ b/box/repl_tools.h @@ -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); + diff --git a/source/main.c b/source/main.c index 7680310..8a33d59 100644 --- a/source/main.c +++ b/source/main.c @@ -1,33 +1,33 @@ //moved here for android shenanigans #define SDL_MAIN_HANDLED -#include "engine.h" +#include "box_engine.h" //the runner library needs a little more setup since it accesses the disk #include "lib_runner.h" int main(int argc, char* argv[]) { //the drive system uses a LiteralDictionary, which must be initialized with this - initDriveDictionary(); + Toy_initDriveDictionary(); - //create a pair of literals, the first for the drive name, the second for the path - Literal driveLiteral = TO_STRING_LITERAL(createRefString("scripts")); - Literal pathLiteral = TO_STRING_LITERAL(createRefString("assets/scripts")); + //create a pair of literals, the first for the drive name, the second for the path + Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts")); + Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("assets/scripts")); - //set these within the drive dictionary - setLiteralDictionary(getDriveDictionary(), driveLiteral, pathLiteral); + //set these within the drive dictionary + Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral); - //these literals are no longer needed - freeLiteral(driveLiteral); - freeLiteral(pathLiteral); + //these literals are no longer needed + Toy_freeLiteral(driveLiteral); + Toy_freeLiteral(pathLiteral); - //run the rest of your program - initEngine(); - execEngine(); - freeEngine(); + //run the rest of your program + Box_initEngine(); + Box_execEngine(); + Box_freeEngine(); - //clean up the drive dictionary when you're done - freeDriveDictionary(); + //clean up the drive dictionary when you're done + Toy_freeDriveDictionary(); return 0; }