mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Fixed an obscure compiler bug involving assignments and indexing, read more
TOY_OP_INDEX_ASSIGN_INTERMEDIATE was being used when it shouldn't have. Now the check runs down the whole binary->right branch to ensure the given node doesn't exist in that tree.
This commit is contained in:
@@ -259,6 +259,81 @@ static int writeLiteralToCompiler(Toy_Compiler* compiler, Toy_Literal literal) {
|
||||
return index;
|
||||
}
|
||||
|
||||
//BUGFIX: check to see if this node lies within this tree
|
||||
bool checkNodeInTree(Toy_ASTNode* tree, Toy_ASTNode* node) {
|
||||
if (tree == node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tree == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tree->type) {
|
||||
case TOY_AST_NODE_UNARY:
|
||||
return checkNodeInTree(tree->unary.child, node);
|
||||
|
||||
case TOY_AST_NODE_BINARY:
|
||||
return checkNodeInTree(tree->binary.left, node) || checkNodeInTree(tree->binary.right, node);
|
||||
|
||||
case TOY_AST_NODE_TERNARY:
|
||||
return checkNodeInTree(tree->ternary.condition, node) || checkNodeInTree(tree->ternary.thenPath, node) || checkNodeInTree(tree->ternary.elsePath, node);
|
||||
|
||||
case TOY_AST_NODE_GROUPING:
|
||||
return checkNodeInTree(tree->grouping.child, node);
|
||||
|
||||
case TOY_AST_NODE_BLOCK:
|
||||
return checkNodeInTree(tree->block.nodes, node);
|
||||
|
||||
case TOY_AST_NODE_COMPOUND:
|
||||
return checkNodeInTree(tree->compound.nodes, node);
|
||||
|
||||
case TOY_AST_NODE_PAIR:
|
||||
return checkNodeInTree(tree->pair.left, node) || checkNodeInTree(tree->pair.right, node);
|
||||
|
||||
case TOY_AST_NODE_INDEX:
|
||||
return checkNodeInTree(tree->index.first, node) || checkNodeInTree(tree->index.second, node) || checkNodeInTree(tree->index.third, node);
|
||||
|
||||
case TOY_AST_NODE_VAR_DECL:
|
||||
return checkNodeInTree(tree->varDecl.expression, node);
|
||||
|
||||
case TOY_AST_NODE_FN_COLLECTION:
|
||||
return checkNodeInTree(tree->fnCollection.nodes, node);
|
||||
|
||||
case TOY_AST_NODE_FN_DECL:
|
||||
return checkNodeInTree(tree->fnDecl.arguments, node) || checkNodeInTree(tree->fnDecl.returns, node) || checkNodeInTree(tree->fnDecl.block, node);
|
||||
|
||||
case TOY_AST_NODE_FN_CALL:
|
||||
return checkNodeInTree(tree->fnCall.arguments, node);
|
||||
|
||||
case TOY_AST_NODE_FN_RETURN:
|
||||
return checkNodeInTree(tree->returns.returns, node);
|
||||
|
||||
case TOY_AST_NODE_IF:
|
||||
return checkNodeInTree(tree->pathIf.condition, node) || checkNodeInTree(tree->pathIf.thenPath, node) || checkNodeInTree(tree->pathIf.elsePath, node);
|
||||
|
||||
case TOY_AST_NODE_WHILE:
|
||||
return checkNodeInTree(tree->pathWhile.condition, node) || checkNodeInTree(tree->pathWhile.thenPath, node);
|
||||
|
||||
case TOY_AST_NODE_FOR:
|
||||
return checkNodeInTree(tree->pathFor.preClause, node) || checkNodeInTree(tree->pathFor.condition, node) || checkNodeInTree(tree->pathFor.postClause, node) || checkNodeInTree(tree->pathFor.thenPath, node);
|
||||
|
||||
case TOY_AST_NODE_ERROR:
|
||||
case TOY_AST_NODE_LITERAL:
|
||||
case TOY_AST_NODE_BREAK:
|
||||
case TOY_AST_NODE_CONTINUE:
|
||||
case TOY_AST_NODE_PREFIX_INCREMENT:
|
||||
case TOY_AST_NODE_PREFIX_DECREMENT:
|
||||
case TOY_AST_NODE_POSTFIX_INCREMENT:
|
||||
case TOY_AST_NODE_POSTFIX_DECREMENT:
|
||||
case TOY_AST_NODE_IMPORT:
|
||||
case TOY_AST_NODE_PASS:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include their sizes in the jump
|
||||
//NOTE: rootNode should NOT include groupings and blocks
|
||||
static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets, Toy_ASTNode* rootNode) {
|
||||
@@ -322,7 +397,8 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
//return this if...
|
||||
Toy_Opcode ret = Toy_writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
|
||||
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) && rootNode->binary.right != node) { //range-based check for assignment type; make sure the index is on the left of the assignment symbol
|
||||
//range-based check for assignment type; make sure the index is on the left of the assignment symbol
|
||||
if (node->binary.opcode == TOY_OP_INDEX && rootNode->type == TOY_AST_NODE_BINARY && (rootNode->binary.opcode >= TOY_OP_VAR_ASSIGN && rootNode->binary.opcode <= TOY_OP_VAR_MODULO_ASSIGN) && !checkNodeInTree(rootNode->binary.right, node)) {
|
||||
return TOY_OP_INDEX_ASSIGN_INTERMEDIATE;
|
||||
}
|
||||
|
||||
|
||||
10
test/scripts/index-assignment-intermediate-bugfix.toy
Normal file
10
test/scripts/index-assignment-intermediate-bugfix.toy
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
var result; //result must exist to ensure assingment, rather than declaration is invoked by the comparison below
|
||||
|
||||
var lhs = [0];
|
||||
var rhs = [0];
|
||||
|
||||
result = lhs[0] < rhs[0]; //make sure this doesn't invoke TOY_OP_INDEX_ASSIGN_INTERMEDIATE
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -121,6 +121,7 @@ int main() {
|
||||
"functions.toy",
|
||||
"index-arrays.toy",
|
||||
"index-assignment-both-bugfix.toy",
|
||||
"index-assignment-intermediate-bugfix.toy",
|
||||
"index-assignment-left-bugfix.toy",
|
||||
"index-dictionaries.toy",
|
||||
"index-strings.toy",
|
||||
|
||||
Reference in New Issue
Block a user