diff --git a/Toy b/Toy index b2c3dd8..e4d843a 160000 --- a/Toy +++ b/Toy @@ -1 +1 @@ -Subproject commit b2c3dd894c23e09c5d65fc020cefb6daf20c13f8 +Subproject commit e4d843ad3a4a16cfd2ac5e40878d98063ca60738 diff --git a/assets/scripts/init.toy b/assets/scripts/init.toy index 9ddcb25..4e1ad0b 100644 --- a/assets/scripts/init.toy +++ b/assets/scripts/init.toy @@ -28,4 +28,4 @@ mapInputEventToKeyUp("character_right", "right"); //event, keysym initWindow("Airport Game", 800, 600, false); //kick off the logic of the scene graph -loadRootNode("assets/scripts/root.toy"); +loadRootNode("scripts:/root.toy"); diff --git a/assets/scripts/root.toy b/assets/scripts/root.toy index c5cc326..eaa53c2 100644 --- a/assets/scripts/root.toy +++ b/assets/scripts/root.toy @@ -14,10 +14,10 @@ fn onInit(node: opaque) { print "root.toy:onInit() called"; //make a child - node.makeChild("assets/scripts/entity.toy"); + node.makeChild("scripts:/entity.toy"); //give the child a child - node.getNodeChild(0).makeChild("assets/scripts/entity.toy"); + node.getNodeChild(0).makeChild("scripts:/entity.toy"); } fn onStep(node: opaque) { diff --git a/box/lib_engine.c b/box/lib_engine.c index 0ce5ef4..dfb79da 100644 --- a/box/lib_engine.c +++ b/box/lib_engine.c @@ -8,6 +8,8 @@ #include "toy_console_colors.h" +#include "lib_runner.h" + //errors here should be fatal static void fatalError(char* message) { fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, message); @@ -84,17 +86,26 @@ static int nativeLoadRootNode(Toy_Interpreter* interpreter, Toy_LiteralArray* ar } //extract the arguments - Toy_Literal fname = Toy_popLiteralArray(arguments); + Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments); - Toy_Literal fnameIdn = fname; - if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) { - Toy_freeLiteral(fnameIdn); + Toy_Literal drivePathLiteralIdn = drivePathLiteral; + if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) { + Toy_freeLiteral(drivePathLiteralIdn); } //check argument types - if (!TOY_IS_STRING(fname)) { + if (!TOY_IS_STRING(drivePathLiteral)) { interpreter->errorOutput("Incorrect argument type passed to loadRootNode\n"); - Toy_freeLiteral(fname); + Toy_freeLiteral(drivePathLiteral); + return -1; + } + + Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral); + + Toy_freeLiteral(drivePathLiteral); //not needed anymore + + if (!TOY_IS_STRING(filePathLiteral)) { + Toy_freeLiteral(filePathLiteral); return -1; } @@ -110,7 +121,7 @@ static int nativeLoadRootNode(Toy_Interpreter* interpreter, Toy_LiteralArray* ar //load the new root node size_t size = 0; - char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size); + char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(filePathLiteral)), &size); unsigned char* tb = Toy_compileString(source, &size); free((void*)source); @@ -142,7 +153,7 @@ static int nativeLoadRootNode(Toy_Interpreter* interpreter, Toy_LiteralArray* ar //cleanup Toy_freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.literalCache); - Toy_freeLiteral(fname); + Toy_freeLiteral(filePathLiteral); return 0; } diff --git a/box/lib_node.c b/box/lib_node.c index 8759ac3..c962eca 100644 --- a/box/lib_node.c +++ b/box/lib_node.c @@ -7,6 +7,8 @@ #include "toy_literal_array.h" #include "toy_memory.h" +#include "lib_runner.h" + #include static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { @@ -16,23 +18,27 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume } //extract the arguments - Toy_Literal fname = Toy_popLiteralArray(arguments); + Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments); - Toy_Literal fnameIdn = fname; - if (TOY_IS_IDENTIFIER(fname) && Toy_parseIdentifierToValue(interpreter, &fname)) { - Toy_freeLiteral(fnameIdn); + Toy_Literal drivePathLiteralIdn = drivePathLiteral; + if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) { + Toy_freeLiteral(drivePathLiteralIdn); } //check argument types - if (!TOY_IS_STRING(fname)) { + if (!TOY_IS_STRING(drivePathLiteral)) { interpreter->errorOutput("Incorrect argument type passed to loadNode\n"); - Toy_freeLiteral(fname); + Toy_freeLiteral(drivePathLiteral); return -1; } + Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral); + + Toy_freeLiteral(drivePathLiteral); //not needed anymore + //load the new node size_t size = 0; - char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(fname)), &size); + char* source = Toy_readFile(Toy_toCString(TOY_AS_STRING(filePathLiteral)), &size); unsigned char* tb = Toy_compileString(source, &size); free((void*)source); @@ -65,7 +71,7 @@ static int nativeLoadNode(Toy_Interpreter* interpreter, Toy_LiteralArray* argume //cleanup Toy_freeLiteralArray(&inner.stack); Toy_freeLiteralArray(&inner.literalCache); - Toy_freeLiteral(fname); + Toy_freeLiteral(filePathLiteral); Toy_freeLiteral(nodeLiteral); return 1; diff --git a/box/lib_runner.c b/box/lib_runner.c index 9433873..50b9576 100644 --- a/box/lib_runner.c +++ b/box/lib_runner.c @@ -24,69 +24,34 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu return -1; } - //get the argument + //get the file path literal with a handle Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments); - Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral)); + Toy_Literal filePathLiteral = Toy_getFilePathLiteral(interpreter, &drivePathLiteral); - //get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library - int driveLength = 0; - while (Toy_toCString(drivePath)[driveLength] != ':') { - if (driveLength >= Toy_lengthRefString(drivePath)) { - interpreter->errorOutput("Incorrect drive path format given to loadScript\n"); - Toy_deleteRefString(drivePath); - Toy_freeLiteral(drivePathLiteral); - return -1; - } - - driveLength++; - } - - Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength); - Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength ); - - //get the real drive file path - Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString - Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral); - - if (!TOY_IS_STRING(realDriveLiteral)) { - interpreter->errorOutput("Incorrect literal type found for drive: "); - Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput); - interpreter->errorOutput("\n"); - Toy_freeLiteral(realDriveLiteral); - Toy_freeLiteral(driveLiteral); - Toy_deleteRefString(path); - Toy_deleteRefString(drivePath); + if (TOY_IS_NULL(filePathLiteral)) { + Toy_freeLiteral(filePathLiteral); Toy_freeLiteral(drivePathLiteral); return -1; } - //get the final real file path (concat) TODO: move this concat to refstring library - Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral)); - int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path); - - char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null - snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path)); - - //clean up the drivepath stuff - Toy_deleteRefString(realDrive); - Toy_freeLiteral(realDriveLiteral); - Toy_freeLiteral(driveLiteral); - Toy_deleteRefString(path); - Toy_deleteRefString(drivePath); Toy_freeLiteral(drivePathLiteral); + //use raw types - easier + char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral)); + int filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral)); + //check for file extensions - if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) { + if (!(filePath[filePathLength - 5] == '.' && filePath[filePathLength - 4] == 't' && filePath[filePathLength - 3] == 'o' && filePath[filePathLength - 2] == 'y')) { interpreter->errorOutput("Bad script file extension (expected .toy)\n"); - TOY_FREE_ARRAY(char, filePath, realLength); + Toy_freeLiteral(filePathLiteral); return -1; } //check for break-out attempts - for (int i = 0; i < realLength - 1; i++) { + for (int i = 0; i < filePathLength - 1; i++) { if (filePath[i] == '.' && filePath[i + 1] == '.') { interpreter->errorOutput("Parent directory access not allowed\n"); - TOY_FREE_ARRAY(char, filePath, realLength); + Toy_freeLiteral(filePathLiteral); return -1; } } @@ -97,6 +62,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu if (!source) { interpreter->errorOutput("Failed to load source file\n"); + Toy_freeLiteral(filePathLiteral); return -1; } @@ -105,6 +71,7 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu if (!bytecode) { interpreter->errorOutput("Failed to compile source file\n"); + Toy_freeLiteral(filePathLiteral); return -1; } @@ -124,7 +91,8 @@ static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* argu Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER); Toy_pushLiteralArray(&interpreter->stack, runnerLiteral); - TOY_FREE_ARRAY(char, filePath, realLength); + //free the drive path + Toy_freeLiteral(filePathLiteral); return 1; } @@ -610,4 +578,65 @@ void Toy_freeDriveDictionary() { Toy_LiteralDictionary* Toy_getDriveDictionary() { return &Toy_driveDictionary; +} + +Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral) { + //check argument types + if (!TOY_IS_STRING(*drivePathLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to Toy_getFilePathLiteral\n"); + return TOY_TO_NULL_LITERAL; + } + + Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(*drivePathLiteral)); + + //get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library + int driveLength = 0; + while (Toy_toCString(drivePath)[driveLength] != ':') { + if (driveLength >= Toy_lengthRefString(drivePath)) { + interpreter->errorOutput("Incorrect drive path format given to Toy_getFilePathLiteral\n"); + + return TOY_TO_NULL_LITERAL; + } + + driveLength++; + } + + Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength); + Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength ); + + //get the real drive file path + Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString + Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral); + + if (!TOY_IS_STRING(realDriveLiteral)) { + interpreter->errorOutput("Incorrect literal type found for drive: "); + Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput); + interpreter->errorOutput("\n"); + Toy_freeLiteral(realDriveLiteral); + Toy_freeLiteral(driveLiteral); + Toy_deleteRefString(path); + Toy_deleteRefString(drivePath); + + return TOY_TO_NULL_LITERAL; + } + + //get the final real file path (concat) TODO: move this concat to refstring library + Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral)); + int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path); + + char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null + snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path)); + + //clean up the drivepath stuff + Toy_deleteRefString(realDrive); + Toy_freeLiteral(realDriveLiteral); + Toy_freeLiteral(driveLiteral); + Toy_deleteRefString(path); + Toy_deleteRefString(drivePath); + + Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(filePath, realLength)); + + TOY_FREE_ARRAY(char, filePath, realLength + 1); + + return result; } \ No newline at end of file diff --git a/box/lib_runner.h b/box/lib_runner.h index 1912de4..661ec39 100644 --- a/box/lib_runner.h +++ b/box/lib_runner.h @@ -10,3 +10,6 @@ void Toy_freeDriveDictionary(); Toy_LiteralDictionary* Toy_getDriveDictionary(); #define TOY_OPAQUE_TAG_RUNNER 100 + +//file system API - for use with other libs +Toy_Literal Toy_getFilePathLiteral(Toy_Interpreter* interpreter, Toy_Literal* drivePathLiteral); diff --git a/test/test_engine_node.c b/test/test_engine_node.c index 41149ee..d696889 100644 --- a/test/test_engine_node.c +++ b/test/test_engine_node.c @@ -1,12 +1,13 @@ -#include "engine_node.h" +#include "box_engine_node.h" + +#include "toy_lexer.h" +#include "toy_parser.h" +#include "toy_compiler.h" +#include "toy_interpreter.h" +#include "toy_console_colors.h" +#include "toy_memory.h" -#include "lexer.h" -#include "parser.h" -#include "compiler.h" -#include "interpreter.h" #include "repl_tools.h" -#include "console_colors.h" -#include "memory.h" #include #include @@ -20,88 +21,90 @@ static void noPrintFn(const char* output) { int main() { { //setup interpreter - Interpreter interpreter; - initInterpreter(&interpreter); - setInterpreterPrint(&interpreter, noPrintFn); + Toy_Interpreter interpreter; + Toy_initInterpreter(&interpreter); + Toy_setInterpreterPrint(&interpreter, noPrintFn); size_t size = 0; - char* source = readFile("./scripts/parent_engine_node.toy", &size); - unsigned char* tb = compileString(source, &size); + char* source = Toy_readFile("./scripts/parent_engine_node.toy", &size); + unsigned char* tb = Toy_compileString(source, &size); //create and test the engine node - EngineNode* node = ALLOCATE(EngineNode, 1); + Box_EngineNode* node = TOY_ALLOCATE(Box_EngineNode, 1); - initEngineNode(node, &interpreter, tb, size); + Box_initEngineNode(node, &interpreter, tb, size); - Literal nodeLiteral = TO_OPAQUE_LITERAL(node, OPAQUE_TAG_ENGINE_NODE); + Toy_Literal nodeLiteral = TOY_TO_OPAQUE_LITERAL(node, OPAQUE_TAG_ENGINE_NODE); //argument list to pass in the node - LiteralArray arguments; - initLiteralArray(&arguments); + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); //call each function - callRecursiveEngineNode(node, &interpreter, "onInit", &arguments); - callRecursiveEngineNode(node, &interpreter, "onStep", &arguments); - callRecursiveEngineNode(node, &interpreter, "onQuit", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onInit", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onStep", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onQuit", &arguments); //cleanup - freeLiteralArray(&arguments); - freeEngineNode(node); + Toy_freeLiteralArray(&arguments); + Box_freeEngineNode(node); free((void*)source); - freeInterpreter(&interpreter); + + Toy_freeInterpreter(&interpreter); } { //setup interpreter - Interpreter interpreter; - initInterpreter(&interpreter); - setInterpreterPrint(&interpreter, noPrintFn); + Toy_Interpreter interpreter; + Toy_initInterpreter(&interpreter); + Toy_setInterpreterPrint(&interpreter, noPrintFn); size_t size = 0; - char* source = readFile("./scripts/parent_engine_node.toy", &size); - unsigned char* tb = compileString(source, &size); + char* source = Toy_readFile("./scripts/parent_engine_node.toy", &size); + unsigned char* tb = Toy_compileString(source, &size); //create and test the engine node - EngineNode* node = ALLOCATE(EngineNode, 1); + Box_EngineNode* node = TOY_ALLOCATE(Box_EngineNode, 1); - initEngineNode(node, &interpreter, tb, size); - resetInterpreter(&interpreter); + Box_initEngineNode(node, &interpreter, tb, size); + Toy_resetInterpreter(&interpreter); for (int i = 0; i < 10; i++) { - char* source = readFile("./scripts/child_engine_node.toy", &size); - unsigned char* tb = compileString(source, &size); + char* source = Toy_readFile("./scripts/child_engine_node.toy", &size); + unsigned char* tb = Toy_compileString(source, &size); - EngineNode* child = ALLOCATE(EngineNode, 1); - initEngineNode(child, &interpreter, tb, size); - resetInterpreter(&interpreter); + Box_EngineNode* child = TOY_ALLOCATE(Box_EngineNode, 1); + Box_initEngineNode(child, &interpreter, tb, size); + Toy_resetInterpreter(&interpreter); - pushEngineNode(node, child); + Box_pushEngineNode(node, child); free((void*)source); } //argument list to pass in each time - LiteralArray arguments; - initLiteralArray(&arguments); + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); //test the calls - callRecursiveEngineNode(node, &interpreter, "onInit", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onInit", &arguments); for (int i = 0; i < 10; i++) { - callRecursiveEngineNode(node, &interpreter, "onStep", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onStep", &arguments); } - callRecursiveEngineNode(node, &interpreter, "onFree", &arguments); + Box_callRecursiveEngineNode(node, &interpreter, "onFree", &arguments); //cleanup - freeLiteralArray(&arguments); - freeEngineNode(node); //frees all children + Toy_freeLiteralArray(&arguments); + Box_freeEngineNode(node); //frees all children free((void*)source); - freeInterpreter(&interpreter); + + Toy_freeInterpreter(&interpreter); } - printf(NOTICE "All good\n" RESET); + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); return 0; }