diff --git a/docs/TODO.txt b/docs/TODO.txt index 0c8837b..c78facf 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -35,9 +35,9 @@ DONE: A way to check the type of a variable (typeOf keyword) DONE: slice and dot notation around the builtin _index and _dot functions DONE: maximum recursion/function depth DONE: better sugar for _push, _pop, _length +DONE: nested compound assignment bug -TODO: nested compound assignment TODO: ternary operator? TODO: Nullish types? TODO: hooks on the external libraries, triggered on import diff --git a/scripts/small.toy b/scripts/small.toy index f7cc170..7b119de 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1,10 +1,11 @@ +//test nested indexing +{ + var a = [[[0]]]; -fn loop(count) { - print count++; - - loop(count); + a[0][0][0] = 42; +print a; + assert a[0][0] == [42], "nested indexing failed"; } -loop(0); \ No newline at end of file diff --git a/scripts/test/index-arrays.toy b/scripts/test/index-arrays.toy index 5a7e659..8484fd9 100644 --- a/scripts/test/index-arrays.toy +++ b/scripts/test/index-arrays.toy @@ -61,4 +61,15 @@ assert week[first:second:third] == ["wednesday", "tuesday"], "indexing with variables failed"; } + +//test nested indexing +{ + var a = [[[0]]]; + + a[0][0][0] = 42; + + assert a[0][0] == [42], "nested indexing failed"; +} + + print "All good"; diff --git a/scripts/test/index-dictionaries.toy b/scripts/test/index-dictionaries.toy index d1bbbc1..c619326 100644 --- a/scripts/test/index-dictionaries.toy +++ b/scripts/test/index-dictionaries.toy @@ -27,4 +27,17 @@ assert d[first] == 2, "indexing with variables failed"; } + +//test nested indexing +{ + var d = ["foo": ["bar": 0]]; + + d["foo"]["bar"] = 42; + + print d; + + assert d == ["foo": ["bar": 42]], "nested indexing failed"; +} + + print "All good"; diff --git a/source/compiler.c b/source/compiler.c index 2e8c203..a2fe7ab 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -267,7 +267,9 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) { return index; } -static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets) { //NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump +//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump +//NODE: rootNode should NOT include groupings and blocks +static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, Node* rootNode) { //grow if the bytecode space is too small if (compiler->count + 32 > compiler->capacity) { int oldCapacity = compiler->capacity; @@ -291,7 +293,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_UNARY: { //pass to the child node, then embed the unary command (print, negate, etc.) - Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte @@ -304,12 +306,12 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break //all infixes come here case NODE_BINARY: { //pass to the child nodes, then embed the binary command (math, etc.) - Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); //special case for when indexing and assigning if (override != OP_EOF && node->binary.opcode >= OP_VAR_ASSIGN && node->binary.opcode <= OP_VAR_MODULO_ASSIGN) { - writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets); - compiler->bytecode[compiler->count++] = (unsigned char)override + 1; //1 byte WARNING: enum arithmetic + writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + compiler->bytecode[compiler->count++] = (unsigned char)OP_INDEX_ASSIGN; //1 byte WARNING: enum trickery compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte return OP_EOF; } @@ -320,7 +322,11 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break } //return this if... - Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); + + if (node->binary.opcode == OP_INDEX && rootNode->type == NODE_BINARY && rootNode->binary.opcode == OP_VAR_ASSIGN) { //why var assign? + return OP_INDEX_ASSIGN_INTERMEDIATE; + } //loopy logic - if opcode == index or dot if (node->binary.opcode == OP_INDEX || node->binary.opcode == OP_DOT) { @@ -340,7 +346,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_GROUPING: { compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte - Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets, node->grouping.child); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -352,7 +358,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte for (int i = 0; i < node->block.count; i++) { - Opcode override = writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr, jumpOffsets, &(node->block.nodes[i])); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -388,7 +394,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_VAR_DECL: { //first, embed the expression (leaves it on the stack) - Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -427,7 +433,7 @@ 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 - Opcode override = writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4); //can be empty, but not NULL + Opcode override = writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4, rootNode); //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 } @@ -480,7 +486,7 @@ 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) { - Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -536,7 +542,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break case NODE_PATH_IF: { //process the condition - Opcode override = writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -547,7 +553,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->count += sizeof(unsigned short); //2 bytes //write the then path - override = writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -566,7 +572,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break if (node->path.elsePath) { //if there's an else path, write it and - Opcode override = writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -589,7 +595,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break unsigned short jumpToStart = compiler->count; //process the condition - Opcode override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -600,7 +606,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->count += sizeof(unsigned short); //2 bytes //write the body - override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -644,14 +650,14 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte //initial setup - Opcode override = writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); 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; - override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -663,7 +669,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break //write the body compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte - override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -673,7 +679,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break int jumpToIncrement = compiler->count; //evaluate third clause, restart - override = writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets); + override = writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -745,7 +751,7 @@ 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++) { - Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -829,7 +835,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - Opcode override = writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -840,7 +846,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - Opcode override = writeCompilerWithJumps(compiler, node->index.second, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.second, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -851,7 +857,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break writeLiteralToCompiler(compiler, TO_NULL_LITERAL); } else { - Opcode override = writeCompilerWithJumps(compiler, node->index.third, breakAddressesPtr, continueAddressesPtr, jumpOffsets); + Opcode override = writeCompilerWithJumps(compiler, node->index.third, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode); if (override != OP_EOF) {//compensate for indexing & dot notation being screwy compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte } @@ -874,7 +880,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break } void writeCompiler(Compiler* compiler, Node* node) { - Opcode op = writeCompilerWithJumps(compiler, node, NULL, NULL, 0); + Opcode op = writeCompilerWithJumps(compiler, node, NULL, NULL, 0, node); //pass in "node" as the root node 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 d5df70e..8cbeb8d 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -1397,7 +1397,7 @@ static bool execExport(Interpreter* interpreter) { return true; } -static bool execIndex(Interpreter* interpreter) { +static bool execIndex(Interpreter* interpreter, bool assignIntermediate) { //assume -> compound, first, second, third are all on the stack Literal third = popLiteralArray(&interpreter->stack); @@ -1405,26 +1405,19 @@ static bool execIndex(Interpreter* interpreter) { Literal first = popLiteralArray(&interpreter->stack); Literal compound = popLiteralArray(&interpreter->stack); - if (!IS_IDENTIFIER(compound)) { - interpreter->errorOutput("Unknown literal found in indexing notation\n"); - printLiteralCustom(compound, interpreter->errorOutput); - interpreter->errorOutput("\n"); - freeLiteral(third); - freeLiteral(second); - freeLiteral(first); - freeLiteral(compound); - return false; - } - Literal idn = compound; + bool freeIdn = false; - if (!parseIdentifierToValue(interpreter, &compound)) { - freeLiteral(third); - freeLiteral(second); - freeLiteral(first); - freeLiteral(compound); - //freeLiteral(idn); //since compound is freed, idn is still pointing there - return false; + if (IS_IDENTIFIER(compound)) { + freeIdn = true; + if (!parseIdentifierToValue(interpreter, &compound)) { + freeLiteral(third); + freeLiteral(second); + freeLiteral(first); + freeLiteral(compound); + //freeLiteral(idn); //since compound is freed, idn is still pointing there + return false; + } } if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) { @@ -1433,7 +1426,9 @@ static bool execIndex(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } return false; } @@ -1449,7 +1444,9 @@ static bool execIndex(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } freeLiteral(func); freeLiteral(key); return false; @@ -1466,6 +1463,17 @@ static bool execIndex(Interpreter* interpreter) { pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment command pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment "opcode" + //leave the idn and compound on the stack + if (assignIntermediate) { + if (IS_IDENTIFIER(idn)) { + pushLiteralArray(&interpreter->stack, idn); + } + pushLiteralArray(&interpreter->stack, compound); + pushLiteralArray(&interpreter->stack, first); + pushLiteralArray(&interpreter->stack, second); + pushLiteralArray(&interpreter->stack, third); + } + //call the function NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode; fn(interpreter, &arguments); @@ -1475,7 +1483,9 @@ static bool execIndex(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } freeLiteral(func); freeLiteral(key); freeLiteralArray(&arguments); @@ -1492,28 +1502,20 @@ static bool execIndexAssign(Interpreter* interpreter) { Literal first = popLiteralArray(&interpreter->stack); Literal compound = popLiteralArray(&interpreter->stack); - if (!IS_IDENTIFIER(compound)) { - interpreter->errorOutput("Unknown literal found in index assigning notation\n"); - printLiteralCustom(compound, interpreter->errorOutput); - interpreter->errorOutput("\n"); - freeLiteral(assign); - freeLiteral(third); - freeLiteral(second); - freeLiteral(first); - freeLiteral(compound); - return false; - } - Literal idn = compound; + bool freeIdn = false; - if (!parseIdentifierToValue(interpreter, &compound)) { - freeLiteral(assign); - freeLiteral(third); - freeLiteral(second); - freeLiteral(first); - freeLiteral(compound); - freeLiteral(idn); - return false; + if (IS_IDENTIFIER(compound)) { + freeIdn = true; + if (!parseIdentifierToValue(interpreter, &compound)) { + freeLiteral(assign); + freeLiteral(third); + freeLiteral(second); + freeLiteral(first); + freeLiteral(compound); + freeLiteral(idn); + return false; + } } if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) { @@ -1523,23 +1525,28 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } 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(third); - freeLiteral(second); - freeLiteral(first); - freeLiteral(compound); - freeLiteral(idn); - freeLiteral(type); - return false; - } + //TODO: come back to this + // //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(third); + // freeLiteral(second); + // freeLiteral(first); + // freeLiteral(compound); + // if (freeIdn) { + // freeLiteral(idn); + // } + // freeLiteral(type); + // return false; + // } //get the index function Literal func = TO_NULL_LITERAL; @@ -1554,8 +1561,10 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); - freeLiteral(type); + if (freeIdn) { + freeLiteral(idn); + } + // freeLiteral(type); freeLiteral(func); freeLiteral(key); return false; @@ -1591,8 +1600,10 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); - freeLiteral(type); + if (freeIdn) { + freeLiteral(idn); + } + // freeLiteral(type); freeLiteral(func); freeLiteral(key); return false; @@ -1618,7 +1629,49 @@ static bool execIndexAssign(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 idn is NOT an identifier, assign backwards while there are things on the stack (inner-compound assignment, BIG assumptions here) + if (!IS_IDENTIFIER(idn)) { + while (interpreter->stack.count > 1) { + //read the new values + freeLiteral(idn); + freeLiteral(third); + freeLiteral(second); + freeLiteral(first); + freeLiteralArray(&arguments); + initLiteralArray(&arguments); + freeLiteral(op); + + third = popLiteralArray(&interpreter->stack); + second = popLiteralArray(&interpreter->stack); + first = popLiteralArray(&interpreter->stack); + idn = popLiteralArray(&interpreter->stack); + + char* opStr = "="; //shadow, but force assignment + int opLength = strlen(opStr); + op = TO_STRING_LITERAL(copyString(opStr, opLength), opLength); + + //assign to the idn / compound - with _index + pushLiteralArray(&arguments, idn); + pushLiteralArray(&arguments, first); + pushLiteralArray(&arguments, second); + pushLiteralArray(&arguments, third); + pushLiteralArray(&arguments, result); + pushLiteralArray(&arguments, op); + + fn(interpreter, &arguments); + + freeLiteral(result); + result = popLiteralArray(&interpreter->stack); + } + + freeLiteral(idn); + idn = popLiteralArray(&interpreter->stack); + compound = idn; + // freeIdn = true; + } + + if (IS_IDENTIFIER(idn) && !setScopeVariable(interpreter->scope, idn, result, true)) { interpreter->errorOutput("Incorrect type assigned to compound member: "); printLiteralCustom(result, interpreter->errorOutput); interpreter->errorOutput("\n"); @@ -1629,9 +1682,11 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } freeLiteral(func); - freeLiteral(type); + // freeLiteral(type); freeLiteral(key); freeLiteral(op); freeLiteralArray(&arguments); @@ -1645,9 +1700,11 @@ static bool execIndexAssign(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + if (freeIdn) { + freeLiteral(idn); + } freeLiteral(func); - freeLiteral(type); + // freeLiteral(type); freeLiteral(key); freeLiteral(op); freeLiteralArray(&arguments); @@ -1871,7 +1928,13 @@ static void execInterpreter(Interpreter* interpreter) { break; case OP_INDEX: - if (!execIndex(interpreter)) { + if (!execIndex(interpreter, false)) { + return; + } + break; + + case OP_INDEX_ASSIGN_INTERMEDIATE: + if (!execIndex(interpreter, true)) { return; } break; diff --git a/source/opcodes.h b/source/opcodes.h index 66187b4..3bfacd9 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -51,6 +51,7 @@ typedef enum Opcode { //for indexing OP_INDEX, OP_INDEX_ASSIGN, + OP_INDEX_ASSIGN_INTERMEDIATE, OP_DOT, //comparison of values