From 51740e2b9ecdf1dc83c177cb188e8c0d8804e493 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 15 Jan 2023 15:09:01 +0000 Subject: [PATCH] Resolved #25, Indexing an array with a non-integer causes an error --- source/builtin.c | 32 ++++++------ source/compiler.c | 5 ++ source/interpreter.c | 50 +++++++++++++++++-- source/literal.c | 4 ++ source/literal.h | 5 ++ source/parser.c | 6 +-- .../mustfail/index-arrays-non-integer.toy | 7 +++ test/test_mustfail.c | 1 + 8 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 test/scripts/mustfail/index-arrays-non-integer.toy diff --git a/source/builtin.c b/source/builtin.c index 15bd573..df5f70b 100644 --- a/source/builtin.c +++ b/source/builtin.c @@ -336,9 +336,9 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { if (IS_ARRAY(compound)) { //array slice if (IS_NULL(op)) { - //parse out the booleans & their defaults + //parse out the blanks & their defaults if (!IS_NULL(first)) { - if (IS_BOOLEAN(first)) { + if (IS_INDEX_BLANK(first)) { freeLiteral(first); first = TO_INTEGER_LITERAL(0); } @@ -351,7 +351,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } if (!IS_NULL(second)) { - if (IS_BOOLEAN(second)) { + if (IS_INDEX_BLANK(second)) { freeLiteral(second); second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count - 1); } @@ -363,7 +363,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - if (IS_NULL(third) || IS_BOOLEAN(third)) { + if (IS_NULL(third) || IS_INDEX_BLANK(third)) { freeLiteral(third); third = TO_INTEGER_LITERAL(1); } @@ -442,9 +442,9 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { //array slice assignment if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) { - //parse out the booleans & their defaults + //parse out the blanks & their defaults if (!IS_NULL(first)) { - if (IS_BOOLEAN(first)) { + if (IS_INDEX_BLANK(first)) { freeLiteral(first); first = TO_INTEGER_LITERAL(0); } @@ -457,7 +457,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } if (!IS_NULL(second)) { - if (IS_BOOLEAN(second)) { + if (IS_INDEX_BLANK(second)) { freeLiteral(second); second = TO_INTEGER_LITERAL(AS_INTEGER(first)); } @@ -469,7 +469,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - if (IS_NULL(third) || IS_BOOLEAN(third)) { + if (IS_NULL(third) || IS_INDEX_BLANK(third)) { freeLiteral(third); third = TO_INTEGER_LITERAL(1); } @@ -656,9 +656,9 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { if (IS_STRING(compound)) { //string slice if (IS_NULL(op)) { - //parse out the booleans & their defaults + //parse out the blanks & their defaults if (!IS_NULL(first)) { - if (IS_BOOLEAN(first)) { + if (IS_INDEX_BLANK(first)) { freeLiteral(first); first = TO_INTEGER_LITERAL(0); } @@ -672,7 +672,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { int compoundLength = AS_STRING(compound)->length; if (!IS_NULL(second)) { - if (IS_BOOLEAN(second)) { + if (IS_INDEX_BLANK(second)) { freeLiteral(second); second = TO_INTEGER_LITERAL(compoundLength); } @@ -684,7 +684,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - if (IS_NULL(third) || IS_BOOLEAN(third)) { + if (IS_NULL(third) || IS_INDEX_BLANK(third)) { freeLiteral(third); third = TO_INTEGER_LITERAL(1); } @@ -769,9 +769,9 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { //string slice assignment else if (IS_STRING(op) && equalsRefStringCString(AS_STRING(op), "=")) { - //parse out the booleans & their defaults + //parse out the blanks & their defaults if (!IS_NULL(first)) { - if (IS_BOOLEAN(first)) { + if (IS_INDEX_BLANK(first)) { freeLiteral(first); first = TO_INTEGER_LITERAL(0); } @@ -785,7 +785,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { int compoundLength = AS_STRING(compound)->length; if (!IS_NULL(second)) { - if (IS_BOOLEAN(second)) { + if (IS_INDEX_BLANK(second)) { freeLiteral(second); second = TO_INTEGER_LITERAL(compoundLength); } @@ -797,7 +797,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { } } - if (IS_NULL(third) || IS_BOOLEAN(third)) { + if (IS_NULL(third) || IS_INDEX_BLANK(third)) { freeLiteral(third); third = TO_INTEGER_LITERAL(1); } diff --git a/source/compiler.c b/source/compiler.c index 4bd3fac..bc43506 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -1176,6 +1176,11 @@ static unsigned char* collateCompilerHeaderOpt(Compiler* compiler, int* size, bo } break; + case LITERAL_INDEX_BLANK: + emitByte(&collation, &capacity, &count, LITERAL_INDEX_BLANK); + //blank has no following value + break; + default: fprintf(stderr, ERROR "[internal] Unknown literal type encountered within literal cache: %d\n" RESET, compiler->literalCache.literals[i].type); return NULL; diff --git a/source/interpreter.c b/source/interpreter.c index 0773bf4..ad65ca4 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -1563,7 +1563,22 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) { } //call the _index function - _index(interpreter, &arguments); + if (_index(interpreter, &arguments) < 0) { + interpreter->errorOutput("Something went wrong while indexing: "); + printLiteralCustom(idn, interpreter->errorOutput); + interpreter->errorOutput("\n"); + + //clean up + freeLiteral(third); + freeLiteral(second); + freeLiteral(first); + freeLiteral(compound); + if (freeIdn) { + freeLiteral(idn); + } + freeLiteralArray(&arguments); + return false; + } //clean up freeLiteral(third); @@ -1667,7 +1682,7 @@ static bool execIndexAssign(Interpreter* interpreter) { pushLiteralArray(&arguments, op); //it expects an assignment "opcode" //call the _index function - if (_index(interpreter, &arguments) == -1) { + if (_index(interpreter, &arguments) < 0) { //clean up freeLiteral(assign); freeLiteral(third); @@ -1715,7 +1730,25 @@ static bool execIndexAssign(Interpreter* interpreter) { pushLiteralArray(&arguments, result); pushLiteralArray(&arguments, op); - _index(interpreter, &arguments); + if (_index(interpreter, &arguments) < 0) { + interpreter->errorOutput("Something went wrong while indexing: "); + printLiteralCustom(idn, interpreter->errorOutput); + interpreter->errorOutput("\n"); + + //clean up + freeLiteral(assign); + freeLiteral(third); + freeLiteral(second); + freeLiteral(first); + freeLiteral(compound); + if (freeIdn) { + freeLiteral(idn); + } + freeLiteral(op); + freeLiteralArray(&arguments); + freeLiteral(result); + return false; + } freeLiteral(result); result = popLiteralArray(&interpreter->stack); @@ -2240,6 +2273,17 @@ static void readInterpreterSections(Interpreter* interpreter) { freeLiteral(typeLiteral); } break; + + case LITERAL_INDEX_BLANK: + //read the blank + pushLiteralArray(&interpreter->literalCache, TO_INDEX_BLANK_LITERAL); + +#ifndef TOY_EXPORT + if (command.verbose) { + printf("(blank)\n"); + } +#endif + break; } } diff --git a/source/literal.c b/source/literal.c index 77de57e..fca4c02 100644 --- a/source/literal.c +++ b/source/literal.c @@ -206,6 +206,7 @@ Literal copyLiteral(Literal original) { case LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler case LITERAL_FUNCTION_NATIVE: + case LITERAL_INDEX_BLANK: //no copying possible return original; @@ -333,6 +334,9 @@ bool literalsAreEqual(Literal lhs, Literal rhs) { fprintf(stderr, ERROR "[internal] Can't compare intermediate functions\n" RESET); return false; + case LITERAL_INDEX_BLANK: + return false; + default: //should never be seen fprintf(stderr, ERROR "[internal] Unrecognized literal type in equality: %d\n" RESET, lhs.type); diff --git a/source/literal.h b/source/literal.h index e2e8f5a..ed6594a 100644 --- a/source/literal.h +++ b/source/literal.h @@ -26,6 +26,7 @@ typedef enum { LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only LITERAL_FUNCTION_NATIVE, //for handling native functions only + LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:] } LiteralType; typedef struct { @@ -104,6 +105,10 @@ typedef struct { #define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }}) #define TO_OPAQUE_LITERAL(value, t) ((Literal){ LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }}) +//BUGFIX: For blank indexing +#define IS_INDEX_BLANK(value) ((value).type == LITERAL_INDEX_BLANK) +#define TO_INDEX_BLANK_LITERAL ((Literal){LITERAL_INDEX_BLANK, { .integer = 0 }}) + TOY_API void freeLiteral(Literal literal); #define IS_TRUTHY(x) _isTruthy(x) diff --git a/source/parser.c b/source/parser.c index 7e1068e..8badb03 100644 --- a/source/parser.c +++ b/source/parser.c @@ -726,9 +726,9 @@ static Opcode indexAccess(Parser* parser, ASTNode** nodeHandle) { //TODO: fix in ASTNode* third = NULL; //booleans indicate blank slice indexing - emitASTNodeLiteral(&first, TO_BOOLEAN_LITERAL(true)); - emitASTNodeLiteral(&second, TO_BOOLEAN_LITERAL(true)); - emitASTNodeLiteral(&third, TO_BOOLEAN_LITERAL(true)); + emitASTNodeLiteral(&first, TO_INDEX_BLANK_LITERAL); + emitASTNodeLiteral(&second, TO_INDEX_BLANK_LITERAL); + emitASTNodeLiteral(&third, TO_INDEX_BLANK_LITERAL); bool readFirst = false; //pattern matching is bullcrap diff --git a/test/scripts/mustfail/index-arrays-non-integer.toy b/test/scripts/mustfail/index-arrays-non-integer.toy new file mode 100644 index 0000000..f55f53f --- /dev/null +++ b/test/scripts/mustfail/index-arrays-non-integer.toy @@ -0,0 +1,7 @@ +{ + var a: [int] = [1, 2, 3]; + print a[a]; +} + + +print "All good"; diff --git a/test/test_mustfail.c b/test/test_mustfail.c index e00c6a2..9261ae3 100644 --- a/test/test_mustfail.c +++ b/test/test_mustfail.c @@ -130,6 +130,7 @@ int main() { "declare-types-array.toy", "declare-types-dictionary-key.toy", "declare-types-dictionary-value.toy", + "index-arrays-non-integer.toy", NULL };