From b8f20add6680ac420abe3e11a045e7e74ae94dbc Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 6 Sep 2022 06:46:00 +0100 Subject: [PATCH] Finished slice and dot notation, needs a lot of testing --- docs/TODO.txt | 2 + scripts/small.toy | 25 +- source/compiler.c | 114 ++++++-- source/interpreter.c | 46 +++- source/lib_builtin.c | 599 ++++++++++++++++++++++++++++++++++++++++- source/literal_array.c | 31 +++ source/literal_array.h | 3 +- source/parser.c | 21 +- 8 files changed, 791 insertions(+), 50 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 30e5346..90fecf0 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -35,6 +35,8 @@ DONE: A way to check the type of a variable (typeOf keyword) TODO: slice and dot notation around the builtin _index and _dot functions +//TODO: check this const-ness +//TODO: add arithmetics TODO: ternary operator diff --git a/scripts/small.toy b/scripts/small.toy index 2b56c10..7b7d436 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1,8 +1,23 @@ +var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]; + +week[::-2] = ["first", "second", "third"]; + +print week; + + +var str = "0123456789"; + +str[3:5:-2] = "abc"; + +print str; + + + +str = "Hello world"; + +print str; //Hello world +print str[::2]; //Hlowrd +print str[::-2]; //drwolH -{ - fn f() { - return i; - } -} diff --git a/source/compiler.c b/source/compiler.c index bd2eb98..6ba36af 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -289,10 +289,16 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break } break; - case NODE_UNARY: + case NODE_UNARY: { //pass to the child node, then embed the unary command (print, negate, etc.) - writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } + compiler->bytecode[compiler->count++] = (unsigned char)node->unary.opcode; //1 byte + } break; //all infixes come here @@ -322,20 +328,28 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break } break; - case NODE_GROUPING: + case NODE_GROUPING: { compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte - writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_END; //1 byte + } break; - case NODE_BLOCK: + case NODE_BLOCK: { compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte for (int i = 0; i < node->block.count; i++) { - writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte + } break; case NODE_COMPOUND: { @@ -364,7 +378,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_VAR_DECL: { //first, embed the expression (leaves it on the stack) - writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //write each piece of the declaration to the bytecode int identifierIndex = findLiteralIndex(&compiler->literalCache, node->varDecl.identifier); @@ -400,7 +417,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break initCompiler(fnCompiler); writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL - writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4); //can be empty, but not NULL + Opcode override = writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4); //can be empty, but not NULL + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //create the function in the literal cache (by storing the compiler object) Literal fnLiteral = TO_FUNCTION_LITERAL(fnCompiler, 0); @@ -450,7 +470,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter //sub-calls if (node->fnCall.arguments->fnCollection.nodes[i].type != NODE_LITERAL) { - writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } continue; } @@ -503,7 +526,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_PATH_IF: { //process the condition - writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //cache the point to insert the jump distance at compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte @@ -511,7 +537,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->count += sizeof(unsigned short); //2 bytes //write the then path - writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } int jumpToEnd = 0; @@ -527,7 +556,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break if (node->path.elsePath) { //if there's an else path, write it and - writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //update the jumpToEnd to point here AS_USHORT(compiler->bytecode[jumpToEnd]) = compiler->count + jumpOffsets; //2 bytes @@ -547,7 +579,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break unsigned short jumpToStart = compiler->count; //process the condition - writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //if false, jump to end compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte @@ -555,7 +590,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->count += sizeof(unsigned short); //2 bytes //write the body - writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //jump to condition compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte @@ -596,11 +634,17 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte //initial setup - writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //conditional unsigned short jumpToStart = compiler->count; - writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } //if false jump to end compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte @@ -609,14 +653,20 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break //write the body compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte - writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } compiler->bytecode[compiler->count++] = OP_SCOPE_END; //1 byte //for-breaks actually jump to the bottom int jumpToIncrement = compiler->count; //evaluate third clause, restart - writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte AS_USHORT(compiler->bytecode[compiler->count]) = jumpToStart + jumpOffsets; @@ -685,7 +735,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_PATH_RETURN: { //read each returned literal onto the stack, and return the number of values to return for (int i = 0; i < node->path.thenPath->fnCollection.count; i++) { - writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } //push the return, with the number of literals @@ -766,7 +819,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } //second @@ -774,7 +830,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - writeCompilerWithJumps(compiler, node->index.second, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.second, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } //third @@ -782,7 +841,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - writeCompilerWithJumps(compiler, node->index.third, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.third, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } // compiler->bytecode[compiler->count++] = (unsigned char)OP_INDEX; //1 byte @@ -797,7 +859,10 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + if (override != OP_EOF) {//compensate for indexing & dot notation being screwy + compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte + } } // compiler->bytecode[compiler->count++] = (unsigned char)OP_DOT; //1 byte @@ -813,8 +878,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break void writeCompiler(Compiler* compiler, Node* node) { Opcode op = writeCompilerWithJumps(compiler, node, NULL, NULL, 0); - //compensate for indexing & dot notation being screwy - if (op != OP_EOF) { + if (op != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)op; //1 byte } } diff --git a/source/interpreter.c b/source/interpreter.c index a91f607..d971bee 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -1428,6 +1428,10 @@ static bool execDot(Interpreter* interpreter) { Literal first = popLiteralArray(&interpreter->stack); Literal compound = popLiteralArray(&interpreter->stack); + Literal tmp = first; + first = TO_STRING_LITERAL(copyString(AS_IDENTIFIER(tmp), strlen(AS_IDENTIFIER(tmp))) , strlen(AS_IDENTIFIER(tmp)) ); + freeLiteral(tmp); + if (!IS_IDENTIFIER(compound)) { interpreter->errorOutput("Unknown literal found in dot notation\n"); freeLiteral(first); @@ -1441,7 +1445,7 @@ static bool execDot(Interpreter* interpreter) { return false; } - if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) { + if (!IS_DICTIONARY(compound)) { interpreter->errorOutput("Unknown compound found in dot notation\n"); freeLiteral(first); freeLiteral(compound); @@ -1527,6 +1531,18 @@ static bool execIndexAssign(Interpreter* interpreter) { return false; } + //check const-ness of "first" within "compound" + Literal type = getScopeType(interpreter->scope, idn); + if ((AS_TYPE(type).typeOf == LITERAL_ARRAY && AS_TYPE(((Literal*)(AS_TYPE(type).subtypes))[0]).constant) || (AS_TYPE(type).typeOf == LITERAL_DICTIONARY && AS_TYPE(((Literal*)(AS_TYPE(type).subtypes))[1]).constant)) { + interpreter->errorOutput("couldn't assign to constant within compound within index assigning notation\n"); + freeLiteral(assign); + freeLiteral(first); + freeLiteral(compound); + freeLiteral(idn); + freeLiteral(type); + return false; + } + //get the index function Literal func = TO_NULL_LITERAL; char* keyStr = "_index"; @@ -1542,6 +1558,7 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(idn); freeLiteral(func); freeLiteral(key); + freeLiteral(type); return false; } @@ -1578,6 +1595,7 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(idn); freeLiteral(func); freeLiteral(key); + freeLiteral(type); return false; } @@ -1616,6 +1634,7 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(func); freeLiteralArray(&arguments); freeLiteral(key); + freeLiteral(type); freeLiteral(result); return false; } @@ -1631,6 +1650,7 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(func); freeLiteralArray(&arguments); freeLiteral(key); + freeLiteral(type); freeLiteral(result); return true; @@ -1643,6 +1663,10 @@ static bool execDotAssign(Interpreter* interpreter) { Literal first = popLiteralArray(&interpreter->stack); Literal compound = popLiteralArray(&interpreter->stack); + Literal tmp = first; + first = TO_STRING_LITERAL(copyString(AS_IDENTIFIER(tmp), strlen(AS_IDENTIFIER(tmp))) , strlen(AS_IDENTIFIER(tmp)) ); + freeLiteral(tmp); + if (!IS_IDENTIFIER(compound)) { interpreter->errorOutput("Unknown literal found in dot assigning notation\n"); freeLiteral(assign); @@ -1661,7 +1685,7 @@ static bool execDotAssign(Interpreter* interpreter) { return false; } - if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) { + if (!IS_DICTIONARY(compound)) { interpreter->errorOutput("Unknown compound found in dot assigning notation\n"); freeLiteral(assign); freeLiteral(first); @@ -1670,6 +1694,18 @@ static bool execDotAssign(Interpreter* interpreter) { return false; } + //check const-ness of "first" within "compound" + Literal type = getScopeType(interpreter->scope, idn); + if (AS_TYPE(type).typeOf == LITERAL_DICTIONARY && AS_TYPE(((Literal*)(AS_TYPE(type).subtypes))[1]).constant) { + interpreter->errorOutput("couldn't assign to constant within compound within dot assigning notation\n"); + freeLiteral(assign); + freeLiteral(first); + freeLiteral(compound); + freeLiteral(idn); + freeLiteral(type); + return false; + } + //get the index function Literal func = TO_NULL_LITERAL; char* keyStr = "_dot"; @@ -1683,6 +1719,7 @@ static bool execDotAssign(Interpreter* interpreter) { freeLiteral(idn); freeLiteral(func); freeLiteral(key); + freeLiteral(type); return false; } @@ -1717,6 +1754,7 @@ static bool execDotAssign(Interpreter* interpreter) { freeLiteral(idn); freeLiteral(func); freeLiteral(key); + freeLiteral(type); return false; } @@ -1737,7 +1775,7 @@ static bool execDotAssign(Interpreter* interpreter) { //save the result (assume top of the interpreter stack is the new compound value) Literal result = popLiteralArray(&interpreter->stack); - if (!setScopeVariable(interpreter->scope, idn, result, true)) {//TODO: check this const-ness + if (!setScopeVariable(interpreter->scope, idn, result, true)) { interpreter->errorOutput("Incorrect type assigned to compound member: "); printLiteralCustom(result, interpreter->errorOutput); interpreter->errorOutput("\n"); @@ -1751,6 +1789,7 @@ static bool execDotAssign(Interpreter* interpreter) { freeLiteral(func); freeLiteralArray(&arguments); freeLiteral(key); + freeLiteral(type); freeLiteral(result); return false; } @@ -1764,6 +1803,7 @@ static bool execDotAssign(Interpreter* interpreter) { freeLiteral(func); freeLiteralArray(&arguments); freeLiteral(key); + freeLiteral(type); freeLiteral(result); return true; diff --git a/source/lib_builtin.c b/source/lib_builtin.c index a2f2bbb..eeb4ef9 100644 --- a/source/lib_builtin.c +++ b/source/lib_builtin.c @@ -1,6 +1,30 @@ #include "lib_builtin.h" #include "memory.h" +#include "literal.h" + +#include + +//static math utils +static Literal addition(Literal lhs, Literal rhs) { + //TODO +} + +static Literal subtraction(Literal lhs, Literal rhs) { + //TODO +} + +static Literal multiplication(Literal lhs, Literal rhs) { + //TODO +} + +static Literal division(Literal lhs, Literal rhs) { + //TODO +} + +static Literal modulo(Literal lhs, Literal rhs) { + //TODO +} int _index(Interpreter* interpreter, LiteralArray* arguments) { //_index(compound, first, second, third, assignValue, op) @@ -11,12 +35,528 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { Literal first = popLiteralArray(arguments); Literal compound = popLiteralArray(arguments); - printLiteralCustom(compound, interpreter->printOutput); - printLiteralCustom(first, interpreter->printOutput); - printLiteralCustom(second, interpreter->printOutput); - printLiteralCustom(third, interpreter->printOutput); - printLiteralCustom(op, interpreter->printOutput); - printLiteralCustom(assign, interpreter->printOutput); + Literal value = TO_NULL_LITERAL; + + //dictionary - no slicing + if (IS_DICTIONARY(compound)) { + value = getLiteralDictionary(AS_DICTIONARY(compound), first); + + //dictionary + //dictionary + if (IS_NULL(op)) { + pushLiteralArray(&interpreter->stack, value); + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return 1; + } + + else if (!strcmp( AS_STRING(op), "=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, assign); + } + + else if (!strcmp( AS_STRING(op), "+=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, addition(value, assign)); + } + + else if (!strcmp( AS_STRING(op), "-=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, subtraction(value, assign)); + } + + else if (!strcmp( AS_STRING(op), "*=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, multiplication(value, assign)); + } + + else if (!strcmp( AS_STRING(op), "/=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, division(value, assign)); + } + + else if (!strcmp( AS_STRING(op), "%=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, modulo(value, assign)); + } + } + + //array - slicing + if (IS_ARRAY(compound)) { + value = getLiteralArray(AS_ARRAY(compound), first); + + //array slice + if (IS_NULL(op)) { + //parse out the booleans & their defaults + if (!IS_NULL(first)) { + if (IS_BOOLEAN(first)) { + freeLiteral(first); + first = TO_INTEGER_LITERAL(0); + } + } + + if (!IS_NULL(second)) { + if (IS_BOOLEAN(second)) { + freeLiteral(second); + second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count); + } + } + + if (IS_NULL(third) || IS_BOOLEAN(third)) { + freeLiteral(third); + third = TO_INTEGER_LITERAL(1); + } + + //handle each null case + if (IS_NULL(first) || !IS_INTEGER(first)) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + if (IS_NULL(second)) { //assign only a single character + //get the "first" within the array, then skip out + + value = getLiteralArray(AS_ARRAY(compound), first); + pushLiteralArray(&interpreter->stack, value); + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return 1; + } + + if (!IS_INTEGER(second) || (!IS_NULL(third) && !IS_INTEGER(third)) || AS_INTEGER(second) < 0 || AS_INTEGER(second) > AS_ARRAY(compound)->count || AS_INTEGER(third) == 0) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + //start building a new array from the old one + LiteralArray* result = ALLOCATE(LiteralArray, 1); + initLiteralArray(result); + + int min = AS_INTEGER(third) > 0 ? 0 : AS_INTEGER(second) - 1; + + //copy compound into result + for (int i = min; i >= 0 && i <= AS_ARRAY(compound)->count && i >= AS_INTEGER(first) && i < AS_INTEGER(second); i += AS_INTEGER(third)) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal tmp = getLiteralArray(AS_ARRAY(compound), idx); + pushLiteralArray(result, tmp); + + freeLiteral(idx); + freeLiteral(tmp); + } + + //finally, swap out the compound for the result + freeLiteral(compound); + compound = TO_ARRAY_LITERAL(result); + } + + //array slice assignment + else if (!strcmp( AS_STRING(op), "=")) { + //parse out the booleans & their defaults + if (!IS_NULL(first)) { + if (IS_BOOLEAN(first)) { + freeLiteral(first); + first = TO_INTEGER_LITERAL(0); + } + } + + if (!IS_NULL(second)) { + if (IS_BOOLEAN(second)) { + freeLiteral(second); + second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count); + } + } + + if (IS_NULL(third) || IS_BOOLEAN(third)) { + freeLiteral(third); + third = TO_INTEGER_LITERAL(1); + } + + //handle each null case + if (IS_NULL(first) || !IS_INTEGER(first)) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + if (IS_NULL(second)) { + //set the "first" within the array, then skip out + setLiteralArray(AS_ARRAY(compound), first, assign); + + pushLiteralArray(&interpreter->stack, compound); + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return 1; + } + + if (!IS_INTEGER(second) || (!IS_NULL(third) && !IS_INTEGER(third)) || AS_INTEGER(second) < 0 || AS_INTEGER(second) > AS_ARRAY(compound)->count || AS_INTEGER(third) == 0) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + //start building a new array from the old one + LiteralArray* result = ALLOCATE(LiteralArray, 1); + initLiteralArray(result); + + //if third is abs(1), simply insert into the correct positions + if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) { + for (int i = 0; i < AS_INTEGER(first); i++) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal tmp = getLiteralArray(AS_ARRAY(compound), idx); + pushLiteralArray(result, tmp); + + freeLiteral(idx); + freeLiteral(tmp); + } + + int min = AS_INTEGER(third) > 0 ? 0 : AS_ARRAY(assign)->count - 1; + + for (int i = min; i >= 0 && i < AS_ARRAY(assign)->count; i += AS_INTEGER(third)) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal tmp = getLiteralArray(AS_ARRAY(assign), idx); //backwards + + //set result + pushLiteralArray(result, tmp); + + freeLiteral(idx); + freeLiteral(tmp); + } + + for (int i = AS_INTEGER(second) + 1; i < AS_ARRAY(compound)->count; i++) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal tmp = getLiteralArray(AS_ARRAY(compound), idx); + pushLiteralArray(result, tmp); + + freeLiteral(idx); + freeLiteral(tmp); + } + } + + //else override elements of the array instead + else { + //copy compound to result + for (int i = 0; i < AS_ARRAY(compound)->count; i++) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal tmp = getLiteralArray(AS_ARRAY(compound), idx); + + pushLiteralArray(result, tmp); + + freeLiteral(idx); + freeLiteral(tmp); + } + + int min = AS_INTEGER(third) > 0 ? 0 : AS_ARRAY(compound)->count - 1; + + int assignIndex = 0; + for (int i = min; i >= 0 && i < AS_ARRAY(compound)->count && assignIndex < AS_ARRAY(assign)->count; i += AS_INTEGER(third)) { + Literal idx = TO_INTEGER_LITERAL(i); + Literal ai = TO_INTEGER_LITERAL(assignIndex++); + Literal tmp = getLiteralArray(AS_ARRAY(assign), ai); + + setLiteralArray(result, idx, tmp); + + freeLiteral(idx); + freeLiteral(ai); + freeLiteral(tmp); + } + } + + //finally, swap out the compound for the result + freeLiteral(compound); + compound = TO_ARRAY_LITERAL(result); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) { + setLiteralArray(AS_ARRAY(compound), first, addition(value, assign)); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "-=")) { + setLiteralArray(AS_ARRAY(compound), first, subtraction(value, assign)); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "*=")) { + setLiteralArray(AS_ARRAY(compound), first, multiplication(value, assign)); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "/=")) { + setLiteralArray(AS_ARRAY(compound), first, division(value, assign)); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "%=")) { + setLiteralArray(AS_ARRAY(compound), first, modulo(value, assign)); + } + } + + //string - slicing + if (IS_STRING(compound)) { + //string slice + if (IS_NULL(op)) { + //parse out the booleans & their defaults + if (!IS_NULL(first)) { + if (IS_BOOLEAN(first)) { + freeLiteral(first); + first = TO_INTEGER_LITERAL(0); + } + } + + if (!IS_NULL(second)) { + if (IS_BOOLEAN(second)) { + freeLiteral(second); + second = TO_INTEGER_LITERAL(strlen(AS_STRING(compound))); + } + } + + if (IS_NULL(third) || IS_BOOLEAN(third)) { + freeLiteral(third); + third = TO_INTEGER_LITERAL(1); + } + + //handle each null case + if (IS_NULL(first) || !IS_INTEGER(first)) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + if (IS_NULL(second)) { //assign only a single character + char c = AS_STRING(compound)[AS_INTEGER(first)]; + + char buffer[16]; + snprintf(buffer, 16, "%c", c); + + freeLiteral(value); + value = TO_STRING_LITERAL(copyString(buffer, strlen(buffer)), strlen(buffer)); + + pushLiteralArray(&interpreter->stack, value); + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return 1; + } + + if (!IS_INTEGER(second) || (!IS_NULL(third) && !IS_INTEGER(third)) || AS_INTEGER(second) < 0 || AS_INTEGER(second) > strlen(AS_STRING(compound)) || AS_INTEGER(third) == 0) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + //start building a new string from the old one + char* result = ALLOCATE(char, MAX_STRING_LENGTH); + + int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1; + + //copy compound into result + int resultIndex = 0; + for (int i = min; i >= AS_INTEGER(first) && i < AS_INTEGER(second); i += AS_INTEGER(third)) { + result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + } + + result[ resultIndex++ ] = '\0'; + + //finally, swap out the compound for the result + freeLiteral(compound); + compound = TO_STRING_LITERAL(copyString(result, strlen(result)), strlen(result)); + + FREE_ARRAY(char, result, MAX_STRING_LENGTH); + } + + //string slice assignment + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "=")) { + //parse out the booleans & their defaults + if (!IS_NULL(first)) { + if (IS_BOOLEAN(first)) { + freeLiteral(first); + first = TO_INTEGER_LITERAL(0); + } + } + + if (!IS_NULL(second)) { + if (IS_BOOLEAN(second)) { + freeLiteral(second); + second = TO_INTEGER_LITERAL(strlen(AS_STRING(compound))); + } + } + + if (IS_NULL(third) || IS_BOOLEAN(third)) { + freeLiteral(third); + third = TO_INTEGER_LITERAL(1); + } + + //handle each null case + if (IS_NULL(first) || !IS_INTEGER(first)) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + if (IS_NULL(second)) { //assign only a single character + //set the "first" within the array, then skip out + if (strlen( AS_STRING(assign) ) != 1) { + //something is weird - skip out + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + AS_STRING(compound)[AS_INTEGER(first)] = AS_STRING(assign)[0]; + + pushLiteralArray(&interpreter->stack, compound); + + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return 1; + } + + if (!IS_INTEGER(second) || (!IS_NULL(third) && !IS_INTEGER(third)) || AS_INTEGER(second) < 0 || AS_INTEGER(second) > strlen(AS_STRING(compound)) || AS_INTEGER(third) == 0) { + //something is weird - skip out + freeLiteral(compound); + freeLiteral(first); + freeLiteral(second); + freeLiteral(third); + freeLiteral(op); + freeLiteral(assign); + freeLiteral(value); + + return -1; + } + + //start building a new string from the old one + char* result = ALLOCATE(char, MAX_STRING_LENGTH); + + //if third is abs(1), simply insert into the correct positions + int resultIndex = 0; + if (AS_INTEGER(third) == 1 || AS_INTEGER(third) == -1) { + for (int i = 0; i < AS_INTEGER(first); i++) { + result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + } + + int min = AS_INTEGER(third) > 0 ? 0 : strlen(AS_STRING(assign)) - 1; + + //TODO: optimize strlen(assign) + for (int i = min; i >= 0 && i < strlen(AS_STRING(assign)); i += AS_INTEGER(third)) { + result[ resultIndex++ ] = AS_STRING(assign)[ i ]; + } + + for (int i = AS_INTEGER(second) + 1; i < strlen(AS_STRING(compound)); i++) { + result[ resultIndex++ ] = AS_STRING(compound)[ i ]; + } + } + + //else override elements of the array instead + else { + //copy compound to result + snprintf(result, MAX_STRING_LENGTH, AS_STRING(compound)); + + int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second); + + int assignIndex = 0; + for (int i = min; i >= AS_INTEGER(first) && i <= AS_INTEGER(second) && assignIndex < strlen(AS_STRING(assign)); i += AS_INTEGER(third)) { + result[ i ] = AS_STRING(assign)[ assignIndex++ ]; + resultIndex++; + } + } + + //finally, swap out the compound for the result + freeLiteral(compound); + compound = TO_STRING_LITERAL(copyString(result, strlen(result)), strlen(result)); + + FREE_ARRAY(char, result, MAX_STRING_LENGTH); + } + + else if (IS_STRING(op) && !strcmp( AS_STRING(op), "+=")) { + Literal tmp = addition(compound, value); + freeLiteral(compound); + compound = tmp; //don't clear tmp + } + } + + //leave the compound on the stack + pushLiteralArray(&interpreter->stack, compound); freeLiteral(compound); freeLiteral(first); @@ -24,8 +564,9 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { freeLiteral(third); freeLiteral(op); freeLiteral(assign); + freeLiteral(value); - return 0; + return 1; } int _dot(Interpreter* interpreter, LiteralArray* arguments) { @@ -35,17 +576,51 @@ int _dot(Interpreter* interpreter, LiteralArray* arguments) { Literal first = popLiteralArray(arguments); Literal compound = popLiteralArray(arguments); - printLiteralCustom(compound, interpreter->printOutput); - printLiteralCustom(first, interpreter->printOutput); - printLiteralCustom(op, interpreter->printOutput); - printLiteralCustom(assign, interpreter->printOutput); + Literal value = getLiteralDictionary(AS_DICTIONARY(compound), first); + //dictionary + if (IS_NULL(op)) { + pushLiteralArray(&interpreter->stack, value); + } + + else if (!strcmp( AS_STRING(op), "=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, assign); + pushLiteralArray(&interpreter->stack, compound); + } + + else if (!strcmp( AS_STRING(op), "+=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, addition(value, assign)); + pushLiteralArray(&interpreter->stack, compound); + } + + else if (!strcmp( AS_STRING(op), "-=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, subtraction(value, assign)); + pushLiteralArray(&interpreter->stack, compound); + } + + else if (!strcmp( AS_STRING(op), "*=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, multiplication(value, assign)); + pushLiteralArray(&interpreter->stack, compound); + } + + else if (!strcmp( AS_STRING(op), "/=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, division(value, assign)); + pushLiteralArray(&interpreter->stack, compound); + } + + else if (!strcmp( AS_STRING(op), "%=")) { + setLiteralDictionary(AS_DICTIONARY(compound), first, modulo(value, assign)); + pushLiteralArray(&interpreter->stack, compound); + } + + //cleanup freeLiteral(compound); freeLiteral(first); freeLiteral(op); freeLiteral(assign); + freeLiteral(value); - return 0; + return 1; } int _set(Interpreter* interpreter, LiteralArray* arguments) { diff --git a/source/literal_array.c b/source/literal_array.c index f7bbc9f..8df5b7c 100644 --- a/source/literal_array.c +++ b/source/literal_array.c @@ -65,3 +65,34 @@ int findLiteralIndex(LiteralArray* array, Literal literal) { return -1; } + +bool setLiteralArray(LiteralArray* array, Literal index, Literal value) { + if (!IS_INTEGER(index)) { + return false; + } + + int idx = AS_INTEGER(index); + + if (idx < 0 || idx >= array->count) { + return false; + } + + freeLiteral(array->literals[idx]); + array->literals[idx] = copyLiteral(value); + + return true; +} + +Literal getLiteralArray(LiteralArray* array, Literal index) { + if (!IS_INTEGER(index)) { + return TO_NULL_LITERAL; + } + + int idx = AS_INTEGER(index); + + if (idx < 0 || idx >= array->count) { + return TO_NULL_LITERAL; + } + + return copyLiteral(array->literals[idx]); +} \ No newline at end of file diff --git a/source/literal_array.h b/source/literal_array.h index 16f43b9..1037b3f 100644 --- a/source/literal_array.h +++ b/source/literal_array.h @@ -12,6 +12,7 @@ void initLiteralArray(LiteralArray* array); void freeLiteralArray(LiteralArray* array); int pushLiteralArray(LiteralArray* array, Literal literal); Literal popLiteralArray(LiteralArray* array); -//TODO: set & get +bool setLiteralArray(LiteralArray* array, Literal index, Literal value); +Literal getLiteralArray(LiteralArray* array, Literal index); int findLiteralIndex(LiteralArray* array, Literal literal); diff --git a/source/parser.c b/source/parser.c index f1afc34..9ad30ca 100644 --- a/source/parser.c +++ b/source/parser.c @@ -726,31 +726,44 @@ static Opcode indexAccess(Parser* parser, Node** nodeHandle) { Node* second = NULL; Node* third = NULL; + //booleans indicate blank slice indexing + emitNodeLiteral(&first, TO_BOOLEAN_LITERAL(true)); + emitNodeLiteral(&second, TO_BOOLEAN_LITERAL(true)); + emitNodeLiteral(&third, TO_BOOLEAN_LITERAL(true)); + //eat the first if (!match(parser, TOKEN_COLON)) { + freeNode(first); parsePrecedence(parser, &first, PREC_TERNARY); + match(parser, TOKEN_COLON); } if (match(parser, TOKEN_BRACKET_RIGHT)) { + // freeNode(second); + // freeNode(third); + // second = NULL; + // third = NULL; + emitNodeIndex(nodeHandle, first, second, third); return OP_INDEX; } - consume(parser, TOKEN_COLON, "Expected ':' in index notation"); - //eat the second if (!match(parser, TOKEN_COLON)) { + freeNode(second); parsePrecedence(parser, &second, PREC_TERNARY); + match(parser, TOKEN_COLON); } if (match(parser, TOKEN_BRACKET_RIGHT)) { + // freeNode(third); + // third = NULL; emitNodeIndex(nodeHandle, first, second, third); return OP_INDEX; } - consume(parser, TOKEN_COLON, "Expected ':' in index notation"); - //eat the third + freeNode(third); parsePrecedence(parser, &third, PREC_TERNARY); emitNodeIndex(nodeHandle, first, second, third);