From 3088c4fe6dff6046e83668911b2a1dcf6c10bc34 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 5 Feb 2023 20:45:31 +0000 Subject: [PATCH] Implemented _concat --- repl/lib_compound.c | 113 +++++++++++++++++++++++++++++++++- scripts/small.toy | 38 ++++++++++-- test/scripts/lib/compound.toy | 34 ++++++++++ 3 files changed, 179 insertions(+), 6 deletions(-) diff --git a/repl/lib_compound.c b/repl/lib_compound.c index 0811a7a..57f942a 100644 --- a/repl/lib_compound.c +++ b/repl/lib_compound.c @@ -5,6 +5,115 @@ #include #include +static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to _concat\n"); + return -1; + } + + //get the args + Toy_Literal otherLiteral = Toy_popLiteralArray(arguments); + Toy_Literal selfLiteral = Toy_popLiteralArray(arguments); + + //parse to value if needed + Toy_Literal selfLiteralIdn = selfLiteral; + if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) { + Toy_freeLiteral(selfLiteralIdn); + } + + Toy_Literal otherLiteralIdn = otherLiteral; + if (TOY_IS_IDENTIFIER(otherLiteral) && Toy_parseIdentifierToValue(interpreter, &otherLiteral)) { + Toy_freeLiteral(otherLiteralIdn); + } + + //for each self type + if (TOY_IS_ARRAY(selfLiteral)) { + if (!TOY_IS_ARRAY(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //append each element of other to self, one-by-one + for (int i = 0; i < TOY_AS_ARRAY(otherLiteral)->count; i++) { + Toy_pushLiteralArray(TOY_AS_ARRAY(selfLiteral), TOY_AS_ARRAY(otherLiteral)->literals[i]); + } + + //return and clean up + Toy_pushLiteralArray(&interpreter->stack, selfLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + + return 1; + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + if (!TOY_IS_DICTIONARY(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //append each element of self to other, which will overwrite existing entries + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + if (!TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + Toy_setLiteralDictionary(TOY_AS_DICTIONARY(otherLiteral), TOY_AS_DICTIONARY(selfLiteral)->entries[i].key, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + } + } + + //return and clean up + Toy_pushLiteralArray(&interpreter->stack, otherLiteral); + + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + + return 1; + } + + if (TOY_IS_STRING(selfLiteral)) { //a little redundant + if (!TOY_IS_STRING(otherLiteral)) { + interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for other)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //get the combined length for the new string + int length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1; + + if (length > TOY_MAX_STRING_LENGTH) { + interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in _concat)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; + } + + //allocate the space and generate + char* buffer = TOY_ALLOCATE(char, length); + snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral))); + + Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer)); + + //push and clean up + Toy_pushLiteralArray(&interpreter->stack, result); + + TOY_FREE_ARRAY(char, buffer, length); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + + return 1; + } + + interpreter->errorOutput("Incorrect argument type passed to _concat (unknown type for self)\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(otherLiteral); + return -1; +} + static int nativeGetKeys(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { if (arguments->count != 1) { interpreter->errorOutput("Incorrect number of arguments to _getKeys\n"); @@ -147,7 +256,7 @@ static void toStringUtil(const char* input) { int len = strlen(input) + 1; if (len > TOY_MAX_STRING_LENGTH) { - len = TOY_MAX_STRING_LENGTH; + len = TOY_MAX_STRING_LENGTH; //TODO: don't truncate } toStringUtilObject = TOY_ALLOCATE(char, len); @@ -362,7 +471,7 @@ typedef struct Natives { int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) { //build the natives list Natives natives[] = { - // {"_concat", native}, //array, dictionary, string + {"_concat", nativeConcat}, //array, dictionary, string // {"_containsKey", native}, //dictionary // {"_containsValue", native}, //array, dictionary // {"_every", native}, //array, dictionary, string diff --git a/scripts/small.toy b/scripts/small.toy index 3113fd4..760e739 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1,6 +1,36 @@ import compound; -//test getKeys -var d = ["foo": 1, "bar": 2]; -var a = d.getValues(); -print a; +//test array concat +{ + var a = [1, 2, 3]; + var b = [4, 5, 6]; + + var c = a.concat(b).concat(b); + + assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed"; +} + +//test dictionary concat +{ + var a = ["one" : 1, "two": 2, "three": 3]; + var b = ["four" : 4, "five": 5, "six": 6]; + + var c = a.concat(b); + + assert c.length() == 6, "dictionary.concat().length() failed"; + + assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed"; +} + +//test string concat +{ + var a = "foo"; + var b = "bar"; + + var c = a.concat(b); + + assert c == "foobar", "string.concat() failed"; +} + + +print "All good"; diff --git a/test/scripts/lib/compound.toy b/test/scripts/lib/compound.toy index 4ee9c4e..36d73b1 100644 --- a/test/scripts/lib/compound.toy +++ b/test/scripts/lib/compound.toy @@ -1,5 +1,39 @@ import compound; +{ + //test array concat + { + var a = [1, 2, 3]; + var b = [4, 5, 6]; + + var c = a.concat(b).concat(b); + + assert c == [1, 2, 3, 4, 5, 6, 4, 5, 6], "array.concat() failed"; + } + + //test dictionary concat + { + var a = ["one" : 1, "two": 2, "three": 3]; + var b = ["four" : 4, "five": 5, "six": 6]; + + var c = a.concat(b); + + assert c.length() == 6, "dictionary.concat().length() failed"; + + assert c == ["one" : 1, "two": 2, "three": 3, "four" : 4, "five": 5, "six": 6], "dictionary.concat() comparison failed"; + } + + //test string concat + { + var a = "foo"; + var b = "bar"; + + var c = a.concat(b); + + assert c == "foobar", "string.concat() failed"; + } +} + //test getKeys { var d = ["foo": 1, "bar": 2];