From 43b58eb421d7ce0c09022dbda5d56f802fea23f0 Mon Sep 17 00:00:00 2001 From: Add00 Date: Fri, 4 Aug 2023 23:13:43 -0400 Subject: [PATCH] Library rename, added HAL, added open function --- repl/hal_file.c | 88 ++++++++++++++ repl/hal_file.h | 63 ++++++++++ repl/lib_fileio.c | 224 ++++++++++++++++++++++++++++++++++++ repl/lib_fileio.h | 5 + repl/lib_io.c | 14 --- repl/lib_io.h | 5 - repl/repl_main.c | 4 +- repl/repl_tools.c | 4 +- test/scripts/lib/fileio.toy | 20 ++++ test/scripts/lib/fileio.txt | 1 + test/scripts/lib/io.toy | 1 - test/test_libraries.c | 4 +- 12 files changed, 407 insertions(+), 26 deletions(-) create mode 100644 repl/hal_file.c create mode 100644 repl/hal_file.h create mode 100644 repl/lib_fileio.c create mode 100644 repl/lib_fileio.h delete mode 100644 repl/lib_io.c delete mode 100644 repl/lib_io.h create mode 100644 test/scripts/lib/fileio.toy create mode 100644 test/scripts/lib/fileio.txt delete mode 100644 test/scripts/lib/io.toy diff --git a/repl/hal_file.c b/repl/hal_file.c new file mode 100644 index 0000000..c65e87d --- /dev/null +++ b/repl/hal_file.c @@ -0,0 +1,88 @@ +#include "hal_file.h" + +#include +#include + +typedef struct hal_file_type { + FILE* fp; +} hal_file; + +// Initialization logic, if needed +hal_file_code setup() { + return HAL_SUCCESS; +} + +hal_file_code open(hal_file** file, const char* filename, const char* mode) { + if (!file || !filename || !mode) { + return HAL_ERROR_INPUT; + } + + *file = (hal_file*)malloc(sizeof(hal_file)); + if (!(*file)) { + return HAL_ERROR_ALLOC; + } + + (*file)->fp = fopen(filename, mode); + if (!(*file)->fp) { + free(*file); + return HAL_ERROR_OPEN; + } + + return HAL_SUCCESS; +} + +hal_file_code read(hal_file* file, char* buffer, const int size) { + if (!file || !file->fp || !buffer || size <= 0) { + return HAL_ERROR_INPUT; + } + + if (fgets(buffer, size, file->fp) == NULL) { + return HAL_ERROR_READ; + } + + return HAL_SUCCESS; +} + +hal_file_code write(hal_file* file, const char* message) { + if (!file || !file->fp || !message) { + return HAL_ERROR_INPUT; + } + + if (fputs(message, file->fp) == EOF) { + return HAL_ERROR_WRITE; + } + + return HAL_SUCCESS; +} + +hal_file_code close(hal_file* file) { + if (!file || !file->fp) { + return HAL_ERROR_INPUT; + } + + if (fclose(file->fp) != 0) { + return HAL_ERROR_CLOSE; + } + + free(file); + return HAL_SUCCESS; +} + +// deletion logic, if needed +hal_file_code teardown() { + return HAL_SUCCESS; +} + +// Expose into global variable +hal_file_operations hal_file_manager = { + .setup = setup, + .open = open, + .read = read, + .write = write, + .close = close, + .teardown = teardown +}; + +const int HAL_MAX_FILENAME_SIZE = FILENAME_MAX; +const int HAL_MAX_FILES_OPEN = FOPEN_MAX; +const int HAL_EOF = EOF; \ No newline at end of file diff --git a/repl/hal_file.h b/repl/hal_file.h new file mode 100644 index 0000000..4fd89cd --- /dev/null +++ b/repl/hal_file.h @@ -0,0 +1,63 @@ +#pragma once + +// Enumeration of all file-related error codes +typedef enum hal_file_code { + HAL_SUCCESS, // Operation was successful + HAL_ERROR_INIT, // Error during initialization + HAL_ERROR_ALLOC, // Memory allocation error + HAL_ERROR_OPEN, // Error while opening a file + HAL_ERROR_INPUT, // Invalid input parameter(s) + HAL_ERROR_READ, // Error while reading from a file + HAL_ERROR_WRITE, // Error while writing to a file + HAL_ERROR_CLOSE, // Error while closing a file + HAL_ERROR_TEARDOWN, // Error during teardown + HAL_ERROR_MAX, // Maximum error code value (used for range checking) +} hal_file_code; + +// Forward declaration of the implementation defined file structure +typedef struct hal_file_type hal_file; + +// Structure for different file operation functions +typedef struct hal_file_operations { + // Function: setup + // Initialize the file handling system. + // Returns: HAL_SUCCESS on successful initialization, or appropriate error code on failure. + hal_file_code (*setup)(); + + // Function: open + // Open a file with the specified filename and mode. + // Returns: HAL_SUCCESS on successful read, or appropriate error code on failure. + hal_file_code (*open)(hal_file** file, const char* filename, const char* mode); + + // Function: read + // Read data from the file into the provided buffer. + // Returns: HAL_SUCCESS on successful read, or appropriate error code on failure. + hal_file_code (*read)(hal_file* file, char* buffer, const int size); + + // Function: write + // Write the provided message to the file. + // Returns: HAL_SUCCESS on successful write, or appropriate error code on failure. + hal_file_code (*write)(hal_file* file, const char* message); + + // Function: close + // Close the file and release associated resources. + // Returns: HAL_SUCCESS on successful close, or appropriate error code on failure. + hal_file_code (*close)(hal_file* file); + + // Function: teardown + // Perform necessary cleanup and teardown operations for the file handling system. + // Returns: HAL_SUCCESS on successful teardown, or appropriate error code on failure. + hal_file_code (*teardown)(); +} hal_file_operations; + +// Global variable to access file operations +extern hal_file_operations hal_file_manager; + +// Maximum size of a filename supported by implementation +extern const int HAL_MAX_FILENAME_SIZE; + +// Maximum number of files that can be open simultaneously by implementation +extern const int HAL_MAX_FILES_OPEN; + +// End-of-File (EOF) indicator value defined by implementation +extern const int HAL_EOF; \ No newline at end of file diff --git a/repl/lib_fileio.c b/repl/lib_fileio.c new file mode 100644 index 0000000..8de32e3 --- /dev/null +++ b/repl/lib_fileio.c @@ -0,0 +1,224 @@ +#include "lib_fileio.h" +#include "toy_memory.h" + +#include "hal_file.h" + +typedef struct Toy_File +{ + hal_file* fp; + int error; + int size; +} Toy_File; + +static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count < 1 || arguments->count > 2) { + interpreter->errorOutput("Incorrect number of arguments to open\n"); + return -1; + } + + Toy_Literal modeLiteral = arguments->count == 2? Toy_popLiteralArray(arguments) : TOY_TO_STRING_LITERAL(Toy_createRefString("r")); + Toy_Literal filenameLiteral = Toy_popLiteralArray(arguments); + + // parse the filename (if it's an identifier) + Toy_Literal filenameLiteralIdn = filenameLiteral; + if (TOY_IS_IDENTIFIER(filenameLiteral) && Toy_parseIdentifierToValue(interpreter, &filenameLiteral)) { + Toy_freeLiteral(filenameLiteralIdn); + } + + // check the filename type + if (!TOY_IS_STRING(filenameLiteral)) { + interpreter->errorOutput("open(string, string) incorrect type for the first parameter expected: string\n"); + Toy_freeLiteral(filenameLiteral); + } + + // parse the mode (if it's an identifier) + Toy_Literal modeLiteralIdn = modeLiteral; + if (TOY_IS_IDENTIFIER(modeLiteral) && Toy_parseIdentifierToValue(interpreter, &modeLiteral)) { + Toy_freeLiteral(modeLiteralIdn); + } + + // check the mode type + if (!TOY_IS_STRING(modeLiteral)) { + interpreter->errorOutput("open(string, string) incorrect type for the second parameter expected: string\n"); + Toy_freeLiteral(modeLiteral); + } + + const char* filename = Toy_toCString(TOY_AS_STRING(filenameLiteral)); + const char* mode = Toy_toCString(TOY_AS_STRING(modeLiteral)); + + static int tag = 0; + bool error = false; + hal_file* fp = NULL; + + // attempt to open file + hal_file_code code = hal_file_manager.open(&fp, filename, mode); + if (code != HAL_SUCCESS) { + error = true; + } + + // set size + int size = 0; + + // if (!error) { + // fseek(fp, 0, SEEK_END); + + // // pervent integer overflow as ftell returns a long + // size = ftell(fp) > INT_MAX? INT_MAX : ftell(fp); + + // fseek(fp, 0, SEEK_SET); + // } + + // result + Toy_LiteralDictionary* result = TOY_ALLOCATE(Toy_LiteralDictionary, 1); + Toy_initLiteralDictionary(result); + + Toy_Literal fileKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("_file")); + Toy_Literal fileLiteral = TOY_TO_OPAQUE_LITERAL(fp, tag); + + Toy_Literal errorKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("error")); + Toy_Literal errorLiteral = TOY_TO_BOOLEAN_LITERAL(error); + + Toy_Literal sizeKeyLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("size")); + Toy_Literal sizeLiteral = TOY_TO_INTEGER_LITERAL(size); + + Toy_setLiteralDictionary(result, fileKeyLiteral, fileLiteral); + Toy_setLiteralDictionary(result, errorKeyLiteral, errorLiteral); + Toy_setLiteralDictionary(result, sizeKeyLiteral, sizeLiteral); + + Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString("File")); + Toy_Literal resultLiteral = TOY_TO_DICTIONARY_LITERAL(result); + + Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); + Toy_Literal stringType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true); + Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true); + TOY_TYPE_PUSH_SUBTYPE(&type, stringType); + TOY_TYPE_PUSH_SUBTYPE(&type, anyType); + + + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(type); + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(filenameLiteral); + Toy_freeLiteral(modeLiteral); + + tag++; + + return 1; +} + +static int nativeClose(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + // if (arguments->count != 1) { + // interpreter->errorOutput("Incorrect number of arguments to open\n"); + // return -1; + // } + + // Toy_Literal fileLiteral = Toy_popLiteralArray(arguments); + + // // parse the file (if it's an identifier) + // Toy_Literal fileLiteralIdn = fileLiteral; + // if (TOY_IS_IDENTIFIER(fileLiteral) && Toy_parseIdentifierToValue(interpreter, &fileLiteral)) { + // Toy_freeLiteral(fileLiteralIdn); + // } + + // // check the file type + // if (!TOY_IS_STRING(fileLiteral)) { + // interpreter->errorOutput("close(File) incorrect type for the first parameter expected: File\n"); + // Toy_freeLiteral(fileLiteral); + // } + + // FILE* fp = (FILE*)TOY_AS_OPAQUE(fileLiteral); + + // Toy_freeLiteral(fileLiteral); + + return 1; +} + +//call the hook +typedef struct Natives { + char* name; + Toy_NativeFn fn; +} Natives; + +typedef struct Variable { + Toy_Literal key; + Toy_Literal identifier; + Toy_Literal literal; +} Variable; + +// Helper function create a variable +void createToyVariable(Variable* variable, char* key, int literal) { + variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key)); + variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key)); + variable->literal = TOY_TO_INTEGER_LITERAL(literal); +} + +// Helper function to clean up variables +void deleteToyVariables(Variable variables[], int size) { + for (int i = 0; i < size; i++) { + Toy_freeLiteral(variables[i].key); + Toy_freeLiteral(variables[i].identifier); + Toy_freeLiteral(variables[i].literal); + } + +} + +bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) { + for (int i = 0; i < size; i++) { + if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) { + interpreter->errorOutput("Can't override an existing variable\n"); + + deleteToyVariables(variables, size); + + return true; + } + } + + return false; +} + +void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) { + Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, true); + + for (int i = 0; i < size; i++) { + Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType); + Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, false); + } + + Toy_freeLiteral(intType); +} + +int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { + //build the natives list + Natives natives[] = { + // Access + {"open", nativeOpen}, + {"close", nativeClose}, + + {NULL, NULL} + }; + + + //default + for (int i = 0; natives[i].name; i++) { + Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn); + } + + const int VARIABLES_SIZE = 3; + Variable variables[VARIABLES_SIZE]; + + createToyVariable(&variables[0], "MAX_FILENAME_SIZE", HAL_MAX_FILENAME_SIZE); + createToyVariable(&variables[1], "MAX_FILES_OPEN", HAL_MAX_FILES_OPEN); + createToyVariable(&variables[2], "END_OF_FILE", HAL_EOF); + + if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) { + return -1; + } + + exposeVariablesToScope(interpreter, variables, VARIABLES_SIZE); + + deleteToyVariables(variables, VARIABLES_SIZE); + + return 0; +} diff --git a/repl/lib_fileio.h b/repl/lib_fileio.h new file mode 100644 index 0000000..1f01e7e --- /dev/null +++ b/repl/lib_fileio.h @@ -0,0 +1,5 @@ +#pragma once + +#include "toy_interpreter.h" + +int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); diff --git a/repl/lib_io.c b/repl/lib_io.c deleted file mode 100644 index 70b1944..0000000 --- a/repl/lib_io.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "lib_io.h" - -#include - -//call the hook -typedef struct Natives { - char* name; - Toy_NativeFn fn; -} Natives; - - -int Toy_hookIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { - return 1; -} \ No newline at end of file diff --git a/repl/lib_io.h b/repl/lib_io.h deleted file mode 100644 index ec7264c..0000000 --- a/repl/lib_io.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "toy_interpreter.h" - -int Toy_hookIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias); diff --git a/repl/repl_main.c b/repl/repl_main.c index cf91d5b..48a49bb 100644 --- a/repl/repl_main.c +++ b/repl/repl_main.c @@ -4,8 +4,8 @@ #include "lib_standard.h" #include "lib_random.h" #include "lib_runner.h" +#include "lib_fileio.h" #include "lib_math.h" -#include "lib_io.h" #include "toy_console_colors.h" @@ -32,8 +32,8 @@ void repl(const char* initialInput) { Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); + Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO); Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); - Toy_injectNativeHook(&interpreter, "io", Toy_hookIO); for(;;) { if (!initialInput) { diff --git a/repl/repl_tools.c b/repl/repl_tools.c index 07d31ff..4de67a8 100644 --- a/repl/repl_tools.c +++ b/repl/repl_tools.c @@ -3,8 +3,8 @@ #include "lib_standard.h" #include "lib_random.h" #include "lib_runner.h" +#include "lib_fileio.h" #include "lib_math.h" -#include "lib_io.h" #include "toy_console_colors.h" @@ -117,8 +117,8 @@ void Toy_runBinary(const unsigned char* tb, size_t size) { Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); + Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO); Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); - Toy_injectNativeHook(&interpreter, "io", Toy_hookIO); Toy_runInterpreter(&interpreter, tb, (int)size); Toy_freeInterpreter(&interpreter); diff --git a/test/scripts/lib/fileio.toy b/test/scripts/lib/fileio.toy new file mode 100644 index 0000000..c59cbd3 --- /dev/null +++ b/test/scripts/lib/fileio.toy @@ -0,0 +1,20 @@ +import fileio; + +// test constants +{ + // print MAX_FILENAME_SIZE; + // print MAX_FILES_OPEN; + // print END_OF_FILE; + + assert END_OF_FILE < 0, "END_OF_FILE failed"; +} + +// test open +{ + var file = open("doesNotExist.txt", "r"); + + assert file["error"] == true, "error failed"; + assert file["size"] == 0, "size failed"; + + // close(file); +} \ No newline at end of file diff --git a/test/scripts/lib/fileio.txt b/test/scripts/lib/fileio.txt new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/test/scripts/lib/fileio.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/test/scripts/lib/io.toy b/test/scripts/lib/io.toy deleted file mode 100644 index b55d06e..0000000 --- a/test/scripts/lib/io.toy +++ /dev/null @@ -1 +0,0 @@ -print "Nothing is here"; \ No newline at end of file diff --git a/test/test_libraries.c b/test/test_libraries.c index c33e167..3957449 100644 --- a/test/test_libraries.c +++ b/test/test_libraries.c @@ -18,8 +18,8 @@ #include "../repl/lib_standard.h" #include "../repl/lib_random.h" #include "../repl/lib_runner.h" +#include "../repl/lib_fileio.h" #include "../repl/lib_math.h" -#include "../repl/lib_io.h" //supress the print output static void noPrintFn(const char* output) { @@ -78,8 +78,8 @@ int main() { {"standard.toy", "standard", Toy_hookStandard}, {"runner.toy", "runner", Toy_hookRunner}, {"random.toy", "random", Toy_hookRandom}, + {"fileio.toy", "fileio", Toy_hookFileIO}, {"math.toy", "math", Toy_hookMath}, - {"io.toy", "io", Toy_hookIO}, {NULL, NULL, NULL} };