From 9a1d81b7fb84bcb127a7ee2b5cfd88f280d8918e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 14 Feb 2023 22:19:08 +0000 Subject: [PATCH] Updated Toy, tweaked code to match new API --- Toy | 2 +- assets/scripts/entity.toy | 14 +- assets/scripts/root.toy | 8 +- box/box_engine.c | 8 +- box/box_engine.h | 1 + box/box_engine_node.c | 16 +- box/lib_compound.c | 1468 ----------------------------------- box/lib_compound.h | 6 - box/lib_node.c | 91 +-- box/lib_runner.c | 49 +- box/lib_standard.c | 1540 ++++++++++++++++++++++++++++++++++++- box/lib_timer.c | 411 ---------- box/lib_timer.h | 6 - box/repl_tools.c | 8 +- 14 files changed, 1610 insertions(+), 2018 deletions(-) delete mode 100644 box/lib_compound.c delete mode 100644 box/lib_compound.h delete mode 100644 box/lib_timer.c delete mode 100644 box/lib_timer.h diff --git a/Toy b/Toy index aeb008c..501ff6f 160000 --- a/Toy +++ b/Toy @@ -1 +1 @@ -Subproject commit aeb008c6845fa5b791fd302a366a99adc3406880 +Subproject commit 501ff6fff45b4cd669eefbf4d6f3414d25f5b115 diff --git a/assets/scripts/entity.toy b/assets/scripts/entity.toy index 4206550..82a13d8 100644 --- a/assets/scripts/entity.toy +++ b/assets/scripts/entity.toy @@ -24,7 +24,7 @@ fn getY(node: opaque) { //lifecycle functions fn onInit(node: opaque) { - print "render.toy:onInit() called\n"; + print "render.toy:onInit() called"; node.loadTexture("sprites:/character.png"); parent = node.getNodeParent(); @@ -36,13 +36,13 @@ fn onStep(node: opaque) { } fn onFree(node: opaque) { - print "render.toy:onFree() called\n"; + print "render.toy:onFree() called"; node.freeTexture(); } fn onDraw(node: opaque) { -// print "render.toy:onDraw() called\n"; +// print "render.toy:onDraw() called"; var px = parent.callNode("getX"); var py = parent.callNode("getY"); @@ -104,11 +104,11 @@ fn onKeyUp(node: opaque, event: string) { } fn onMouseMotion(node: opaque, x: int, y: int, xrel: int, yrel: int) { - // print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")\n"; + // print "entity.toy:onMouseMotion(" + string x + ", " + string y + ", " + string xrel + ", " + string yrel + ")"; } fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) { - // print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")\n"; + // print "entity.toy:onMouseButtonDown(" + string x + ", " + string y + ", " + button + ")"; //jump to pos posX = x - WIDTH / 2; @@ -116,10 +116,10 @@ fn onMouseButtonDown(node: opaque, x: int, y: int, button: string) { } fn onMouseButtonUp(node: opaque, x: int, y: int, button: string) { - // print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")\n"; + // print "entity.toy:onMouseButtonUp(" + string x + ", " + string y + ", " + button + ")"; } fn onMouseWheel(node: opaque, xrel: int, yrel: int) { - // print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")\n"; + // print "entity.toy:onMouseWheel(" + string xrel + ", " + string yrel + ")"; } diff --git a/assets/scripts/root.toy b/assets/scripts/root.toy index 2ae4ebc..f19cfcb 100644 --- a/assets/scripts/root.toy +++ b/assets/scripts/root.toy @@ -3,7 +3,7 @@ import engine; import node; //util to generate and init a child node of a parent -fn _makeChild(parent: opaque, fname: string) { +fn makeChild(parent: opaque, fname: string) { var child: opaque = loadNode(fname); parent.pushNode(child); child.initNode(); @@ -11,7 +11,7 @@ fn _makeChild(parent: opaque, fname: string) { //NOTE: root node can load the whole scene, and essentially act as the scene object fn onInit(node: opaque) { - print "root.toy:onInit() called\n"; + print "root.toy:onInit() called"; //make a child node.makeChild("scripts:/entity.toy"); @@ -21,9 +21,9 @@ fn onInit(node: opaque) { } fn onStep(node: opaque) { - //print clock() + "\n"; + //print clock(); } fn onFree(node: opaque) { - print "root.toy:onFree() called\n"; + print "root.toy:onFree() called"; } diff --git a/box/box_engine.c b/box/box_engine.c index cfd2d5f..336c412 100644 --- a/box/box_engine.c +++ b/box/box_engine.c @@ -4,8 +4,6 @@ #include "lib_input.h" #include "lib_node.h" #include "lib_standard.h" -#include "lib_compound.h" -#include "lib_timer.h" #include "lib_runner.h" #include "repl_tools.h" @@ -51,13 +49,11 @@ void Box_initEngine() { //init Toy Toy_initInterpreter(&engine.interpreter); + Toy_injectNativeHook(&engine.interpreter, "standard", Toy_hookStandard); + Toy_injectNativeHook(&engine.interpreter, "runner", Toy_hookRunner); 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, "compound", Toy_hookCompound); - Toy_injectNativeHook(&engine.interpreter, "timer", Toy_hookTimer); - Toy_injectNativeHook(&engine.interpreter, "runner", Toy_hookRunner); size_t size = 0; const char* source = Toy_readFile("./assets/scripts/init.toy", &size); diff --git a/box/box_engine.h b/box/box_engine.h index 3db15eb..6ed331b 100644 --- a/box/box_engine.h +++ b/box/box_engine.h @@ -7,6 +7,7 @@ #include "toy_literal_array.h" #include "toy_literal_dictionary.h" +//TODO: remove this, and replace with time.h #include //the base engine object, which represents the state of the game diff --git a/box/box_engine_node.c b/box/box_engine_node.c index b9f5c3b..862e85f 100644 --- a/box/box_engine_node.c +++ b/box/box_engine_node.c @@ -106,15 +106,15 @@ Toy_Literal Box_callEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* int Toy_initLiteralArray(&arguments); Toy_initLiteralArray(&returns); - //feed the arguments in backwards! + //feed the arguments in + Toy_pushLiteralArray(&arguments, n); + if (args) { - for (int i = args->count -1; i >= 0; i--) { + for (int i = 0; i < args->count; i++) { Toy_pushLiteralArray(&arguments, args->literals[i]); } } - Toy_pushLiteralArray(&arguments, n); - Toy_callLiteralFn(interpreter, fn, &arguments, &returns); ret = Toy_popLiteralArray(&returns); @@ -151,15 +151,15 @@ void Box_callRecursiveEngineNodeLiteral(Box_EngineNode* node, Toy_Interpreter* i Toy_initLiteralArray(&arguments); Toy_initLiteralArray(&returns); - //feed the arguments in backwards! + //feed the arguments in + Toy_pushLiteralArray(&arguments, n); + if (args) { - for (int i = args->count -1; i >= 0; i--) { + for (int i = 0; i < args->count; i++) { Toy_pushLiteralArray(&arguments, args->literals[i]); } } - Toy_pushLiteralArray(&arguments, n); - Toy_callLiteralFn(interpreter, fn, &arguments, &returns); Toy_freeLiteralArray(&arguments); diff --git a/box/lib_compound.c b/box/lib_compound.c deleted file mode 100644 index 9ddba6b..0000000 --- a/box/lib_compound.c +++ /dev/null @@ -1,1468 +0,0 @@ -#include "lib_compound.h" - -#include "toy_memory.h" - -#include -#include - -static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _concat\n"); - return -1; - } - - //get the args - Toy_Literal otherLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal otherLiteralIdn = otherLiteral; - if (TOY_IS_IDENTIFIER(otherLiteral) && Toy_parseIdentifierToValue(interpreter, &otherLiteral)) { - Toy_freeLiteral(otherLiteralIdn); - } - - //for each self type - if (TOY_IS_ARRAY(selfLiteral)) { - if (!TOY_IS_ARRAY(otherLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - return -1; - } - - //append each element of other to self, one-by-one - for (int i = 0; i < TOY_AS_ARRAY(otherLiteral)->count; i++) { - Toy_pushLiteralArray(TOY_AS_ARRAY(selfLiteral), TOY_AS_ARRAY(otherLiteral)->literals[i]); - } - - //return and clean up - Toy_pushLiteralArray(&interpreter->stack, selfLiteral); - - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - - return 1; - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - if (!TOY_IS_DICTIONARY(otherLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - return -1; - } - - //append each element of self to other, which will overwrite existing entries - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - if (!TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - Toy_setLiteralDictionary(TOY_AS_DICTIONARY(otherLiteral), TOY_AS_DICTIONARY(selfLiteral)->entries[i].key, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - } - } - - //return and clean up - Toy_pushLiteralArray(&interpreter->stack, otherLiteral); - - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - - return 1; - } - - if (TOY_IS_STRING(selfLiteral)) { //a little redundant - if (!TOY_IS_STRING(otherLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - return -1; - } - - //get the combined length for the new string - int length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1; - - if (length > TOY_MAX_STRING_LENGTH) { - interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in _concat)\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - return -1; - } - - //allocate the space and generate - char* buffer = TOY_ALLOCATE(char, length); - snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral))); - - Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); - - //push and clean up - Toy_pushLiteralArray(&interpreter->stack, result); - - TOY_FREE_ARRAY(char, buffer, length); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - Toy_freeLiteral(result); - - return 1; - } - - interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for self)\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(otherLiteral); - return -1; -} - -static int nativeContainsKey(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _containsKey\n"); - return -1; - } - - //get the args - Toy_Literal keyLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal keyLiteralIdn = keyLiteral; - if (TOY_IS_IDENTIFIER(keyLiteral) && Toy_parseIdentifierToValue(interpreter, &keyLiteral)) { - Toy_freeLiteral(keyLiteralIdn); - } - - //check type - if (!(/* TOY_IS_ARRAY(selfLiteral) || */ TOY_IS_DICTIONARY(selfLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _containsKey\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(keyLiteral); - return -1; - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(false); - if (TOY_IS_DICTIONARY(selfLiteral) && Toy_existsLiteralDictionary( TOY_AS_DICTIONARY(selfLiteral), keyLiteral )) { - //return true of it contains the key - Toy_freeLiteral(resultLiteral); - resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); - } - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(keyLiteral); - - return 1; -} - -static int nativeContainsValue(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _containsValue\n"); - return -1; - } - - //get the args - Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal valueLiteralIdn = valueLiteral; - if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { - Toy_freeLiteral(valueLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _containsValue\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(valueLiteral); - return -1; - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(false); - if (TOY_IS_DICTIONARY(selfLiteral)) { - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - if (!TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key) && Toy_literalsAreEqual( TOY_AS_DICTIONARY(selfLiteral)->entries[i].value, valueLiteral )) { - //return true of it contains the value - Toy_freeLiteral(resultLiteral); - resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); - break; - } - } - } - else if (TOY_IS_ARRAY(selfLiteral)) { - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - Toy_Literal elementLiteral = Toy_getLiteralArray(TOY_AS_ARRAY(selfLiteral), indexLiteral); - - - if (Toy_literalsAreEqual(elementLiteral, valueLiteral)) { - Toy_freeLiteral(indexLiteral); - Toy_freeLiteral(elementLiteral); - - //return true of it contains the value - Toy_freeLiteral(resultLiteral); - resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); - break; - } - - Toy_freeLiteral(indexLiteral); - Toy_freeLiteral(elementLiteral); - } - } - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(valueLiteral); - - return 1; -} - -static int nativeEvery(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _every\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _every\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - bool result = true; - - // - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - - //if not truthy - if (!TOY_IS_TRUTHY(lit)) { - Toy_freeLiteral(lit); - result = false; - break; - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - bool result = true; - - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - - //if not truthy - if (!TOY_IS_TRUTHY(lit)) { - Toy_freeLiteral(lit); - result = false; - break; - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeFilter(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _filter\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _filter\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1); - Toy_initLiteralArray(result); - - // - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - - //if truthy - if (TOY_IS_TRUTHY(lit)) { - Toy_pushLiteralArray(result, TOY_AS_ARRAY(selfLiteral)->literals[i]); - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_ARRAY_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - Toy_LiteralDictionary* result = TOY_ALLOCATE(Toy_LiteralDictionary, 1); - Toy_initLiteralDictionary(result); - - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - - //if truthy - if (TOY_IS_TRUTHY(lit)) { - Toy_setLiteralDictionary(result, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_DICTIONARY_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeForEach(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _forEach\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _forEach\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - } - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - } - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(selfLiteral); - - return 0; -} - -static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _getKeys\n"); - return -1; - } - - //get the self - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - //check type - if (!TOY_IS_DICTIONARY(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _getKeys\n"); - Toy_freeLiteral(selfLiteral); - return -1; - } - - //generate the result literal - Toy_LiteralArray* resultPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); - Toy_initLiteralArray(resultPtr); - - //get each key from the dictionary, pass it to the array - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - if (!TOY_IS_NULL( TOY_AS_DICTIONARY(selfLiteral)->entries[i].key )) { - Toy_pushLiteralArray(resultPtr, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - } - } - - //return the result - Toy_Literal result = TOY_TO_ARRAY_LITERAL(resultPtr); //no copy - Toy_pushLiteralArray(&interpreter->stack, result); //internal copy - - //clean up - Toy_freeLiteralArray(resultPtr); - TOY_FREE(Toy_LiteralArray, resultPtr); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _getValues\n"); - return -1; - } - - //get the self - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - //check type - if (!TOY_IS_DICTIONARY(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _getValues\n"); - Toy_freeLiteral(selfLiteral); - return -1; - } - - //generate the result literal - Toy_LiteralArray* resultPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); - Toy_initLiteralArray(resultPtr); - - //get each key from the dictionary, pass it to the array - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - if (!TOY_IS_NULL( TOY_AS_DICTIONARY(selfLiteral)->entries[i].key )) { - Toy_pushLiteralArray(resultPtr, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - } - } - - //return the result - Toy_Literal result = TOY_TO_ARRAY_LITERAL(resultPtr); //no copy - Toy_pushLiteralArray(&interpreter->stack, result); //internal copy - - //clean up - Toy_freeLiteralArray(resultPtr); - TOY_FREE(Toy_LiteralArray, resultPtr); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeMap(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _map\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _map\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); - Toy_initLiteralArray(returnsPtr); - - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - Toy_pushLiteralArray(returnsPtr, lit); - Toy_freeLiteral(lit); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - } - - Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr); - Toy_pushLiteralArray(&interpreter->stack, returnsLiteral); - Toy_freeLiteral(returnsLiteral); - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); - Toy_initLiteralArray(returnsPtr); - - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - Toy_pushLiteralArray(returnsPtr, lit); - Toy_freeLiteral(lit); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - } - - Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr); - Toy_pushLiteralArray(&interpreter->stack, returnsLiteral); - Toy_freeLiteral(returnsLiteral); - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(selfLiteral); - - return 0; -} - -static int nativeReduce(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 3) { - interpreter->errorOutput("Incorrect number of arguments to _reduce\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal defaultLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal defaultLiteralIdn = defaultLiteral; - if (TOY_IS_IDENTIFIER(defaultLiteral) && Toy_parseIdentifierToValue(interpreter, &defaultLiteral)) { - Toy_freeLiteral(defaultLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _reduce\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(defaultLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - Toy_pushLiteralArray(&arguments, defaultLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_freeLiteral(defaultLiteral); - defaultLiteral = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - } - - Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - Toy_pushLiteralArray(&arguments, defaultLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_freeLiteral(defaultLiteral); - defaultLiteral = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - } - - Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(defaultLiteral); - Toy_freeLiteral(selfLiteral); - - return 0; -} - -static int nativeSome(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _some\n"); - return -1; - } - - //get the args - Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to value if needed - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - Toy_Literal fnLiteralIdn = fnLiteral; - if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { - Toy_freeLiteral(fnLiteralIdn); - } - - //check type - if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { - interpreter->errorOutput("Incorrect argument type passed to _some\n"); - Toy_freeLiteral(selfLiteral); - Toy_freeLiteral(fnLiteral); - return -1; - } - - //call the given function on each element, based on the compound type - if (TOY_IS_ARRAY(selfLiteral)) { - bool result = false; - - // - for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { - Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); - Toy_pushLiteralArray(&arguments, indexLiteral); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - Toy_freeLiteral(indexLiteral); - - //if not truthy - if (TOY_IS_TRUTHY(lit)) { - Toy_freeLiteral(lit); - result = true; - break; - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - if (TOY_IS_DICTIONARY(selfLiteral)) { - bool result = false; - - for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { - //skip nulls - if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { - continue; - } - - Toy_LiteralArray arguments; - Toy_initLiteralArray(&arguments); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); - Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); - - Toy_LiteralArray returns; - Toy_initLiteralArray(&returns); - - Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); - - //grab the results - Toy_Literal lit = Toy_popLiteralArray(&returns); - - Toy_freeLiteralArray(&arguments); - Toy_freeLiteralArray(&returns); - - //if not truthy - if (TOY_IS_TRUTHY(lit)) { - Toy_freeLiteral(lit); - result = true; - break; - } - - Toy_freeLiteral(lit); - } - - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); - Toy_freeLiteral(resultLiteral); - } - - Toy_freeLiteral(fnLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _toLower\n"); - return -1; - } - - //get the argument to a C-string - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - if (!TOY_IS_STRING(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _toLower\n"); - Toy_freeLiteral(selfLiteral); - return -1; - } - - Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); - const char* self = Toy_toCString(selfRefString); - - //allocate buffer space for the result - char* result = TOY_ALLOCATE(char, Toy_lengthRefString(selfRefString) + 1); - - //set each new character - for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { - result[i] = tolower(self[i]); - } - result[Toy_lengthRefString(selfRefString)] = '\0'; //end the string - - //wrap up and push the new result onto the stack - Toy_RefString* resultRefString = Toy_createRefStringLength(result, Toy_lengthRefString(selfRefString)); //internal copy - Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(resultRefString); //NO copy - - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy - - //cleanup - TOY_FREE_ARRAY(char, result, Toy_lengthRefString(resultRefString) + 1); - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static char* toStringUtilObject = NULL; -static void toStringUtil(const char* input) { - size_t len = strlen(input) + 1; - - if (len > TOY_MAX_STRING_LENGTH) { - len = TOY_MAX_STRING_LENGTH; //TODO: don't truncate - } - - toStringUtilObject = TOY_ALLOCATE(char, len); - - snprintf(toStringUtilObject, len, "%s", input); -} - -static int nativeToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _toString\n"); - return -1; - } - - //get the argument - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - //parse to a value - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - //BUGFIX: probably an undefined variable - if (TOY_IS_IDENTIFIER(selfLiteral)) { - Toy_freeLiteral(selfLiteral); - return -1; - } - - //print it to a custom function - Toy_printLiteralCustom(selfLiteral, toStringUtil); - - //create the resulting string and push it - Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(toStringUtilObject)); //internal copy - - Toy_pushLiteralArray(&interpreter->stack, result); - - //cleanup - TOY_FREE_ARRAY(char, toStringUtilObject, Toy_lengthRefString( TOY_AS_STRING(result) ) + 1); - toStringUtilObject = NULL; - - Toy_freeLiteral(result); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeToUpper(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - //no arguments - if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _toUpper\n"); - return -1; - } - - //get the argument to a C-string - Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - if (!TOY_IS_STRING(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _toUpper\n"); - Toy_freeLiteral(selfLiteral); - return -1; - } - - Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); - const char* self = Toy_toCString(selfRefString); - - //allocate buffer space for the result - char* result = TOY_ALLOCATE(char, Toy_lengthRefString(selfRefString) + 1); - - //set each new character - for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { - result[i] = toupper(self[i]); - } - result[Toy_lengthRefString(selfRefString)] = '\0'; //end the string - - //wrap up and push the new result onto the stack - Toy_RefString* resultRefString = Toy_createRefStringLength(result, Toy_lengthRefString(selfRefString)); //internal copy - Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(resultRefString); //NO copy - - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy - - //cleanup - TOY_FREE_ARRAY(char, result, Toy_lengthRefString(resultRefString) + 1); - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeTrim(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count < 1 || arguments->count > 2) { - interpreter->errorOutput("Incorrect number of arguments to _trim\n"); - return -1; - } - - //get the arguments - Toy_Literal trimCharsLiteral; - Toy_Literal selfLiteral; - - if (arguments->count == 2) { - trimCharsLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; - if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { - Toy_freeLiteral(trimCharsLiteralIdn); - } - } - else { - trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); - } - selfLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - if (!TOY_IS_STRING(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _trim\n"); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - return -1; - } - - //unwrap the arguments - Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); - Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); - - //allocate space for the new string - int bufferBegin = 0; - int bufferEnd = Toy_lengthRefString(selfRefString); - - //for each character in self, check it against each character in trimChars - on a fail, go to end - for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { - int trimIndex = 0; - - while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - //there is a match - DON'T increment anymore - if (Toy_toCString(selfRefString)[i] == Toy_toCString(trimCharsRefString)[trimIndex]) { - break; - } - - trimIndex++; - } - - //if the match is found, increment buffer begin - if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - bufferBegin++; - continue; - } - else { - break; - } - } - - //again, from the back - for (int i = Toy_lengthRefString(selfRefString); i >= 0; i--) { - int trimIndex = 0; - - while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - //there is a match - DON'T increment anymore - if (Toy_toCString(selfRefString)[i-1] == Toy_toCString(trimCharsRefString)[trimIndex]) { - break; - } - - trimIndex++; - } - - //if the match is found, increment buffer begin - if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - bufferEnd--; - continue; - } - else { - break; - } - } - - //generate the result - Toy_Literal resultLiteral; - if (bufferBegin >= bufferEnd) { //catch errors - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); - } - else { - char buffer[TOY_MAX_STRING_LENGTH]; - snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy - } - - //wrap up the buffer and return it - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeTrimBegin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count < 1 || arguments->count > 2) { - interpreter->errorOutput("Incorrect number of arguments to _trimBegin\n"); - return -1; - } - - //get the arguments - Toy_Literal trimCharsLiteral; - Toy_Literal selfLiteral; - - if (arguments->count == 2) { - trimCharsLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; - if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { - Toy_freeLiteral(trimCharsLiteralIdn); - } - } - else { - trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); - } - selfLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - if (!TOY_IS_STRING(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _trimBegin\n"); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - return -1; - } - - //unwrap the arguments - Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); - Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); - - //allocate space for the new string - int bufferBegin = 0; - int bufferEnd = Toy_lengthRefString(selfRefString); - - //for each character in self, check it against each character in trimChars - on a fail, go to end - for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { - int trimIndex = 0; - - while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - //there is a match - DON'T increment anymore - if (Toy_toCString(selfRefString)[i] == Toy_toCString(trimCharsRefString)[trimIndex]) { - break; - } - - trimIndex++; - } - - //if the match is found, increment buffer begin - if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - bufferBegin++; - continue; - } - else { - break; - } - } - - //generate the result - Toy_Literal resultLiteral; - if (bufferBegin >= bufferEnd) { //catch errors - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); - } - else { - char buffer[TOY_MAX_STRING_LENGTH]; - snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy - } - - //wrap up the buffer and return it - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -static int nativeTrimEnd(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { - if (arguments->count < 1 || arguments->count > 2) { - interpreter->errorOutput("Incorrect number of arguments to _trimEnd\n"); - return -1; - } - - //get the arguments - Toy_Literal trimCharsLiteral; - Toy_Literal selfLiteral; - - if (arguments->count == 2) { - trimCharsLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; - if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { - Toy_freeLiteral(trimCharsLiteralIdn); - } - } - else { - trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); - } - selfLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal selfLiteralIdn = selfLiteral; - if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { - Toy_freeLiteral(selfLiteralIdn); - } - - if (!TOY_IS_STRING(selfLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to _trimEnd\n"); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - return -1; - } - - //unwrap the arguments - Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); - Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); - - //allocate space for the new string - int bufferBegin = 0; - int bufferEnd = Toy_lengthRefString(selfRefString); - - //again, from the back - for (int i = (int)Toy_lengthRefString(selfRefString); i >= 0; i--) { - int trimIndex = 0; - - while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - //there is a match - DON'T increment anymore - if (Toy_toCString(selfRefString)[i-1] == Toy_toCString(trimCharsRefString)[trimIndex]) { - break; - } - - trimIndex++; - } - - //if the match is found, increment buffer begin - if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { - bufferEnd--; - continue; - } - else { - break; - } - } - - //generate the result - Toy_Literal resultLiteral; - if (bufferBegin >= bufferEnd) { //catch errors - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); - } - else { - char buffer[TOY_MAX_STRING_LENGTH]; - snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy - } - - //wrap up the buffer and return it - Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy - - //cleanup - Toy_freeLiteral(resultLiteral); - Toy_freeLiteral(trimCharsLiteral); - Toy_freeLiteral(selfLiteral); - - return 1; -} - -//call the hook -typedef struct Natives { - char* name; - Toy_NativeFn fn; -} Natives; - -int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { - //build the natives list - Natives natives[] = { - {"_concat", nativeConcat}, //array, dictionary, string - {"_containsKey", nativeContainsKey}, //dictionary - {"_containsValue", nativeContainsValue}, //array, dictionary - {"_every", nativeEvery}, //array, dictionary - {"_filter", nativeFilter}, //array, dictionary - {"_forEach", nativeForEach}, //array, dictionary - {"_getKeys", nativeGetKeys}, //dictionary - {"_getValues", nativeGetValues}, //dictionary - // {"_indexOf", native}, //array, string - // {"_insert", native}, //array, dictionary, string - {"_map", nativeMap}, //array, dictionary - {"_reduce", nativeReduce}, //array, dictionary - // {"_remove", native}, //array, dictionary - // {"_replace", native}, //string - {"_some", nativeSome}, //array, dictionary - // {"_sort", native}, //array - {"_toLower", nativeToLower}, //string - {"_toString", nativeToString}, //array, dictionary - {"_toUpper", nativeToUpper}, //string - {"_trim", nativeTrim}, //string - {"_trimBegin", nativeTrimBegin}, //string - {"_trimEnd", nativeTrimEnd}, //string - {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 -1; - } - - //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_NATIVE_LITERAL(natives[i].fn); - - 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_compound.h b/box/lib_compound.h deleted file mode 100644 index 2f256f6..0000000 --- a/box/lib_compound.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "toy_interpreter.h" - -int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); - diff --git a/box/lib_node.c b/box/lib_node.c index 15d57a6..35bd29e 100644 --- a/box/lib_node.c +++ b/box/lib_node.c @@ -209,7 +209,7 @@ static int nativePushNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //checks if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments passed to getNode\n"); + interpreter->errorOutput("Incorrect number of arguments passed to getNodeChild\n"); return -1; } @@ -222,7 +222,7 @@ static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* ar } if (!TOY_IS_OPAQUE(parent) || !TOY_IS_INTEGER(index)) { - interpreter->errorOutput("Incorrect argument type passed to getNode\n"); + interpreter->errorOutput("Incorrect argument type passed to getNodeChild\n"); Toy_freeLiteral(parent); Toy_freeLiteral(index); return -1; @@ -233,7 +233,7 @@ static int nativeGetNodeChild(Toy_Interpreter* interpreter, Toy_LiteralArray* ar int intIndex = TOY_AS_INTEGER(index); if (intIndex < 0 || intIndex >= parentNode->count) { - interpreter->errorOutput("index out of bounds in getNode\n"); + interpreter->errorOutput("index out of bounds in getNodeChild\n"); Toy_freeLiteral(parent); Toy_freeLiteral(index); return -1; @@ -292,7 +292,7 @@ static int nativeGetNodeParent(Toy_Interpreter* interpreter, Toy_LiteralArray* a static int nativeLoadTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments passed to loadTextureEngineNode\n"); + interpreter->errorOutput("Incorrect number of arguments passed to loadTexture\n"); return -1; } @@ -312,7 +312,7 @@ static int nativeLoadTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arg //check argument types if (!TOY_IS_STRING(drivePathLiteral) || !TOY_IS_OPAQUE(nodeLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to loadTextureEngineNode\n"); + interpreter->errorOutput("Incorrect argument type passed to loadTexture\n"); Toy_freeLiteral(drivePathLiteral); Toy_freeLiteral(nodeLiteral); return -1; @@ -351,7 +351,7 @@ static int nativeLoadTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arg static int nativeFreeTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments passed to freeTextureEngineNode\n"); + interpreter->errorOutput("Incorrect number of arguments passed to freeTexture\n"); return -1; } @@ -365,7 +365,7 @@ static int nativeFreeTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arg //check argument types if (!TOY_IS_OPAQUE(nodeLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to freeTextureEngineNode\n"); + interpreter->errorOutput("Incorrect argument type passed to freeTexture\n"); Toy_freeLiteral(nodeLiteral); return -1; } @@ -385,7 +385,7 @@ static int nativeFreeTexture(Toy_Interpreter* interpreter, Toy_LiteralArray* arg static int nativeSetRect(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 5) { - interpreter->errorOutput("Incorrect number of arguments passed to setRectEngineNode\n"); + interpreter->errorOutput("Incorrect number of arguments passed to setRect\n"); return -1; } @@ -423,7 +423,7 @@ static int nativeSetRect(Toy_Interpreter* interpreter, Toy_LiteralArray* argumen //check argument types 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"); + interpreter->errorOutput("Incorrect argument type passed to setRect\n"); Toy_freeLiteral(nodeLiteral); Toy_freeLiteral(x); Toy_freeLiteral(y); @@ -452,7 +452,7 @@ static int nativeSetRect(Toy_Interpreter* interpreter, Toy_LiteralArray* argumen 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"); + interpreter->errorOutput("Incorrect number of arguments passed to drawNode\n"); return -1; } @@ -494,7 +494,7 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume //check argument types 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"); + interpreter->errorOutput("Incorrect argument type passed to drawNode\n"); Toy_freeLiteral(nodeLiteral); Toy_freeLiteral(x); Toy_freeLiteral(y); @@ -528,51 +528,16 @@ static int nativeDrawNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume return 0; } -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; - } - - Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments); - - Toy_Literal nodeIdn = nodeLiteral; - if (TOY_IS_IDENTIFIER(nodeLiteral) && Toy_parseIdentifierToValue(interpreter, &nodeLiteral)) { - Toy_freeLiteral(nodeIdn); - } - - if (!TOY_IS_OPAQUE(nodeLiteral)) { - interpreter->errorOutput("Incorrect argument type passed to getNodeTag\n"); - Toy_freeLiteral(nodeLiteral); - return -1; - } - - //push the tag - Toy_Literal tagLiteral = TOY_TO_INTEGER_LITERAL( ((Box_EngineNode*)TOY_AS_OPAQUE(nodeLiteral))->tag ); - - Toy_pushLiteralArray(&interpreter->stack, tagLiteral); - - //cleanup - Toy_freeLiteral(nodeLiteral); - Toy_freeLiteral(tagLiteral); - - return 1; -} - static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //checks if (arguments->count < 2) { - interpreter->errorOutput("Too few arguments passed to callEngineNode\n"); + interpreter->errorOutput("Too few arguments passed to callNode\n"); return -1; } Toy_LiteralArray extraArgs; Toy_initLiteralArray(&extraArgs); - Toy_LiteralArray flippedExtraArgs; - Toy_initLiteralArray(&flippedExtraArgs); - //extract the extra arg values while (arguments->count > 2) { Toy_Literal tmp = Toy_popLiteralArray(arguments); @@ -582,19 +547,10 @@ static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume Toy_freeLiteral(idn); } - Toy_pushLiteralArray(&flippedExtraArgs, tmp); - Toy_freeLiteral(tmp); - } - - //correct the order - while (flippedExtraArgs.count) { - Toy_Literal tmp = Toy_popLiteralArray(&flippedExtraArgs); Toy_pushLiteralArray(&extraArgs, tmp); Toy_freeLiteral(tmp); } - Toy_freeLiteralArray(&flippedExtraArgs); - //back on track Toy_Literal fnName = Toy_popLiteralArray(arguments); Toy_Literal nodeLiteral = Toy_popLiteralArray(arguments); @@ -610,7 +566,7 @@ static int nativeCallNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume } if (!TOY_IS_OPAQUE(nodeLiteral) || !TOY_IS_STRING(fnName)) { - interpreter->errorOutput("Incorrect argument type passed to callEngineNode\n"); + interpreter->errorOutput("Incorrect argument type passed to callNode\n"); Toy_freeLiteral(nodeLiteral); Toy_freeLiteral(fnName); return -1; @@ -644,17 +600,16 @@ int Box_hookNode(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter //build the natives list Natives natives[] = { {"loadNode", nativeLoadNode}, - {"_initNode", nativeInitNode}, - {"_freeChildNode", nativeFreeChildNode}, - {"_pushNode", nativePushNode}, - {"_getNodeChild", nativeGetNodeChild}, - {"_getNodeParent", nativeGetNodeParent}, - {"_loadTexture", nativeLoadTexture}, - {"_freeTexture", nativeFreeTexture}, - {"_setRect", nativeSetRect}, - {"_drawNode", nativeDrawNode}, - {"_callNode", nativeCallNode}, - // {"getNodeTag", nativeGetNodeTag}, //not needed if there's only one node type + {"initNode", nativeInitNode}, + {"freeChildNode", nativeFreeChildNode}, + {"pushNode", nativePushNode}, + {"getNodeChild", nativeGetNodeChild}, + {"getNodeParent", nativeGetNodeParent}, + {"loadTexture", nativeLoadTexture}, + {"freeTexture", nativeFreeTexture}, + {"setRect", nativeSetRect}, + {"drawNode", nativeDrawNode}, + {"callNode", nativeCallNode}, {NULL, NULL}, }; diff --git a/box/lib_runner.c b/box/lib_runner.c index 186b6d3..04fbc57 100644 --- a/box/lib_runner.c +++ b/box/lib_runner.c @@ -44,7 +44,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu //use raw types - easier const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral)); - int filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral)); + size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral)); //load and compile the bytecode size_t fileSize = 0; @@ -138,7 +138,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr //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); + size_t 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)); @@ -159,7 +159,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr } //check for break-out attempts - for (int i = 0; i < realLength - 1; i++) { + for (size_t 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); @@ -200,7 +200,7 @@ static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArr static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _runScript\n"); + interpreter->errorOutput("Incorrect number of arguments to runScript\n"); return -1; } @@ -213,7 +213,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _runScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in runScript\n"); return -1; } @@ -241,7 +241,7 @@ static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argum static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 2) { - interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n"); + interpreter->errorOutput("Incorrect number of arguments to getScriptVar\n"); return -1; } @@ -260,7 +260,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _runScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in getScriptVar\n"); return -1; } @@ -292,7 +292,7 @@ static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* ar static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count < 2) { - interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n"); + interpreter->errorOutput("Incorrect number of arguments to callScriptFn\n"); return -1; } @@ -309,7 +309,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar Toy_LiteralArray rest; Toy_initLiteralArray(&rest); - while (tmp.count) { //correct the order of the rest args + while (tmp.count > 0) { //correct the order of the rest args Toy_Literal lit = Toy_popLiteralArray(&tmp); Toy_pushLiteralArray(&rest, lit); Toy_freeLiteral(lit); @@ -317,7 +317,6 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar Toy_freeLiteralArray(&tmp); - //get the runner object Toy_Literal varName = Toy_popLiteralArray(arguments); Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments); @@ -333,7 +332,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _runScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in callScriptFn\n"); return -1; } @@ -389,7 +388,7 @@ static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* ar static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _resetScript\n"); + interpreter->errorOutput("Incorrect number of arguments to resetScript\n"); return -1; } @@ -402,7 +401,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _runScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in resetScript\n"); return -1; } @@ -425,7 +424,7 @@ static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arg static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _freeScript\n"); + interpreter->errorOutput("Incorrect number of arguments to freeScript\n"); return -1; } @@ -438,7 +437,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in freeScript\n"); return -1; } @@ -459,7 +458,7 @@ static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { - interpreter->errorOutput("Incorrect number of arguments to _runScript\n"); + interpreter->errorOutput("Incorrect number of arguments to checkScriptDirty\n"); return -1; } @@ -472,7 +471,7 @@ static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray } if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) { - interpreter->errorOutput("Unrecognized opaque literal in _runScript\n"); + interpreter->errorOutput("Unrecognized opaque literal in checkScriptDirty\n"); return -1; } @@ -501,12 +500,12 @@ int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit Natives natives[] = { {"loadScript", nativeLoadScript}, {"loadScriptBytecode", nativeLoadScriptBytecode}, - {"_runScript", nativeRunScript}, - {"_getScriptVar", nativeGetScriptVar}, - {"_callScriptFn", nativeCallScriptFn}, - {"_resetScript", nativeResetScript}, - {"_freeScript", nativeFreeScript}, - {"_checkScriptDirty", nativeCheckScriptDirty}, + {"runScript", nativeRunScript}, + {"getScriptVar", nativeGetScriptVar}, + {"callScriptFn", nativeCallScriptFn}, + {"resetScript", nativeResetScript}, + {"freeScript", nativeFreeScript}, + {"checkScriptDirty", nativeCheckScriptDirty}, {NULL, NULL} }; @@ -617,7 +616,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr //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); + size_t 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)); @@ -630,7 +629,7 @@ Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* dr Toy_deleteRefString(drivePath); //check for break-out attempts - for (int i = 0; i < realLength - 1; i++) { + for (size_t 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 + 1); diff --git a/box/lib_standard.c b/box/lib_standard.c index 33d612f..57fdbb3 100644 --- a/box/lib_standard.c +++ b/box/lib_standard.c @@ -2,8 +2,9 @@ #include "toy_memory.h" +#include +#include #include -#include static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments @@ -18,7 +19,7 @@ static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments char* timestr = asctime(timeinfo); //push to the stack - int len = strlen(timestr) - 1; //-1 for the newline + size_t len = strlen(timestr) - 1; //-1 for the newline Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len)); //push to the stack @@ -30,6 +31,1522 @@ static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments return 1; } +static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to concat\n"); + return -1; + } + + //get the args + Toy_Literal otherLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal otherLiteralIdn = otherLiteral; + if (TOY_IS_IDENTIFIER(otherLiteral) && Toy_parseIdentifierToValue(interpreter, &otherLiteral)) { + Toy_freeLiteral(otherLiteralIdn); + } + + //for each self type + if (TOY_IS_ARRAY(selfLiteral)) { + if (!TOY_IS_ARRAY(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //append each element of other to self, one-by-one + for (int i = 0; i < TOY_AS_ARRAY(otherLiteral)->count; i++) { + Toy_pushLiteralArray(TOY_AS_ARRAY(selfLiteral), TOY_AS_ARRAY(otherLiteral)->literals[i]); + } + + //return and clean up + Toy_pushLiteralArray(&interpreter->stack, selfLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + + return 1; + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + if (!TOY_IS_DICTIONARY(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //append each element of self to other, which will overwrite existing entries + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + if (!TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + Toy_setLiteralDictionary(TOY_AS_DICTIONARY(otherLiteral), TOY_AS_DICTIONARY(selfLiteral)->entries[i].key, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + } + } + + //return and clean up + Toy_pushLiteralArray(&interpreter->stack, otherLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + + return 1; + } + + if (TOY_IS_STRING(selfLiteral)) { //a little redundant + if (!TOY_IS_STRING(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //get the combined length for the new string + size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1; + + if (length > TOY_MAX_STRING_LENGTH) { + interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in concat)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //allocate the space and generate + char* buffer = TOY_ALLOCATE(char, length); + snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral))); + + Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); + + //push and clean up + Toy_pushLiteralArray(&interpreter->stack, result); + + TOY_FREE_ARRAY(char, buffer, length); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + Toy_freeLiteral(result); + + return 1; + } + + interpreter->errorOutput("Incorrect argument type passed to concat (unknown type for self)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; +} + +static int nativeContainsKey(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to containsKey\n"); + return -1; + } + + //get the args + Toy_Literal keyLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal keyLiteralIdn = keyLiteral; + if (TOY_IS_IDENTIFIER(keyLiteral) && Toy_parseIdentifierToValue(interpreter, &keyLiteral)) { + Toy_freeLiteral(keyLiteralIdn); + } + + //check type + if (!(/* TOY_IS_ARRAY(selfLiteral) || */ TOY_IS_DICTIONARY(selfLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to containsKey\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(keyLiteral); + return -1; + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(false); + if (TOY_IS_DICTIONARY(selfLiteral) && Toy_existsLiteralDictionary( TOY_AS_DICTIONARY(selfLiteral), keyLiteral )) { + //return true of it contains the key + Toy_freeLiteral(resultLiteral); + resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); + } + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(keyLiteral); + + return 1; +} + +static int nativeContainsValue(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to containsValue\n"); + return -1; + } + + //get the args + Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal valueLiteralIdn = valueLiteral; + if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { + Toy_freeLiteral(valueLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to containsValue\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(valueLiteral); + return -1; + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(false); + if (TOY_IS_DICTIONARY(selfLiteral)) { + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + if (!TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key) && Toy_literalsAreEqual( TOY_AS_DICTIONARY(selfLiteral)->entries[i].value, valueLiteral )) { + //return true of it contains the value + Toy_freeLiteral(resultLiteral); + resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); + break; + } + } + } + else if (TOY_IS_ARRAY(selfLiteral)) { + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + Toy_Literal elementLiteral = Toy_getLiteralArray(TOY_AS_ARRAY(selfLiteral), indexLiteral); + + + if (Toy_literalsAreEqual(elementLiteral, valueLiteral)) { + Toy_freeLiteral(indexLiteral); + Toy_freeLiteral(elementLiteral); + + //return true of it contains the value + Toy_freeLiteral(resultLiteral); + resultLiteral = TOY_TO_BOOLEAN_LITERAL(true); + break; + } + + Toy_freeLiteral(indexLiteral); + Toy_freeLiteral(elementLiteral); + } + } + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(valueLiteral); + + return 1; +} + +static int nativeEvery(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to every\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to every\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + bool result = true; + + // + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + + //if not truthy + if (!TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = false; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + bool result = true; + + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + //if not truthy + if (!TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = false; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeFilter(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to filter\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to filter\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1); + Toy_initLiteralArray(result); + + // + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + + //if truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_pushLiteralArray(result, TOY_AS_ARRAY(selfLiteral)->literals[i]); + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_ARRAY_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + Toy_LiteralDictionary* result = TOY_ALLOCATE(Toy_LiteralDictionary, 1); + Toy_initLiteralDictionary(result); + + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + //if truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_setLiteralDictionary(result, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_DICTIONARY_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeForEach(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to forEach\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to forEach\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + } + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + } + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + +static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to getKeys\n"); + return -1; + } + + //get the self + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + //check type + if (!TOY_IS_DICTIONARY(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to getKeys\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //generate the result literal + Toy_LiteralArray* resultPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); + Toy_initLiteralArray(resultPtr); + + //get each key from the dictionary, pass it to the array + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + if (!TOY_IS_NULL( TOY_AS_DICTIONARY(selfLiteral)->entries[i].key )) { + Toy_pushLiteralArray(resultPtr, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + } + } + + //return the result + Toy_Literal result = TOY_TO_ARRAY_LITERAL(resultPtr); //no copy + Toy_pushLiteralArray(&interpreter->stack, result); //internal copy + + //clean up + Toy_freeLiteralArray(resultPtr); + TOY_FREE(Toy_LiteralArray, resultPtr); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to getValues\n"); + return -1; + } + + //get the self + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + //check type + if (!TOY_IS_DICTIONARY(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to getValues\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //generate the result literal + Toy_LiteralArray* resultPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); + Toy_initLiteralArray(resultPtr); + + //get each key from the dictionary, pass it to the array + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + if (!TOY_IS_NULL( TOY_AS_DICTIONARY(selfLiteral)->entries[i].key )) { + Toy_pushLiteralArray(resultPtr, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + } + } + + //return the result + Toy_Literal result = TOY_TO_ARRAY_LITERAL(resultPtr); //no copy + Toy_pushLiteralArray(&interpreter->stack, result); //internal copy + + //clean up + Toy_freeLiteralArray(resultPtr); + TOY_FREE(Toy_LiteralArray, resultPtr); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to indexOf\n"); + return -1; + } + + //get the args + Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal valueLiteralIdn = valueLiteral; + if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { + Toy_freeLiteral(valueLiteralIdn); + } + + //check type + if (!TOY_IS_ARRAY(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to indexOf\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(valueLiteral); + return -1; + } + + //search the array for the matching literal + Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL; + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + if (Toy_literalsAreEqual(valueLiteral, TOY_AS_ARRAY(selfLiteral)->literals[i])) { + resultLiteral = TOY_TO_INTEGER_LITERAL(i); + break; + } + } + + //return the result and clean up + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeMap(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to map\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to map\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); + Toy_initLiteralArray(returnsPtr); + + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + Toy_pushLiteralArray(returnsPtr, lit); + Toy_freeLiteral(lit); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + } + + Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr); + Toy_pushLiteralArray(&interpreter->stack, returnsLiteral); + Toy_freeLiteral(returnsLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + Toy_LiteralArray* returnsPtr = TOY_ALLOCATE(Toy_LiteralArray, 1); + Toy_initLiteralArray(returnsPtr); + + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + Toy_pushLiteralArray(returnsPtr, lit); + Toy_freeLiteral(lit); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + } + + Toy_Literal returnsLiteral = TOY_TO_ARRAY_LITERAL(returnsPtr); + Toy_pushLiteralArray(&interpreter->stack, returnsLiteral); + Toy_freeLiteral(returnsLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + +static int nativeReduce(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 3) { + interpreter->errorOutput("Incorrect number of arguments to reduce\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal defaultLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal defaultLiteralIdn = defaultLiteral; + if (TOY_IS_IDENTIFIER(defaultLiteral) && Toy_parseIdentifierToValue(interpreter, &defaultLiteral)) { + Toy_freeLiteral(defaultLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to reduce\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(defaultLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, defaultLiteral); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_freeLiteral(defaultLiteral); + defaultLiteral = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + } + + Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, defaultLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_freeLiteral(defaultLiteral); + defaultLiteral = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + } + + Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(defaultLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + +static int nativeSome(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to some\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to some\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + bool result = false; + + // + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + + //if not truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = true; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + bool result = false; + + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + //if not truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = true; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static void swapLiteralsUtil(Toy_Literal* lhs, Toy_Literal* rhs) { + Toy_Literal tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + +//https://www.youtube.com/watch?v=MZaf_9IZCrc +static void recursiveLiteralQuicksortUtil(Toy_Interpreter* interpreter, Toy_Literal* ptr, int literalCount, Toy_Literal fnCompareLiteral) { + //base case + if (literalCount <= 1) { + return; + } + + int runner = 0; + + //iterate through the array + for (int checker = 0; checker < literalCount - 1; checker++) { + Toy_LiteralArray arguments; + Toy_LiteralArray returns; + + Toy_initLiteralArray(&arguments); + Toy_initLiteralArray(&returns); + + Toy_pushLiteralArray(&arguments, ptr[checker]); + Toy_pushLiteralArray(&arguments, ptr[literalCount - 1]); + + Toy_callLiteralFn(interpreter, fnCompareLiteral, &arguments, &returns); + + Toy_Literal lessThan = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + if (TOY_IS_TRUTHY(lessThan)) { + swapLiteralsUtil(&ptr[runner++], &ptr[checker]); + } + + Toy_freeLiteral(lessThan); + } + + //"shift everything up" so the pivot is in the middle + swapLiteralsUtil(&ptr[runner], &ptr[literalCount - 1]); + + //recurse on each end + recursiveLiteralQuicksortUtil(interpreter, &ptr[0], runner, fnCompareLiteral); + recursiveLiteralQuicksortUtil(interpreter, &ptr[runner + 1], literalCount - runner - 1, fnCompareLiteral); +} + +static int nativeSort(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to sort\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!TOY_IS_ARRAY(selfLiteral) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to sort\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the quicksort util + if (TOY_IS_ARRAY(selfLiteral)) { + recursiveLiteralQuicksortUtil(interpreter, TOY_AS_ARRAY(selfLiteral)->literals, TOY_AS_ARRAY(selfLiteral)->count, fnLiteral); + } + + Toy_pushLiteralArray(&interpreter->stack, selfLiteral); + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toLower\n"); + return -1; + } + + //get the argument to a C-string + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + if (!TOY_IS_STRING(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to toLower\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); + const char* self = Toy_toCString(selfRefString); + + //allocate buffer space for the result + char* result = TOY_ALLOCATE(char, Toy_lengthRefString(selfRefString) + 1); + + //set each new character + for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { + result[i] = tolower(self[i]); + } + result[Toy_lengthRefString(selfRefString)] = '\0'; //end the string + + //wrap up and push the new result onto the stack + Toy_RefString* resultRefString = Toy_createRefStringLength(result, Toy_lengthRefString(selfRefString)); //internal copy + Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(resultRefString); //NO copy + + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy + + //cleanup + TOY_FREE_ARRAY(char, result, Toy_lengthRefString(resultRefString) + 1); + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static char* toStringUtilObject = NULL; +static void toStringUtil(const char* input) { + size_t len = strlen(input) + 1; + + if (len > TOY_MAX_STRING_LENGTH) { + len = TOY_MAX_STRING_LENGTH; //TODO: don't truncate + } + + toStringUtilObject = TOY_ALLOCATE(char, len); + + snprintf(toStringUtilObject, len, "%s", input); +} + +static int nativeToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toString\n"); + return -1; + } + + //get the argument + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to a value + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + //BUGFIX: probably an undefined variable + if (TOY_IS_IDENTIFIER(selfLiteral)) { + Toy_freeLiteral(selfLiteral); + return -1; + } + + //print it to a custom function + Toy_printLiteralCustom(selfLiteral, toStringUtil); + + //create the resulting string and push it + Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(toStringUtilObject)); //internal copy + + Toy_pushLiteralArray(&interpreter->stack, result); + + //cleanup + TOY_FREE_ARRAY(char, toStringUtilObject, Toy_lengthRefString( TOY_AS_STRING(result) ) + 1); + toStringUtilObject = NULL; + + Toy_freeLiteral(result); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeToUpper(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to toUpper\n"); + return -1; + } + + //get the argument to a C-string + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + if (!TOY_IS_STRING(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to toUpper\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); + const char* self = Toy_toCString(selfRefString); + + //allocate buffer space for the result + char* result = TOY_ALLOCATE(char, Toy_lengthRefString(selfRefString) + 1); + + //set each new character + for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { + result[i] = toupper(self[i]); + } + result[Toy_lengthRefString(selfRefString)] = '\0'; //end the string + + //wrap up and push the new result onto the stack + Toy_RefString* resultRefString = Toy_createRefStringLength(result, Toy_lengthRefString(selfRefString)); //internal copy + Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(resultRefString); //NO copy + + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy + + //cleanup + TOY_FREE_ARRAY(char, result, Toy_lengthRefString(resultRefString) + 1); + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeTrim(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count < 1 || arguments->count > 2) { + interpreter->errorOutput("Incorrect number of arguments to trim\n"); + return -1; + } + + //get the arguments + Toy_Literal trimCharsLiteral; + Toy_Literal selfLiteral; + + if (arguments->count == 2) { + trimCharsLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; + if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { + Toy_freeLiteral(trimCharsLiteralIdn); + } + } + else { + trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); + } + selfLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + if (!TOY_IS_STRING(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to trim\n"); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //unwrap the arguments + Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); + Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); + + //allocate space for the new string + size_t bufferBegin = 0; + size_t bufferEnd = Toy_lengthRefString(selfRefString); + + //for each character in self, check it against each character in trimChars - on a fail, go to end + for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { + int trimIndex = 0; + + while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + //there is a match - DON'T increment anymore + if (Toy_toCString(selfRefString)[i] == Toy_toCString(trimCharsRefString)[trimIndex]) { + break; + } + + trimIndex++; + } + + //if the match is found, increment buffer begin + if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + bufferBegin++; + continue; + } + else { + break; + } + } + + //again, from the back + for (int i = (int)Toy_lengthRefString(selfRefString); i >= 0; i--) { + int trimIndex = 0; + + while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + //there is a match - DON'T increment anymore + if (Toy_toCString(selfRefString)[i-1] == Toy_toCString(trimCharsRefString)[trimIndex]) { + break; + } + + trimIndex++; + } + + //if the match is found, increment buffer begin + if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + bufferEnd--; + continue; + } + else { + break; + } + } + + //generate the result + Toy_Literal resultLiteral; + if (bufferBegin >= bufferEnd) { //catch errors + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); + } + else { + char buffer[TOY_MAX_STRING_LENGTH]; + snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy + } + + //wrap up the buffer and return it + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeTrimBegin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count < 1 || arguments->count > 2) { + interpreter->errorOutput("Incorrect number of arguments to trimBegin\n"); + return -1; + } + + //get the arguments + Toy_Literal trimCharsLiteral; + Toy_Literal selfLiteral; + + if (arguments->count == 2) { + trimCharsLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; + if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { + Toy_freeLiteral(trimCharsLiteralIdn); + } + } + else { + trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); + } + selfLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + if (!TOY_IS_STRING(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to trimBegin\n"); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //unwrap the arguments + Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); + Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); + + //allocate space for the new string + size_t bufferBegin = 0; + size_t bufferEnd = Toy_lengthRefString(selfRefString); + + //for each character in self, check it against each character in trimChars - on a fail, go to end + for (int i = 0; i < (int)Toy_lengthRefString(selfRefString); i++) { + int trimIndex = 0; + + while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + //there is a match - DON'T increment anymore + if (Toy_toCString(selfRefString)[i] == Toy_toCString(trimCharsRefString)[trimIndex]) { + break; + } + + trimIndex++; + } + + //if the match is found, increment buffer begin + if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + bufferBegin++; + continue; + } + else { + break; + } + } + + //generate the result + Toy_Literal resultLiteral; + if (bufferBegin >= bufferEnd) { //catch errors + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); + } + else { + char buffer[TOY_MAX_STRING_LENGTH]; + snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy + } + + //wrap up the buffer and return it + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeTrimEnd(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count < 1 || arguments->count > 2) { + interpreter->errorOutput("Incorrect number of arguments to trimEnd\n"); + return -1; + } + + //get the arguments + Toy_Literal trimCharsLiteral; + Toy_Literal selfLiteral; + + if (arguments->count == 2) { + trimCharsLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal trimCharsLiteralIdn = trimCharsLiteral; + if (TOY_IS_IDENTIFIER(trimCharsLiteral) && Toy_parseIdentifierToValue(interpreter, &trimCharsLiteral)) { + Toy_freeLiteral(trimCharsLiteralIdn); + } + } + else { + trimCharsLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(" \t\n\r")); + } + selfLiteral = Toy_popLiteralArray(arguments); + + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + if (!TOY_IS_STRING(selfLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to trimEnd\n"); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //unwrap the arguments + Toy_RefString* trimCharsRefString = TOY_AS_STRING(trimCharsLiteral); + Toy_RefString* selfRefString = TOY_AS_STRING(selfLiteral); + + //allocate space for the new string + size_t bufferBegin = 0; + size_t bufferEnd = Toy_lengthRefString(selfRefString); + + //again, from the back + for (int i = (int)Toy_lengthRefString(selfRefString); i >= 0; i--) { + int trimIndex = 0; + + while (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + //there is a match - DON'T increment anymore + if (Toy_toCString(selfRefString)[i-1] == Toy_toCString(trimCharsRefString)[trimIndex]) { + break; + } + + trimIndex++; + } + + //if the match is found, increment buffer begin + if (trimIndex < (int)Toy_lengthRefString(trimCharsRefString)) { + bufferEnd--; + continue; + } + else { + break; + } + } + + //generate the result + Toy_Literal resultLiteral; + if (bufferBegin >= bufferEnd) { //catch errors + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("")); + } + else { + char buffer[TOY_MAX_STRING_LENGTH]; + snprintf(buffer, bufferEnd - bufferBegin + 1, "%s", &Toy_toCString(selfRefString)[ bufferBegin ]); + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); //internal copy + } + + //wrap up the buffer and return it + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); //internal copy + + //cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(trimCharsLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + //call the hook typedef struct Natives { char* name; @@ -40,6 +1557,25 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L //build the natives list Natives natives[] = { {"clock", nativeClock}, + {"concat", nativeConcat}, //array, dictionary, string + {"containsKey", nativeContainsKey}, //dictionary + {"containsValue", nativeContainsValue}, //array, dictionary + {"every", nativeEvery}, //array, dictionary + {"filter", nativeFilter}, //array, dictionary + {"forEach", nativeForEach}, //array, dictionary + {"getKeys", nativeGetKeys}, //dictionary + {"getValues", nativeGetValues}, //dictionary + {"indexOf", nativeIndexOf}, //array + {"map", nativeMap}, //array, dictionary + {"reduce", nativeReduce}, //array, dictionary + {"some", nativeSome}, //array, dictionary + {"sort", nativeSort}, //array + {"toLower", nativeToLower}, //string + {"toString", nativeToString}, //array, dictionary + {"toUpper", nativeToUpper}, //string + {"trim", nativeTrim}, //string + {"trimBegin", nativeTrimBegin}, //string + {"trimEnd", nativeTrimEnd}, //string {NULL, NULL} }; diff --git a/box/lib_timer.c b/box/lib_timer.c deleted file mode 100644 index d05011e..0000000 --- a/box/lib_timer.c +++ /dev/null @@ -1,411 +0,0 @@ -#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 -1; - } - - //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_NATIVE_LITERAL(natives[i].fn); - - 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 deleted file mode 100644 index 90193e8..0000000 --- a/box/lib_timer.h +++ /dev/null @@ -1,6 +0,0 @@ -#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 index 7018e93..141ba4d 100644 --- a/box/repl_tools.c +++ b/box/repl_tools.c @@ -1,8 +1,6 @@ #include "repl_tools.h" #include "lib_about.h" -#include "lib_compound.h" #include "lib_standard.h" -#include "lib_timer.h" #include "lib_runner.h" #include "toy_console_colors.h" @@ -57,7 +55,7 @@ int Toy_writeFile(const char* path, const unsigned char* bytes, size_t size) { return -1; } - int written = fwrite(bytes, size, 1, file); + size_t written = fwrite(bytes, size, 1, file); if (written != 1) { fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path); @@ -113,12 +111,10 @@ void Toy_runBinary(const unsigned char* tb, size_t size) { //inject the libs Toy_injectNativeHook(&interpreter, "about", Toy_hookAbout); - Toy_injectNativeHook(&interpreter, "compound", Toy_hookCompound); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); - Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); - Toy_runInterpreter(&interpreter, tb, size); + Toy_runInterpreter(&interpreter, tb, (int)size); Toy_freeInterpreter(&interpreter); }