From 38ba2273ddd08762ab62480a4a81a72d3a9a3f5c Mon Sep 17 00:00:00 2001 From: Add00 Date: Thu, 10 Aug 2023 23:00:26 -0400 Subject: [PATCH] added accessors, write and additional tests --- repl/lib_fileio.c | 448 ++++++++++++++++++++++++++++++++---- scripts/shapes.toy | 61 +++++ test/scripts/lib/fileio.toy | 63 +++-- 3 files changed, 510 insertions(+), 62 deletions(-) create mode 100644 scripts/shapes.toy diff --git a/repl/lib_fileio.c b/repl/lib_fileio.c index 35f7a0b..de412ef 100644 --- a/repl/lib_fileio.c +++ b/repl/lib_fileio.c @@ -4,12 +4,12 @@ #include #include +#include typedef struct Toy_File { FILE* fp; - int error; - int size; + Toy_RefString* mode; } Toy_File; static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { @@ -70,30 +70,21 @@ static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) // build file object Toy_File* file = TOY_ALLOCATE(Toy_File, 1); - file->error = 0; file->fp = NULL; - file->size = 0; + file->mode = Toy_createRefString(mode); // attempt to open file file->fp = fopen(filePath, mode); - if (file->fp == NULL) { - TOY_FREE(Toy_File, file); - fprintf(stderr, "File not found: %s\n", filePath); - file->error = 1; - } - - // set size - if (!file->error) { - fseek(file->fp, 0, SEEK_END); - - // pervent integer overflow as ftell returns a long - file->size = ftell(file->fp) > INT_MAX? INT_MAX : ftell(file->fp); - - fseek(file->fp, 0, SEEK_SET); - } // result - Toy_Literal fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE); + Toy_Literal fileLiteral = TOY_TO_NULL_LITERAL; + if (file->fp == NULL) { + TOY_FREE(Toy_File, file); + } + else { + fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE); + } + Toy_pushLiteralArray(&interpreter->stack, fileLiteral); // cleanup @@ -130,19 +121,17 @@ static int nativeClose(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); int result = 0; - if (file->error > 0) { - result = file->error; - } - else { + if (file->fp != NULL) { result = fclose(file->fp); } // return the result - Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result > 0); + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != EOF); Toy_pushLiteralArray(&interpreter->stack, resultLiteral); // cleanup TOY_FREE(Toy_File, file); + Toy_deleteRefString(file->mode); Toy_freeLiteral(selfLiteral); return 1; @@ -179,7 +168,7 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) } // check self type - if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == 900)) { + if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != 900) { interpreter->errorOutput("Incorrect argument type passed to read\n"); Toy_freeLiteral(selfLiteral); Toy_freeLiteral(valueLiteral); @@ -189,15 +178,27 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); - Toy_Literal resultLiteral = {0}; + Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL; - if (file->error == 0) { - switch (selfLiteral.type) + switch (valueLiteral.as.type.typeOf) { + case TOY_LITERAL_BOOLEAN: + { + char value[TOY_MAX_STRING_LENGTH] = {0}; + fgets(value, sizeof(value) - 1, file->fp); + value[TOY_MAX_STRING_LENGTH] = '\0'; + + Toy_Literal stringLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value)); + resultLiteral = TOY_TO_BOOLEAN_LITERAL(TOY_IS_TRUTHY(stringLiteral)); + Toy_freeLiteral(stringLiteral); + + break; + } + case TOY_LITERAL_INTEGER: { int value = 0; - file->error = fscanf(file->fp, "%i", &value); + fscanf(file->fp, "%i", &value); resultLiteral = TOY_TO_INTEGER_LITERAL(value); @@ -207,7 +208,7 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) case TOY_LITERAL_FLOAT: { float value = 0.0f; - file->error = fscanf(file->fp, "%f", &value); + fscanf(file->fp, "%f", &value); resultLiteral = TOY_TO_FLOAT_LITERAL(value); @@ -220,15 +221,15 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) fgets(value, sizeof(value) - 1, file->fp); value[TOY_MAX_STRING_LENGTH] = '\0'; - resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(value, TOY_MAX_STRING_LENGTH)); + resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value)); break; } default: + // TODO handle other types break; } - } Toy_pushLiteralArray(&interpreter->stack, resultLiteral); @@ -240,6 +241,282 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } +static int nativeWrite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to write\n"); + return -1; + } + + Toy_Literal valueLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the value (if it's an identifier) + Toy_Literal valueLiteralIdn = valueLiteral; + if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) { + Toy_freeLiteral(valueLiteralIdn); + } + + // check the value type + if (TOY_IS_NULL(valueLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to write\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(valueLiteral); + + return -1; + } + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!TOY_IS_OPAQUE(selfLiteral) && !(TOY_GET_OPAQUE_TAG(selfLiteral) == 900)) { + interpreter->errorOutput("Incorrect argument type passed to read\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(valueLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + int result = 0; + switch (valueLiteral.type) + { + case TOY_LITERAL_INTEGER: + { + result = fprintf(file->fp, "%i", TOY_AS_INTEGER(valueLiteral)); + break; + } + + case TOY_LITERAL_FLOAT: + { + result = fprintf(file->fp, "%f", TOY_AS_FLOAT(valueLiteral)); + break; + } + + case TOY_LITERAL_STRING: + { + result = fprintf(file->fp, "%s", Toy_toCString(TOY_AS_STRING(valueLiteral))); + break; + } + + default: + // TODO handle other types + break; + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result > 0); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(valueLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeError(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to error\n"); + return -1; + } + + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == TOY_OPAQUE_TAG_FILE)) { + interpreter->errorOutput("Incorrect argument type passed to error\n"); + Toy_freeLiteral(selfLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + int result = ferror(file->fp); + + // return the result + Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(result == 0); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeCompleted(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to error\n"); + return -1; + } + + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == TOY_OPAQUE_TAG_FILE)) { + interpreter->errorOutput("Incorrect argument type passed to error\n"); + Toy_freeLiteral(selfLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + int result = feof(file->fp); + + // return the result + Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(result == 0); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativePosition(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to size\n"); + return -1; + } + + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == TOY_OPAQUE_TAG_FILE)) { + interpreter->errorOutput("Incorrect argument type passed to size\n"); + Toy_freeLiteral(selfLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + int size = 0; + + // pervent integer overflow as ftell returns a long + if (ftell(file->fp) > INT_MAX) { + size = INT_MAX; + } + else { + size = ftell(file->fp); + } + + // return the result + Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeSize(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to size\n"); + return -1; + } + + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == TOY_OPAQUE_TAG_FILE)) { + interpreter->errorOutput("Incorrect argument type passed to size\n"); + Toy_freeLiteral(selfLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + int size = 0; + fseek(file->fp, 0, SEEK_END); + + // pervent integer overflow as ftell returns a long + if (ftell(file->fp) > INT_MAX) { + size = INT_MAX; + } + else { + size = ftell(file->fp); + } + + fseek(file->fp, 0, SEEK_SET); + + // return the result + Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(selfLiteral); + + return 1; +} + +static int nativeMode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + if (arguments->count != 1) { + interpreter->errorOutput("Incorrect number of arguments to mode\n"); + return -1; + } + + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + // parse the self (if it's an identifier) + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + // check self type + if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == TOY_OPAQUE_TAG_FILE)) { + interpreter->errorOutput("Incorrect argument type passed to mode\n"); + Toy_freeLiteral(selfLiteral); + + return -1; + } + + Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral); + + // return the result + Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(file->mode); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + + // cleanup + Toy_freeLiteral(resultLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + // call the hook typedef struct Natives { char* name; @@ -252,13 +529,20 @@ typedef struct Variable { Toy_Literal literal; } Variable; -// Helper function create a variable -void createToyVariable(Variable* variable, char* key, int literal) { +// Helper function create a int variable +void createToyVariableInt(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 create a file variable +void createToyVariableFile(Variable* variable, char* key, Toy_File* literal) { + variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key)); + variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key)); + variable->literal = TOY_TO_OPAQUE_LITERAL(literal, TOY_OPAQUE_TAG_FILE); +} + // Helper function to clean up variables void deleteToyVariables(Variable variables[], int size) { for (int i = 0; i < size; i++) { @@ -269,6 +553,7 @@ void deleteToyVariables(Variable variables[], int size) { } +// Helper to check for naming conflicts with existing variables bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) { for (int i = 0; i < size; i++) { if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) { @@ -283,29 +568,65 @@ bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) return false; } +// Helper to place variables into scope should be called after scopeConflict void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) { - Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, true); + Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, false); + Toy_Literal opaqueType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_OPAQUE, false); 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); + if (variables[i].literal.type == TOY_LITERAL_INTEGER) { + Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType); + } + else if (variables[i].literal.type == TOY_LITERAL_OPAQUE) { + Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, opaqueType); + } + + Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, true); } Toy_freeLiteral(intType); + Toy_freeLiteral(opaqueType); } int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { - //build the natives list + // build the natives list Natives natives[] = { - // Access + // access {"open", nativeOpen}, {"close", nativeClose}, - // + // input/output {"read", nativeRead}, + {"write", nativeWrite}, + + // accessors + {"error", nativeError}, + {"completed", nativeCompleted}, + {"position", nativePosition}, + {"size", nativeSize}, + {"mode", nativeMode}, + {NULL, NULL} }; + + // global variables + const int VARIABLES_SIZE = 5; + Variable variables[VARIABLES_SIZE]; + createToyVariableInt(&variables[0], "MAX_FILENAME_SIZE", FILENAME_MAX); + createToyVariableInt(&variables[1], "MAX_FILES_OPEN", FOPEN_MAX); + createToyVariableInt(&variables[2], "END_OF_FILE", EOF); + + Toy_File* outFile = TOY_ALLOCATE(Toy_File, 1); + outFile->fp = stdout; + + createToyVariableFile(&variables[3], "output", outFile); + + Toy_File* inFile = TOY_ALLOCATE(Toy_File, 1); + inFile->fp = stdin; + + createToyVariableFile(&variables[4], "input", inFile); + // store the library in an aliased dictionary if (!TOY_IS_NULL(alias)) { // make sure the name isn't taken @@ -315,7 +636,43 @@ int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit return -1; } - // TODO + // 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); + } + + // set global variables + for (int i = 0; i < VARIABLES_SIZE; i++) { + Toy_setLiteralDictionary(dictionary, variables[i].key, variables[i].literal); + } + + // build the type + Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true); + Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true); + Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true); + TOY_TYPE_PUSH_SUBTYPE(&type, anyType); + 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 @@ -323,13 +680,6 @@ int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn); } - const int VARIABLES_SIZE = 3; - Variable variables[VARIABLES_SIZE]; - - createToyVariable(&variables[0], "MAX_FILENAME_SIZE", FILENAME_MAX); - createToyVariable(&variables[1], "MAX_FILES_OPEN", FOPEN_MAX); - createToyVariable(&variables[2], "END_OF_FILE", EOF); - if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) { return -1; } diff --git a/scripts/shapes.toy b/scripts/shapes.toy new file mode 100644 index 0000000..9b92948 --- /dev/null +++ b/scripts/shapes.toy @@ -0,0 +1,61 @@ +import math; +import fileio; +import standard; + +fn circle(radius: int, centerX: int, centerY: int) { + for (var y: int = 0; y <= 2 * radius; y++) { + for (var x: int = 0; x <= 2 * radius; x++) { + var distance: int = round(sqrt((x - radius) * (x - radius) + (y - radius) * (y - radius))); + + if (distance <= radius) { + output.write("*"); + } else { + output.write(" "); + } + } + + output.write("\n"); + } +} + +fn triangle(height: int) { + for (var i: int = 1; i <= height; i++) { + for (var j: int = 1; j <= height - i; j++) { + output.write(" "); + } + + for (var j: int = 1; j <= 2 * i - 1; j++) { + output.write("*"); + } + + output.write("\n"); + } +} + +fn square(size: int) { + for (var i: int = 0; i < size; ++i) { + for (var j: int = 0; j < size; ++j) { + output.write("* "); + } + + output.write("\n"); + } +} + +for (;;) { + output.write("Enter:\n0\tfor circle\n1\tfor triangle\n2\tfor square\n> "); + var result: any = input.read(int); + + if (result == 0) { + circle(5, 5, 5); + } + else if (result == 1) { + triangle(5); + } + else if (result == 2) { + square(5); + } + else { + output.write("invalid input :(\n"); + } +} \ No newline at end of file diff --git a/test/scripts/lib/fileio.toy b/test/scripts/lib/fileio.toy index 7d9d171..04d8636 100644 --- a/test/scripts/lib/fileio.toy +++ b/test/scripts/lib/fileio.toy @@ -1,18 +1,55 @@ import fileio; -// test open +// test global constants +{ + assert MAX_FILENAME_SIZE > 0, "MAX_FILENAME_SIZE failed"; + assert MAX_FILES_OPEN > 0, "MAX_FILES_OPEN failed"; + assert END_OF_FILE == -1, "END_OF_FILE failed"; +} + +// test open and close +{ + var file = open("scripts:/lib/file/fileio.txt", "r"); + assert file != null, "open failed"; + + var wrong = open("scripts:/doesNotExist", "r"); + assert wrong == null, "open failed"; + + assert file.close() == true, "close failed"; +} + +// test accessors { var file = open("scripts:/lib/file/fileio.txt", "r"); - // file.read(string); - - // TODO: - // file.write(12, ",", 12); - // file.size(); - // file.isOpened(); - // file.getrror(); - // file.position(); - // file.mode(); - - print file.close(); -} \ No newline at end of file + print file.error(); + print file.completed(); + print file.position(); + print file.size(); + print file.mode(); + + file.close(); +} + +// test output +{ + // assert output.write(8), "write int failed"; + // assert output.write("\n"), "write string failed"; + // assert output.write(12.5), "write float failed"; +} + +// test input +{ + // // enter 8 + // assert input.read(int) == 8, "read int failed"; + + // // enter 12.5 + // assert input.read(float) == 12.5, "read float failed"; + + // // enter test + // assert input.read(string) == "test\n", "read string failed"; + + // // invaild types + // assert input.read(type) == null, "type failed"; + // assert input.read(any) == null, "any failed"; +}