mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Library rename, added HAL, added open function
This commit is contained in:
88
repl/hal_file.c
Normal file
88
repl/hal_file.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "hal_file.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
63
repl/hal_file.h
Normal file
63
repl/hal_file.h
Normal file
@@ -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;
|
||||
224
repl/lib_fileio.c
Normal file
224
repl/lib_fileio.c
Normal file
@@ -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;
|
||||
}
|
||||
5
repl/lib_fileio.h
Normal file
5
repl/lib_fileio.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "lib_io.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//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;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_interpreter.h"
|
||||
|
||||
int Toy_hookIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
20
test/scripts/lib/fileio.toy
Normal file
20
test/scripts/lib/fileio.toy
Normal file
@@ -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);
|
||||
}
|
||||
1
test/scripts/lib/fileio.txt
Normal file
1
test/scripts/lib/fileio.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello, World!
|
||||
@@ -1 +0,0 @@
|
||||
print "Nothing is here";
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user