From ca24c4f21146574c9a020daf5c0138fb51a28cff Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 3 Oct 2022 21:02:13 +0100 Subject: [PATCH] Added the opaque data type --- scripts/test/opaque-data-type.toy | 6 ++ source/literal.c | 16 +++ source/literal.h | 6 ++ source/literal_dictionary.c | 23 ++++- test/test_opaque_data_type.c | 165 ++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 scripts/test/opaque-data-type.toy create mode 100644 test/test_opaque_data_type.c diff --git a/scripts/test/opaque-data-type.toy b/scripts/test/opaque-data-type.toy new file mode 100644 index 0000000..b35aa6f --- /dev/null +++ b/scripts/test/opaque-data-type.toy @@ -0,0 +1,6 @@ +//test the opaque data type works + +var o = produce(); + +consume(o); + diff --git a/source/literal.c b/source/literal.c index f62ebe3..675d2c6 100644 --- a/source/literal.c +++ b/source/literal.c @@ -165,6 +165,10 @@ Literal copyLiteral(Literal original) { return lit; } + case LITERAL_OPAQUE: { + return original; //literally a shallow copy + } + case LITERAL_DICTIONARY_INTERMEDIATE: { LiteralArray* array = ALLOCATE(LiteralArray, 1); initLiteralArray(array); @@ -327,6 +331,9 @@ bool literalsAreEqual(Literal lhs, Literal rhs) { } return true; + case LITERAL_OPAQUE: + return false; //IDK what this is! + case LITERAL_ANY: return true; @@ -389,6 +396,7 @@ int hashLiteral(Literal lit) { case LITERAL_TYPE: return AS_TYPE(lit).typeOf; //nothing else I can do + case LITERAL_OPAQUE: case LITERAL_ANY: return -1; @@ -639,6 +647,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { printToBuffer("type"); break; + case LITERAL_OPAQUE: + printToBuffer("opaque"); + break; + case LITERAL_ANY: printToBuffer("any"); break; @@ -676,6 +688,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { printFn("Unprintable literal found"); break; + case LITERAL_OPAQUE: + printFn("(opaque)"); + break; + case LITERAL_ANY: printFn("(any)"); break; diff --git a/source/literal.h b/source/literal.h index e49cdb9..433eb00 100644 --- a/source/literal.h +++ b/source/literal.h @@ -15,6 +15,7 @@ typedef enum { LITERAL_FUNCTION, LITERAL_IDENTIFIER, LITERAL_TYPE, + LITERAL_OPAQUE, LITERAL_ANY, //these are meta-level types - not for general use @@ -58,6 +59,8 @@ typedef struct { int capacity; int count; } type; + + void* opaque; } as; } Literal; @@ -72,6 +75,7 @@ typedef struct { #define IS_FUNCTION_NATIVE(value) ((value).type == LITERAL_FUNCTION_NATIVE) #define IS_IDENTIFIER(value) ((value).type == LITERAL_IDENTIFIER) #define IS_TYPE(value) ((value).type == LITERAL_TYPE) +#define IS_OPAQUE(value) ((value).type == LITERAL_OPAQUE) #define AS_BOOLEAN(value) ((value).as.boolean) #define AS_INTEGER(value) ((value).as.integer) @@ -82,6 +86,7 @@ typedef struct { #define AS_FUNCTION(value) ((value).as.function) #define AS_IDENTIFIER(value) ((value).as.identifier.ptr) #define AS_TYPE(value) ((value).as.type) +#define AS_OPAQUE(value) ((value).as.opaque) #define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }}) #define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }}) @@ -93,6 +98,7 @@ typedef struct { #define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }}) #define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l) #define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }}) +#define TO_OPAQUE_LITERAL(value) ((Literal){ LITERAL_OPAQUE, { .opaque = value }}) TOY_API void freeLiteral(Literal literal); diff --git a/source/literal_dictionary.c b/source/literal_dictionary.c index ed708f4..8eda7d5 100644 --- a/source/literal_dictionary.c +++ b/source/literal_dictionary.c @@ -136,13 +136,18 @@ void freeLiteralDictionary(LiteralDictionary* dictionary) { void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value) { if (IS_NULL(key)) { - fprintf(stderr, ERROR "Dictionaries can't have null keys (get)\n" RESET); + fprintf(stderr, ERROR "Dictionaries can't have null keys (set)\n" RESET); return; } //BUGFIX: Can't hash a function if (IS_FUNCTION(key) || IS_FUNCTION_NATIVE(key)) { - fprintf(stderr, ERROR "Dictionaries can't have function keys (get)\n" RESET); + fprintf(stderr, ERROR "Dictionaries can't have function keys (set)\n" RESET); + return; + } + + if (IS_OPAQUE(key)) { + fprintf(stderr, ERROR "Dictionaries can't have opaque keys (set)\n" RESET); return; } @@ -156,13 +161,18 @@ void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal va Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key) { if (IS_NULL(key)) { - fprintf(stderr, ERROR "Dictionaries can't have null keys (set)\n" RESET); + fprintf(stderr, ERROR "Dictionaries can't have null keys (get)\n" RESET); return TO_NULL_LITERAL; } //BUGFIX: Can't hash a function if (IS_FUNCTION(key) || IS_FUNCTION_NATIVE(key)) { - fprintf(stderr, ERROR "Dictionaries can't have function keys (set)\n" RESET); + fprintf(stderr, ERROR "Dictionaries can't have function keys (get)\n" RESET); + return TO_NULL_LITERAL; + } + + if (IS_OPAQUE(key)) { + fprintf(stderr, ERROR "Dictionaries can't have opaque keys (get)\n" RESET); return TO_NULL_LITERAL; } @@ -188,6 +198,11 @@ void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key) { return; } + if (IS_OPAQUE(key)) { + fprintf(stderr, ERROR "Dictionaries can't have opaque keys (remove)\n" RESET); + return; + } + _entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), true); if (entry != NULL) { diff --git a/test/test_opaque_data_type.c b/test/test_opaque_data_type.c new file mode 100644 index 0000000..add93a6 --- /dev/null +++ b/test/test_opaque_data_type.c @@ -0,0 +1,165 @@ +#include "lexer.h" +#include "parser.h" +#include "compiler.h" +#include "interpreter.h" + +#include "console_colors.h" + +#include "memory.h" + +#include +#include + +//supress the print output +static void noPrintFn(const char* output) { + //NO OP +} + +//compilation functions +char* readFile(char* path, size_t* fileSize) { + FILE* file = fopen(path, "rb"); + + if (file == NULL) { + fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path); + exit(-1); + } + + fseek(file, 0L, SEEK_END); + *fileSize = ftell(file); + rewind(file); + + char* buffer = (char*)malloc(*fileSize + 1); + + if (buffer == NULL) { + fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path); + exit(-1); + } + + size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file); + + buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this + + if (bytesRead < *fileSize) { + fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path); + exit(-1); + } + + fclose(file); + + return buffer; +} + +unsigned char* compileString(char* source, size_t* size) { + Lexer lexer; + Parser parser; + Compiler compiler; + + initLexer(&lexer, source); + initParser(&parser, &lexer); + initCompiler(&compiler); + + //run the parser until the end of the source + ASTNode* node = scanParser(&parser); + while(node != NULL) { + //pack up and leave + if (node->type == AST_NODEERROR) { + printf(ERROR "error node detected\n" RESET); + freeNode(node); + freeCompiler(&compiler); + freeParser(&parser); + return NULL; + } + + writeCompiler(&compiler, node); + freeNode(node); + node = scanParser(&parser); + } + + //get the bytecode dump + unsigned char* tb = collateCompiler(&compiler, (int*)(size)); + + //cleanup + freeCompiler(&compiler); + freeParser(&parser); + //no lexer to clean up + + //finally + return tb; +} + +void error(char* msg) { + printf(msg); + exit(-1); +} + +//utilities +typedef struct ArbitraryData { + int value; +} ArbitraryData; + +static int produce(Interpreter* interpreter, LiteralArray* arguments) { + ArbitraryData* data = ALLOCATE(ArbitraryData, 1); + data->value = 42; + + Literal o = TO_OPAQUE_LITERAL(data); + + pushLiteralArray(&interpreter->stack, o); + + freeLiteral(o); + + return 1; +} + +static int consume(Interpreter* interpreter, LiteralArray* arguments) { + Literal o = popLiteralArray(arguments); + + Literal idn = o; + + if (parseIdentifierToValue(interpreter, &o)) { + freeLiteral(o); + } + + if (IS_OPAQUE(o) && ((ArbitraryData*)(AS_OPAQUE(o)))->value == 42) { + ArbitraryData* data = (ArbitraryData*)AS_OPAQUE(o); + + FREE(ArbitraryData, data); + + //all went well + freeLiteral(o); + return 0; + } + + printf(ERROR "opaque failed: %d\n" RESET, IS_OPAQUE(o)); + + exit(-1); + return -1; +} + +int main() { + { + size_t size = 0; + char* source = readFile("../scripts/test/opaque-data-type.toy", &size); + unsigned char* tb = compileString(source, &size); + free((void*)source); + + if (!tb) { + return -1; + } + + Interpreter interpreter; + initInterpreter(&interpreter); + + injectNativeFn(&interpreter, "produce", produce); + injectNativeFn(&interpreter, "consume", consume); + + //run teh script + runInterpreter(&interpreter, tb, size); + + //clean up + freeInterpreter(&interpreter); + } + + printf(NOTICE "All good\n" RESET); + return 0; +} +