From 9a55ff221a7a9328d9c188154478e68f9aa2e39e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 7 Sep 2022 18:43:32 +0100 Subject: [PATCH] Fixed some indexing bugs --- README.md | 21 +++++++++++++++------ scripts/small.toy | 24 +++++++++++++++++------- scripts/test/index-arrays.toy | 16 +++++++++++++++- scripts/test/index-strings.toy | 15 +++++++++++++-- source/interpreter.c | 2 +- source/lib_builtin.c | 32 +++++++++++++++++++------------- source/parser.c | 11 +++++++++-- 7 files changed, 89 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 940c557..0f38f2a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,15 @@ This is the Toy programming language interpreter, written in C. Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path. +## Nifty Features + +* Simple C-like syntax +* Bytecode intermediate compilation +* `import` and `export` variables from the host program +* Optional, but robust type system +* functions and types are first-class citizens +* Fancy slice notation for strings, arrays and dictionaries (`print greeting[0:4:-1]; //prints "olleh"`) + ## Building Simply run make in the root directory. @@ -15,7 +24,7 @@ Simply run make in the root directory. ## Syntax ``` -import "standard"; //for a bunch of utility functions +import standard; //for a bunch of utility functions print "Hello world"; //"print" is a keyword @@ -36,13 +45,13 @@ fn makeCounter() { //declare a function like this return counter; //closures are explicitly supported } -var counter = makeCounter(); +var tally = makeCounter(); -print counter(); //1 -print counter(); //2 -print counter(); //3 +print tally(); //1 +print tally(); //2 +print tally(); //3 -export makeCounter; //export this variable to the host program +export tally; //export this variable to the host program ``` # License diff --git a/scripts/small.toy b/scripts/small.toy index 89062fc..1a2a795 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -2,14 +2,24 @@ -var t: type = astype [int]; -var u: type = astype [t]; +fn makeCounter() { + var total: int = 0; -var a: u; + fn counter(): int { + return ++total; + } -t = astype [float]; //redefnition + return counter; +} -var b: u; +var tally = makeCounter(); -print typeof a; //<[]> -print typeof b; //<[]> \ No newline at end of file +print tally(); //1 +print tally(); //2 +print tally(); //3 + +export tally; + +//heck yeah! +import tally as tally2; +print tally2(); //4 diff --git a/scripts/test/index-arrays.toy b/scripts/test/index-arrays.toy index 846544f..8908a55 100644 --- a/scripts/test/index-arrays.toy +++ b/scripts/test/index-arrays.toy @@ -1,8 +1,22 @@ + +//test basic indexing +{ + var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]; + + assert week[1] == "tuesday", "basic indexing failed (single element)"; + + assert week[1:1] == ["tuesday"], "basic indexing failed (single element as array)"; + + assert week[:] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first and second)"; + assert week[::] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first, second and third)"; +} + + //test basic replacement { var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]; - week[3] = "Holiday"; + week[3:3] = "Holiday"; assert week == ["monday", "tuesday", "wednesday", "Holiday", "friday", "saturday", "sunday"], "basic replacement failed"; } diff --git a/scripts/test/index-strings.toy b/scripts/test/index-strings.toy index 7aba228..e0896eb 100644 --- a/scripts/test/index-strings.toy +++ b/scripts/test/index-strings.toy @@ -1,13 +1,24 @@ -//test basic replacement +//test basic indexing var greeting: string = "hello world"; +assert greeting[1] == "e", "basic default index failed (first)"; + +assert greeting[:] == "hello world", "basic default index failed (first and second)"; + +assert greeting[::] == "hello world", "basic default index failed (first, second & third)"; + +assert greeting[0:4] == "hello", "basic indexing failed"; + + + +//test basic replacement greeting[0:4] = "goodnight"; assert greeting == "goodnight world", "basic replacement failed"; - //test backwards string assert greeting[::-1] == "dlrow thgindoog", "backwards string failed"; +assert greeting[11:15:-1] == "dlrow", "backwards indexed string failed"; //test string weird manipulation diff --git a/source/interpreter.c b/source/interpreter.c index 4b8b6f2..81095e0 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -1386,7 +1386,7 @@ static bool execIndex(Interpreter* interpreter) { freeLiteral(second); freeLiteral(first); freeLiteral(compound); - freeLiteral(idn); + //freeLiteral(idn); //since compound is freed, idn is still pointing there return false; } diff --git a/source/lib_builtin.c b/source/lib_builtin.c index 577410b..58121b7 100644 --- a/source/lib_builtin.c +++ b/source/lib_builtin.c @@ -329,7 +329,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { if (!IS_NULL(second)) { if (IS_BOOLEAN(second)) { freeLiteral(second); - second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count); + second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count - 1); } } @@ -387,10 +387,10 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { LiteralArray* result = ALLOCATE(LiteralArray, 1); initLiteralArray(result); - int min = AS_INTEGER(third) > 0 ? 0 : AS_INTEGER(second) - 1; + int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second); //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)) { + 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); @@ -417,7 +417,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { if (!IS_NULL(second)) { if (IS_BOOLEAN(second)) { freeLiteral(second); - second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count); + second = TO_INTEGER_LITERAL(AS_INTEGER(first)); } } @@ -487,15 +487,20 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { 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 + if (IS_ARRAY(assign)) { //push elements of an assigned array + 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); + //set result + pushLiteralArray(result, tmp); - freeLiteral(idx); - freeLiteral(tmp); + freeLiteral(idx); + freeLiteral(tmp); + } + } + else { //push just one element into the array + pushLiteralArray(result, assign); } for (int i = AS_INTEGER(second) + 1; i < AS_ARRAY(compound)->count; i++) { @@ -649,11 +654,12 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) { //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; + int lower = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(first) -1; + 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)) { + for (int i = min; i >= lower && i <= AS_INTEGER(second); i += AS_INTEGER(third)) { result[ resultIndex++ ] = AS_STRING(compound)[ i ]; } diff --git a/source/parser.c b/source/parser.c index 2262dd4..4c693b2 100644 --- a/source/parser.c +++ b/source/parser.c @@ -736,17 +736,24 @@ static Opcode indexAccess(Parser* parser, Node** nodeHandle) { emitNodeLiteral(&second, TO_BOOLEAN_LITERAL(true)); emitNodeLiteral(&third, TO_BOOLEAN_LITERAL(true)); + bool readFirst = false; //pattern matching is bullcrap + //eat the first if (!match(parser, TOKEN_COLON)) { freeNode(first); parsePrecedence(parser, &first, PREC_TERNARY); match(parser, TOKEN_COLON); + readFirst = true; } if (match(parser, TOKEN_BRACKET_RIGHT)) { - freeNode(second); + + if (readFirst) { + freeNode(second); + second = NULL; + } + freeNode(third); - second = NULL; third = NULL; emitNodeIndex(nodeHandle, first, second, third);