diff --git a/repl/lib_compound.c b/repl/lib_compound.c index 09b6c14..d101b77 100644 --- a/repl/lib_compound.c +++ b/repl/lib_compound.c @@ -385,6 +385,105 @@ static int nativeMap(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 0; } +static int nativeReduce(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 3) { + interpreter->errorOutput("Incorrect number of arguments to _reduce\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = Toy_popLiteralArray(arguments); + Toy_Literal defaultLiteral = 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 defaultLiteralIdn = defaultLiteral; + if (TOY_IS_IDENTIFIER(defaultLiteral) && Toy_parseIdentifierToValue(interpreter, &defaultLiteral)) { + Toy_freeLiteral(defaultLiteralIdn); + } + + Toy_Literal fnLiteralIdn = fnLiteral; + if (TOY_IS_IDENTIFIER(fnLiteral) && Toy_parseIdentifierToValue(interpreter, &fnLiteral)) { + Toy_freeLiteral(fnLiteralIdn); + } + + //check type + if (!( TOY_IS_ARRAY(selfLiteral) || TOY_IS_DICTIONARY(selfLiteral) ) || !( TOY_IS_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to _reduce\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + for (int i = 0; i < TOY_AS_ARRAY(selfLiteral)->count; i++) { + Toy_Literal indexLiteral = TOY_TO_INTEGER_LITERAL(i); + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_ARRAY(selfLiteral)->literals[i]); + Toy_pushLiteralArray(&arguments, indexLiteral); + Toy_pushLiteralArray(&arguments, defaultLiteral); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_freeLiteral(defaultLiteral); + defaultLiteral = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + } + + Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + for (int i = 0; i < TOY_AS_DICTIONARY(selfLiteral)->capacity; i++) { + //skip nulls + if (TOY_IS_NULL(TOY_AS_DICTIONARY(selfLiteral)->entries[i].key)) { + continue; + } + + Toy_LiteralArray arguments; + Toy_initLiteralArray(&arguments); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].value); + Toy_pushLiteralArray(&arguments, TOY_AS_DICTIONARY(selfLiteral)->entries[i].key); + Toy_pushLiteralArray(&arguments, defaultLiteral); + + Toy_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_freeLiteral(defaultLiteral); + defaultLiteral = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + } + + Toy_pushLiteralArray(&interpreter->stack, defaultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(defaultLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { @@ -839,7 +938,7 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L // {"_indexOf", native}, //array, string // {"_insert", native}, //array, dictionary, string {"_map", nativeMap}, //array, dictionary - // {"_reduce", native}, //array, dictionary + {"_reduce", nativeReduce}, //array, dictionary // {"_remove", native}, //array, dictionary // {"_replace", native}, //string // {"_some", native}, //array, dictionary, string diff --git a/scripts/small.toy b/scripts/small.toy index e69de29..aa075fa 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -0,0 +1,2 @@ +import compound; + diff --git a/test/scripts/lib/compound.toy b/test/scripts/lib/compound.toy index 0182df2..c87d3ca 100644 --- a/test/scripts/lib/compound.toy +++ b/test/scripts/lib/compound.toy @@ -113,6 +113,20 @@ import compound; } +//test reduce +{ + var a = [1, 2, 3, 4]; + var d = ["one": 1, "two": 2, "three": 3, "four": 4]; + + fn f(acc, k, v) { + return acc + v; + } + + assert a.reduce(0, f) == 10, "array.reduce() failed"; + assert d.reduce(0, f) == 10, "dictionary.reduce() failed"; +} + + //test toLower { assert "Hello World".toLower() == "hello world", "_toLower() failed"; @@ -161,12 +175,12 @@ import compound; //test trim custom values { - var chars = "heilod"; + var chars = "heliod"; assert "hello world".trim(chars) == " wor", "custom _trim() failed"; } - //test trimBegin() + //test trimBegin() & trimEnd() assert " foo ".trimBegin() == "foo ", "string.trimBegin() failed"; assert " foo ".trimEnd() == " foo", "string.trimBegin() failed"; }