From 67f7b3e4360439dc45af9b8e27d92674b8621b4d Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 10 Aug 2022 17:42:04 +0100 Subject: [PATCH] Arrays and dictionaries have been implemented, read more The arrays and dictionaries are currently being printed out correctly, afaik. This means I should be able to go back and work on the type system, assuming nothing happens. --- scripts/example.toy | 15 +- scripts/long-array.toy | 337 ++++++++++++++++++++++++++++++++++++ scripts/long-dictionary.toy | 2 + scripts/small.toy | 2 + source/compiler.c | 103 +++++++++++ source/interpreter.c | 52 ++++++ source/lexer.c | 1 + source/literal.c | 107 +++++++++++- source/literal.h | 21 ++- source/node.c | 59 ++++++- source/node.h | 25 ++- source/parser.c | 111 +++++++++++- source/repl_main.c | 20 ++- 13 files changed, 819 insertions(+), 36 deletions(-) create mode 100644 scripts/long-array.toy create mode 100644 scripts/long-dictionary.toy create mode 100644 scripts/small.toy diff --git a/scripts/example.toy b/scripts/example.toy index 2556c03..e1277a3 100644 --- a/scripts/example.toy +++ b/scripts/example.toy @@ -23,14 +23,17 @@ print 2 + (3 * 3); } print "Back to the outer scope."; -//test asserts -assert true, "This won't be seen"; -assert false, "This is an error"; - - - +print [1, 2, 3]; +print [4, 5]; +print ["key":"value"]; //var arr : [int] = [1, 2, 3, 42]; //var dict : [string, int] = ["hello": 1, "world":2]; + + +//test asserts at the end of the file +assert true, "This won't be seen"; +assert false, "This is a failed assert, and will end execution"; + diff --git a/scripts/long-array.toy b/scripts/long-array.toy new file mode 100644 index 0000000..8053dfb --- /dev/null +++ b/scripts/long-array.toy @@ -0,0 +1,337 @@ +print [ + +"0", +"1", +"2", +"3", +"4", +"5", +"6", +"7", +"8", +"9", + +"10", +"11", +"12", +"13", +"14", +"15", +"16", +"17", +"18", +"19", + +"20", +"21", +"22", +"23", +"24", +"25", +"26", +"27", +"28", +"29", + +"30", +"31", +"32", +"33", +"34", +"35", +"36", +"37", +"38", +"39", + +"40", +"41", +"42", +"43", +"44", +"45", +"46", +"47", +"48", +"49", + +"50", +"51", +"52", +"53", +"54", +"55", +"56", +"57", +"58", +"59", + +"60", +"61", +"62", +"63", +"64", +"65", +"66", +"67", +"68", +"69", + +"70", +"71", +"72", +"73", +"74", +"75", +"76", +"77", +"78", +"79", + +"80", +"81", +"82", +"83", +"84", +"85", +"86", +"87", +"88", +"89", + +"90", +"91", +"92", +"93", +"94", +"95", +"96", +"97", +"98", +"99", + +//------------------------- + +"100", +"101", +"102", +"103", +"104", +"105", +"106", +"107", +"108", +"109", + +"110", +"111", +"112", +"113", +"114", +"115", +"116", +"117", +"118", +"119", + +"120", +"121", +"122", +"123", +"124", +"125", +"126", +"127", +"128", +"129", + +"130", +"131", +"132", +"133", +"134", +"135", +"136", +"137", +"138", +"139", + +"140", +"141", +"142", +"143", +"144", +"145", +"146", +"147", +"148", +"149", + +"150", +"151", +"152", +"153", +"154", +"155", +"156", +"157", +"158", +"159", + +"160", +"161", +"162", +"163", +"164", +"165", +"166", +"167", +"168", +"169", + +"170", +"171", +"172", +"173", +"174", +"175", +"176", +"177", +"178", +"179", + +"180", +"181", +"182", +"183", +"184", +"185", +"186", +"187", +"188", +"189", + +"190", +"191", +"192", +"193", +"194", +"195", +"196", +"197", +"198", +"199", + +//------------------------- + +"200", +"201", +"202", +"203", +"204", +"205", +"206", +"207", +"208", +"209", + +"210", +"211", +"212", +"213", +"214", +"215", +"216", +"217", +"218", +"219", + +"220", +"221", +"222", +"223", +"224", +"225", +"226", +"227", +"228", +"229", + +"230", +"231", +"232", +"233", +"234", +"235", +"236", +"237", +"238", +"239", + +"240", +"241", +"242", +"243", +"244", +"245", +"246", +"247", +"248", +"249", + +"250", +"251", +"252", +"253", +"254", +"255", +"256", +"257", +"258", +"259", + +"260", +"261", +"262", +"263", +"264", +"265", +"266", +"267", +"268", +"269", + +"270", +"271", +"272", +"273", +"274", +"275", +"276", +"277", +"278", +"279", + +"280", +"281", +"282", +"283", +"284", +"285", +"286", +"287", +"288", +"289", + +"290", +"291", +"292", +"293", +"294", +"295", +"296", +"297", +"298", +"299" + +]; diff --git a/scripts/long-dictionary.toy b/scripts/long-dictionary.toy new file mode 100644 index 0000000..10887f6 --- /dev/null +++ b/scripts/long-dictionary.toy @@ -0,0 +1,2 @@ +//NOTE: dictionaries are NOT stored in order +print ["0":"0","1":"1","2":"2","3":"3","4":"4","5":"5","6":"6","7":"7","8":"8","9":"9","10":"10","11":"11","12":"12","13":"13","14":"14","15":"15","16":"16","17":"17","18":"18","19":"19","20":"20","21":"21","22":"22","23":"23","24":"24","25":"25","26":"26","27":"27","28":"28","29":"29","30":"30","31":"31","32":"32","33":"33","34":"34","35":"35","36":"36","37":"37","38":"38","39":"39","40":"40","41":"41","42":"42","43":"43","44":"44","45":"45","46":"46","47":"47","48":"48","49":"49","50":"50","51":"51","52":"52","53":"53","54":"54","55":"55","56":"56","57":"57","58":"58","59":"59","60":"60","61":"61","62":"62","63":"63","64":"64","65":"65","66":"66","67":"67","68":"68","69":"69","70":"70","71":"71","72":"72","73":"73","74":"74","75":"75","76":"76","77":"77","78":"78","79":"79","80":"80","81":"81","82":"82","83":"83","84":"84","85":"85","86":"86","87":"87","88":"88","89":"89","90":"90","91":"91","92":"92","93":"93","94":"94","95":"95","96":"96","97":"97","98":"98","99":"99","100":"100","101":"101","102":"102","103":"103","104":"104","105":"105","106":"106","107":"107","108":"108","109":"109","110":"110","111":"111","112":"112","113":"113","114":"114","115":"115","116":"116","117":"117","118":"118","119":"119","120":"120","121":"121","122":"122","123":"123","124":"124","125":"125","126":"126","127":"127","128":"128","129":"129","130":"130","131":"131","132":"132","133":"133","134":"134","135":"135","136":"136","137":"137","138":"138","139":"139","140":"140","141":"141","142":"142","143":"143","144":"144","145":"145","146":"146","147":"147","148":"148","149":"149","150":"150","151":"151","152":"152","153":"153","154":"154","155":"155","156":"156","157":"157","158":"158","159":"159","160":"160","161":"161","162":"162","163":"163","164":"164","165":"165","166":"166","167":"167","168":"168","169":"169","170":"170","171":"171","172":"172","173":"173","174":"174","175":"175","176":"176","177":"177","178":"178","179":"179","180":"180","181":"181","182":"182","183":"183","184":"184","185":"185","186":"186","187":"187","188":"188","189":"189","190":"190","191":"191","192":"192","193":"193","194":"194","195":"195","196":"196","197":"197","198":"198","199":"199","200":"200","201":"201","202":"202","203":"203","204":"204","205":"205","206":"206","207":"207","208":"208","209":"209","210":"210","211":"211","212":"212","213":"213","214":"214","215":"215","216":"216","217":"217","218":"218","219":"219","220":"220","221":"221","222":"222","223":"223","224":"224","225":"225","226":"226","227":"227","228":"228","229":"229","230":"230","231":"231","232":"232","233":"233","234":"234","235":"235","236":"236","237":"237","238":"238","239":"239","240":"240","241":"241","242":"242","243":"243","244":"244","245":"245","246":"246","247":"247","248":"248","249":"249","250":"250","251":"251","252":"252","253":"253","254":"254","255":"255","256":"256","257":"257","258":"258","259":"259","260":"260","261":"261","262":"262","263":"263","264":"264","265":"265","266":"266","267":"267","268":"268","269":"269","270":"270","271":"271","272":"272","273":"273","274":"274","275":"275","276":"276","277":"277","278":"278","279":"279","280":"280","281":"281","282":"282","283":"283","284":"284","285":"285","286":"286","287":"287","288":"288","289":"289","290":"290","291":"291","292":"292","293":"293","294":"294","295":"295","296":"296","297":"297","298":"298","299":"299"]; \ No newline at end of file diff --git a/scripts/small.toy b/scripts/small.toy new file mode 100644 index 0000000..f4d58b7 --- /dev/null +++ b/scripts/small.toy @@ -0,0 +1,2 @@ +print ["foo", "bar"]; +print ["foo":1, "bar":2]; \ No newline at end of file diff --git a/source/compiler.c b/source/compiler.c index f4b5b10..efa3bf1 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -2,6 +2,10 @@ #include "memory.h" +#include "literal.h" +#include "literal_array.h" +#include "literal_dictionary.h" + #include void initCompiler(Compiler* compiler) { @@ -90,6 +94,72 @@ void writeCompiler(Compiler* compiler, Node* node) { compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte break; + case NODE_COMPOUND: { + int index = -1; + + //for both, stored as an array + LiteralArray* store = ALLOCATE(LiteralArray, 1); + initLiteralArray(store); + + //emit an array or a dictionary definition + if (node->compound.nodes->type == NODE_PAIR) { + //ensure each literal key and value are in the cache, individually + for (int i = 0; i < node->compound.count; i++) { + //keys + int key = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal); + if (key < 0) { + key = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].pair.left->atomic.literal); + } + + //values + int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal); + if (val < 0) { + val = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].pair.right->atomic.literal); + } + + pushLiteralArray(store, TO_INTEGER_LITERAL(key)); + pushLiteralArray(store, TO_INTEGER_LITERAL(val)); + } + + //push the store to the cache, with instructions about how pack it + index = pushLiteralArray(&compiler->literalCache, TO_DICTIONARY_LITERAL(store)); + } + else { + //ensure each literal value is in the cache, individually + for (int i = 0; i < node->compound.count; i++) { + //values + int val = findLiteralIndex(&compiler->literalCache, node->compound.nodes[i].atomic.literal); + if (val < 0) { + val = pushLiteralArray(&compiler->literalCache, node->compound.nodes[i].atomic.literal); + } + + pushLiteralArray(store, TO_INTEGER_LITERAL(val)); + } + + //push the store to the cache, with instructions about how pack it + index = pushLiteralArray(&compiler->literalCache, TO_ARRAY_LITERAL(store)); + } + + //push the node opcode to the bytecode + if (index >= 256) { + //push a "long" index + compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes + + compiler->count += sizeof(unsigned short); + } + else { + //push the index + compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte + compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte + } + } + break; + + case NODE_PAIR: + fprintf(stderr, "[Internal] NODE_PAIR encountered in writeCompiler()"); + break; + case NODE_VAR_TYPES: //TODO: OP_TYPE_DECL break; @@ -221,6 +291,39 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) { } break; + case LITERAL_ARRAY: { + emitByte(&collation, &capacity, &count, LITERAL_ARRAY); + + LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]); + + //length of the array, as a short + emitShort(&collation, &capacity, &count, ptr->count); + + //each element of the array + for (int i = 0; i < ptr->count; i++) { + emitShort(&collation, &capacity, &count, (unsigned short)AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values + } + + freeLiteralArray(ptr); + } + break; + + case LITERAL_DICTIONARY: + emitByte(&collation, &capacity, &count, LITERAL_DICTIONARY); + + LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above + + //length of the array, as a short + emitShort(&collation, &capacity, &count, ptr->count); //count is the array size, NOT the dictionary size + + //each element of the array + for (int i = 0; i < ptr->count; i++) { + emitShort(&collation, &capacity, &count, (unsigned short)AS_INTEGER(ptr->literals[i])); //shorts representing the indexes of the values + } + + freeLiteralArray(ptr); + break; + default: fprintf(stderr, "[Internal] Unknown literal type encountered within literal cache\n"); return NULL; diff --git a/source/interpreter.c b/source/interpreter.c index 1bd3042..7191d58 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -306,6 +306,11 @@ static void execInterpreter(Interpreter* interpreter) { } void runInterpreter(Interpreter* interpreter) { + if (!interpreter->bytecode) { + printf(ERROR "Error: No valid bytecode given\n" RESET); + return; + } + //header section const unsigned char major = readByte(interpreter->bytecode, &interpreter->count); const unsigned char minor = readByte(interpreter->bytecode, &interpreter->count); @@ -385,6 +390,53 @@ void runInterpreter(Interpreter* interpreter) { } } break; + + case LITERAL_ARRAY: { + LiteralArray* array = ALLOCATE(LiteralArray, 1); + initLiteralArray(array); + + unsigned short length = readShort(interpreter->bytecode, &interpreter->count); + + //read each index, then unpack the value from the existing literal cache + for (int i = 0; i < length; i++) { + int index = readShort(interpreter->bytecode, &interpreter->count); + pushLiteralArray(array, interpreter->literalCache.literals[index]); + } + + if (command.verbose) { + printf("(array "); + printLiteral(TO_ARRAY_LITERAL(array)); + printf(")\n"); + } + + //finally, push the array proper + pushLiteralArray(&interpreter->literalCache, TO_ARRAY_LITERAL(array)); + } + break; + + case LITERAL_DICTIONARY: { + LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1); + initLiteralDictionary(dictionary); + + unsigned short length = readShort(interpreter->bytecode, &interpreter->count); + + //read each index, then unpack the value from the existing literal cache + for (int i = 0; i < length / 2; i++) { + int key = readShort(interpreter->bytecode, &interpreter->count); + int val = readShort(interpreter->bytecode, &interpreter->count); + setLiteralDictionary(dictionary, interpreter->literalCache.literals[key], interpreter->literalCache.literals[val]); + } + + if (command.verbose) { + printf("(dictionary "); + printLiteral(TO_DICTIONARY_LITERAL(dictionary)); + printf(")\n"); + } + + //finally, push the dictionary proper + pushLiteralArray(&interpreter->literalCache, TO_DICTIONARY_LITERAL(dictionary)); + } + break; } } diff --git a/source/lexer.c b/source/lexer.c index 1c96181..162dce5 100644 --- a/source/lexer.c +++ b/source/lexer.c @@ -69,6 +69,7 @@ static void eatWhitespace(Lexer* lexer) { advance(lexer); break; } + break; default: return; diff --git a/source/literal.c b/source/literal.c index 2d77d3b..0922a52 100644 --- a/source/literal.c +++ b/source/literal.c @@ -1,13 +1,35 @@ #include "literal.h" #include "memory.h" +#include "literal_array.h" +#include "literal_dictionary.h" + #include #include +//utils static void stdoutWrapper(const char* output) { fprintf(stdout, output); } +//buffer the prints +static char* globalPrintBuffer = NULL; +static size_t globalPrintCapacity = 0; +static size_t globalPrintCount = 0; + +static void printToBuffer(const char* str) { + while (strlen(str) + globalPrintCount > globalPrintCapacity) { + int oldCapacity = globalPrintCapacity; + + globalPrintCapacity = GROW_CAPACITY(globalPrintCapacity); + globalPrintBuffer = GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity); + } + + snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str); + globalPrintCount += strlen(str); +} + +//exposed functions void printLiteral(Literal literal) { printLiteralCustom(literal, stdoutWrapper); } @@ -37,12 +59,93 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { break; case LITERAL_STRING: { - char buffer[256]; - snprintf(buffer, 256, "%.*s", STRLEN(literal), AS_STRING(literal)); + char buffer[4096]; + snprintf(buffer, 4096, "\"%.*s\"", STRLEN(literal), AS_STRING(literal)); printFn(buffer); } break; + case LITERAL_ARRAY: { + LiteralArray* ptr = AS_ARRAY(literal); + + //hold potential parent-call buffers + char* cacheBuffer = globalPrintBuffer; + globalPrintBuffer = NULL; + int cacheCapacity = globalPrintCapacity; + globalPrintCapacity = 0; + int cacheCount = globalPrintCount; + globalPrintCount = 0; + + //print the contents to the global buffer + printToBuffer("["); + for (int i = 0; i < ptr->count; i++) { + printLiteralCustom(ptr->literals[i], printToBuffer); + + if (i + 1 < ptr->count) { + printToBuffer(","); + } + } + printToBuffer("]"); + + //swap the parent-call buffer back into place + char* printBuffer = globalPrintBuffer; + int printCapacity = globalPrintCapacity; + int printCount = globalPrintCount; + + globalPrintBuffer = cacheBuffer; + globalPrintCapacity = cacheCapacity; + globalPrintCount = cacheCount; + + //finally, output and cleanup + printFn(printBuffer); + FREE_ARRAY(char, printBuffer, printCapacity); + } + break; + + case LITERAL_DICTIONARY: { + LiteralDictionary* ptr = AS_DICTIONARY(literal); + + //hold potential parent-call buffers + char* cacheBuffer = globalPrintBuffer; + globalPrintBuffer = NULL; + int cacheCapacity = globalPrintCapacity; + globalPrintCapacity = 0; + int cacheCount = globalPrintCount; + globalPrintCount = 0; + + //print the contents to the global buffer + int delimCount = 0; + printToBuffer("["); + for (int i = 0; i < ptr->capacity; i++) { + if (ptr->entries[i].key.type == LITERAL_NULL) { + continue; + } + + if (delimCount++ > 0) { + printToBuffer(","); + } + + printLiteralCustom(ptr->entries[i].key, printToBuffer); + printToBuffer(":"); + printLiteralCustom(ptr->entries[i].value, printToBuffer); + } + printToBuffer("]"); + + //swap the parent-call buffer back into place + char* printBuffer = globalPrintBuffer; + int printCapacity = globalPrintCapacity; + int printCount = globalPrintCount; + + globalPrintBuffer = cacheBuffer; + globalPrintCapacity = cacheCapacity; + globalPrintCount = cacheCount; + + //finally, output and cleanup + printFn(printBuffer); + FREE_ARRAY(char, printBuffer, printCapacity); + } + break; + case LITERAL_IDENTIFIER: { char buffer[256]; snprintf(buffer, 256, "%.*s", STRLEN_I(literal), AS_IDENTIFIER(literal)); diff --git a/source/literal.h b/source/literal.h index fa55909..7ea320e 100644 --- a/source/literal.h +++ b/source/literal.h @@ -10,10 +10,11 @@ typedef enum { LITERAL_INTEGER, LITERAL_FLOAT, LITERAL_STRING, - // LITERAL_ARRAY, - // LITERAL_DICTIONARY, + LITERAL_ARRAY, + LITERAL_DICTIONARY, // LITERAL_FUNCTION, LITERAL_IDENTIFIER, + // LITERAL_TYPE, } LiteralType; typedef struct { @@ -27,15 +28,17 @@ typedef struct { int length; } string; - // //experimental - // void* array; - // void* dictionary; + void* array; + void* dictionary; + // void* function; struct { //for variable names char* ptr; int length; } identifier; + + //TODO: type } as; } Literal; @@ -53,8 +56,8 @@ typedef struct { #define AS_INTEGER(value) ((value).as.integer) #define AS_FLOAT(value) ((value).as.number) #define AS_STRING(value) ((value).as.string.ptr) -// #define AS_ARRAY(value) -// #define AS_DICTIONARY(value) +#define AS_ARRAY(value) ((value).as.array) +#define AS_DICTIONARY(value) ((value).as.dictionary) // #define AS_FUNCTION(value) #define AS_IDENTIFIER(value) ((value).as.identifier.ptr) @@ -63,8 +66,8 @@ typedef struct { #define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }}) #define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }}) #define TO_STRING_LITERAL(value) _toStringLiteral(value) -// #define TO_ARRAY_LITERAL -// #define TO_DICTIONARY_LITERAL +#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }}) +#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }}) // #define TO_FUNCTION_LITERAL #define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value) diff --git a/source/node.c b/source/node.c index 5a52c46..7cb4f28 100644 --- a/source/node.c +++ b/source/node.c @@ -37,14 +37,26 @@ void freeNode(Node* node) { for (int i = 0; i < node->block.count; i++) { freeNode(node->block.nodes + i); } - //each sub-node gets freed individually + FREE_ARRAY(Node, node->block.nodes, node->block.capacity); + break; + + case NODE_COMPOUND: + for (int i = 0; i < node->compound.count; i++) { + freeNode(node->compound.nodes + i); + } + FREE_ARRAY(Node, node->compound.nodes, node->compound.capacity); + break; + + case NODE_PAIR: + freeNode(node->pair.left); + freeNode(node->pair.right); break; case NODE_VAR_TYPES: for (int i = 0; i < node->varTypes.count; i++) { freeNode(node->varTypes.nodes + 1); } - //each sub-node gets freed individually + FREE_ARRAY(Node, node->varTypes.nodes, node->varTypes.capacity); break; case NODE_VAR_DECL: @@ -53,8 +65,6 @@ void freeNode(Node* node) { freeNode(node->varDecl.expression); break; } - - FREE(Node, node); } void emitNodeLiteral(Node** nodeHandle, Literal literal) { @@ -105,6 +115,27 @@ void emitNodeBlock(Node** nodeHandle) { *nodeHandle = tmp; } +void emitNodeCompound(Node** nodeHandle) { + Node* tmp = ALLOCATE(Node, 1); + + tmp->type = NODE_COMPOUND; + tmp->compound.nodes = NULL; + tmp->compound.capacity = 0; + tmp->compound.count = 0; + + *nodeHandle = tmp; +} + +void emitNodePair(Node** nodeHandle, Node* left, Node* right) { + Node* tmp = ALLOCATE(Node, 1); + + tmp->type = NODE_PAIR; + tmp->pair.left = left; + tmp->pair.right = right; + + *nodeHandle = tmp; +} + void emitNodeVarTypes(Node** nodeHandle, unsigned char mask) { Node* tmp = ALLOCATE(Node, 1); @@ -172,8 +203,26 @@ void printNode(Node* node) { printf("}\n"); break; + case NODE_COMPOUND: + printf("compound[\n"); + + for (int i = 0; i < node->compound.count; i++) { + printNode(&(node->compound.nodes[i])); + } + + printf("]\n"); + break; + + case NODE_PAIR: + printf("pair-left:"); + printNode(node->pair.left); + printf(";pair-right:"); + printNode(node->pair.right); + printf(";"); + break; + case NODE_VAR_TYPES: - printf("[\n"); + printf("type[\n"); for (int i = 0; i < node->varTypes.count; i++) { printNode(&(node->varTypes.nodes[i])); diff --git a/source/node.h b/source/node.h index dd8fa65..4145db9 100644 --- a/source/node.h +++ b/source/node.h @@ -9,10 +9,12 @@ typedef union _node Node; typedef enum NodeType { NODE_ERROR, NODE_LITERAL, //a simple value - NODE_UNARY, //one child - NODE_BINARY, //two children, left and right + NODE_UNARY, //one child + opcode + NODE_BINARY, //two children, left and right + opcode NODE_GROUPING, //one child - NODE_BLOCK, //contains sub-node array + NODE_BLOCK, //contains a sub-node array + NODE_COMPOUND, //contains a sub-node array + NODE_PAIR, //contains a left and right NODE_VAR_TYPES, //contains a type mask and a sub-node array for compound types NODE_VAR_DECL, //contains identifier literal, typenode, expression definition // NODE_CONDITIONAL, //three children: conditional, then path, else path @@ -48,6 +50,19 @@ typedef struct NodeBlock { int count; } NodeBlock; +typedef struct NodeCompound { + NodeType type; + Node* nodes; + int capacity; + int count; +} NodeCompound; + +typedef struct NodePair { + NodeType type; + Node* left; + Node* right; +} NodePair; + typedef struct NodeVarTypes { NodeType type; unsigned char mask; @@ -70,6 +85,8 @@ union _node { NodeBinary binary; NodeGrouping grouping; NodeBlock block; + NodeCompound compound; + NodePair pair; NodeVarTypes varTypes; NodeVarDecl varDecl; }; @@ -80,6 +97,8 @@ void emitNodeUnary(Node** nodeHandle, Opcode opcode); void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode); void emitNodeGrouping(Node** nodeHandle); void emitNodeBlock(Node** nodeHandle); +void emitNodeCompound(Node** nodeHandle); +void emitNodePair(Node** nodeHandle, Node* left, Node* right); void emitNodeVarTypes(Node** nodeHandle, unsigned char mask); void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Node* varType, Node* expression); diff --git a/source/parser.c b/source/parser.c index 63debbe..733e19d 100644 --- a/source/parser.c +++ b/source/parser.c @@ -36,6 +36,7 @@ static void advance(Parser* parser) { if (parser->current.type == TOKEN_ERROR) { error(parser, parser->current, "Lexer error"); + printf(parser->lexer->source); } } @@ -115,6 +116,106 @@ static void declaration(Parser* parser, Node** nodeHandle); static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule); //the expression rules +static Opcode compound(Parser* parser, Node** nodeHandle, bool canBeAssigned) { + //read either an array or a dictionary into a literal node + + int iterations = 0; //count the number of entries iterated over + + //compound nodes to store what is read + Node* array = NULL; + Node* dictionary = NULL; + + while (!match(parser, TOKEN_BRACKET_RIGHT)) { + //if empty dictionary, there will be a colon between the brackets + if (iterations == 0 && match(parser, TOKEN_COLON)) { + consume(parser, TOKEN_BRACE_RIGHT, "Expected ']' at the end of empty dictionary definition"); + break; + } + + if (iterations > 0) { + consume(parser, TOKEN_COMMA, "Expected ',' in array or dictionary"); + } + + iterations++; + + Node* left = NULL; + Node* right = NULL; + + //store the left + parsePrecedence(parser, &left, PREC_PRIMARY); + + //detect a dictionary + if (match(parser, TOKEN_COLON)) { + parsePrecedence(parser, &right, PREC_PRIMARY); + + //check we ARE defining a dictionary + if (array) { + error(parser, parser->previous, "Incorrect detection between array and dictionary"); + freeNode(array); + return OP_EOF; + } + + //init the dictionary + if (!dictionary) { + emitNodeCompound(&dictionary); + } + + //grow the node if needed + if (dictionary->compound.capacity < dictionary->compound.count + 1) { + int oldCapacity = dictionary->compound.capacity; + + dictionary->compound.capacity = GROW_CAPACITY(oldCapacity); + dictionary->compound.nodes = GROW_ARRAY(Node, dictionary->compound.nodes, oldCapacity, dictionary->compound.capacity); + } + + //store the left and right in the node + Node* pair = NULL; + emitNodePair(&pair, left, right); + dictionary->compound.nodes[dictionary->compound.count++] = *pair; + } + //detect an array + else { + //check we ARE defining an array + if (dictionary) { + error(parser, parser->current, "Incorrect detection between array and dictionary"); + freeNode(dictionary); + return OP_EOF; + } + + //init the array + if (!array) { + emitNodeCompound(&array); + } + + //grow the node if needed + if (array->compound.capacity < array->compound.count + 1) { + int oldCapacity = array->compound.capacity; + + array->compound.capacity = GROW_CAPACITY(oldCapacity); + array->compound.nodes = GROW_ARRAY(Node, array->compound.nodes, oldCapacity, array->compound.capacity); + } + + //store the left in the array + array->compound.nodes[array->compound.count++] = *left; + } + } + + //save the result + if (array) { + (*nodeHandle) = array; + } + else if (dictionary) { + (*nodeHandle) = dictionary; + } + else { + error(parser, parser->current, "[internal] Couldn't determine if should save an array or dictionary"); + } + + + //ignored + return OP_EOF; +} + static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) { //handle strings switch(parser->previous.type) { @@ -330,7 +431,7 @@ ParseRule parseRules[] = { //must match the token types //logical operators {grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT, {NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT, - {NULL, NULL, PREC_NONE},// TOKEN_BRACKET_LEFT, + {compound, NULL, PREC_CALL},// TOKEN_BRACKET_LEFT, {NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT, {NULL, NULL, PREC_NONE},// TOKEN_BRACE_LEFT, {NULL, NULL, PREC_NONE},// TOKEN_BRACE_RIGHT, @@ -348,7 +449,7 @@ ParseRule parseRules[] = { //must match the token types {NULL, NULL, PREC_NONE},// TOKEN_ASSIGN, {NULL, NULL, PREC_NONE},// TOKEN_COLON, {NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON, - {NULL, NULL, PREC_NONE},// TOKEN_COMMA, + {NULL, NULL, PREC_CALL},// TOKEN_COMMA, {NULL, NULL, PREC_NONE},// TOKEN_DOT, {NULL, NULL, PREC_NONE},// TOKEN_PIPE, {NULL, NULL, PREC_NONE},// TOKEN_REST, @@ -570,9 +671,9 @@ static void assertStmt(Parser* parser, Node* node) { node->type = NODE_BINARY; node->unary.opcode = OP_ASSERT; - expression(parser, &(node->binary.left)); + parsePrecedence(parser, &(node->binary.left), PREC_PRIMARY); consume(parser, TOKEN_COMMA, "Expected ',' in assert statement"); - expression(parser, &(node->binary.right)); + parsePrecedence(parser, &(node->binary.right), PREC_PRIMARY); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of assert statement"); } @@ -607,7 +708,7 @@ static void statement(Parser* parser, Node* node) { //declarations and definitions static void readVarType(Parser* parser, Node** nodeHandle) { - //TODO: compound types with the "type" keyword + //TODO: custom types with the "type" keyword advance(parser); unsigned char typeMask = 0; diff --git a/source/repl_main.c b/source/repl_main.c index 29142c3..4c6e99a 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -25,7 +25,7 @@ char* readFile(char* path, size_t* fileSize) { *fileSize = ftell(file); rewind(file); - char* buffer = (char*)malloc(*fileSize); + char* buffer = (char*)malloc(*fileSize + 1); if (buffer == NULL) { fprintf(stderr, "Not enough memory to read \"%s\"\n", path); @@ -34,6 +34,8 @@ char* readFile(char* path, size_t* fileSize) { size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file); + buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this + if (bytesRead < *fileSize) { fprintf(stderr, "Could not read file \"%s\"\n", path); exit(-1); @@ -109,13 +111,19 @@ void runBinary(unsigned char* tb, size_t size) { void runBinaryFile(char* fname) { size_t size = 0; //not used unsigned char* tb = (unsigned char*)readFile(fname, &size); + if (!tb) { + return; + } runBinary(tb, size); //interpreter takes ownership of the binary data } void runSource(char* source) { - size_t size; + size_t size = 0; unsigned char* tb = compileString(source, &size); + if (!tb) { + return; + } runBinary(tb, size); } @@ -169,11 +177,11 @@ void repl() { int size = 0; unsigned char* tb = collateCompiler(&compiler, &size); - // for (int i = 0; i < size; i++) { - // printf("%d ", tb[i]); - // } + for (int i = 0; i < size; i++) { + printf("%d ", tb[i]); + } - // printf("\n"); + printf("\n"); //run the bytecode initInterpreter(&interpreter, tb, size);