From 3ba2e420ea1b523e33ef14334a06d9bb065dc4b8 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 10 Feb 2023 15:00:15 +0000 Subject: [PATCH] Added _every() and _some() --- repl/lib_compound.c | 234 +++++++++++++++++++++++++++++++++- scripts/small.toy | 15 ++- source/toy_literal.c | 4 +- test/scripts/lib/compound.toy | 56 ++++++++ 4 files changed, 304 insertions(+), 5 deletions(-) diff --git a/repl/lib_compound.c b/repl/lib_compound.c index 52eedc4..dc2d1e0 100644 --- a/repl/lib_compound.c +++ b/repl/lib_compound.c @@ -115,6 +115,121 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument return -1; } +static int nativeEvery(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to _every\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = 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 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 _every\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + bool result = true; + + // + 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_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + + //if not truthy + if (!TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = false; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + bool result = true; + + 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_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + //if not truthy + if (!TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = false; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + static int nativeForEach(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 2) { @@ -484,6 +599,121 @@ static int nativeReduce(Toy_Interpreter* interpreter, Toy_LiteralArray* argument return 0; } +static int nativeSome(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to _some\n"); + return -1; + } + + //get the args + Toy_Literal fnLiteral = 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 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 _some\n"); + Toy_freeLiteral(selfLiteral); + return -1; + } + + //call the given function on each element, based on the compound type + if (TOY_IS_ARRAY(selfLiteral)) { + bool result = false; + + // + 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_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + Toy_freeLiteral(indexLiteral); + + //if not truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = true; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + if (TOY_IS_DICTIONARY(selfLiteral)) { + bool result = false; + + 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_LiteralArray returns; + Toy_initLiteralArray(&returns); + + Toy_callLiteralFn(interpreter, fnLiteral, &arguments, &returns); + + //grab the results + Toy_Literal lit = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + //if not truthy + if (TOY_IS_TRUTHY(lit)) { + Toy_freeLiteral(lit); + result = true; + break; + } + + Toy_freeLiteral(lit); + } + + Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result); + Toy_pushLiteralArray(&interpreter->stack, resultLiteral); + Toy_freeLiteral(resultLiteral); + } + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 0; +} + static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { @@ -930,7 +1160,7 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"_concat", nativeConcat}, //array, dictionary, string // {"_containsKey", native}, //dictionary // {"_containsValue", native}, //array, dictionary - // {"_every", native}, //array, dictionary, string + {"_every", nativeEvery}, //array, dictionary // {"_filter", native}, //array, dictionary {"_forEach", nativeForEach}, //array, dictionary {"_getKeys", nativeGetKeys}, //dictionary @@ -941,7 +1171,7 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"_reduce", nativeReduce}, //array, dictionary // {"_remove", native}, //array, dictionary // {"_replace", native}, //string - // {"_some", native}, //array, dictionary, string + {"_some", nativeSome}, //array, dictionary // {"_sort", native}, //array {"_toLower", nativeToLower}, //string {"_toString", nativeToString}, //array, dictionary diff --git a/scripts/small.toy b/scripts/small.toy index f3e002a..3a5666d 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1,2 +1,15 @@ -/* +import compound; +var a = [false, false, false]; +var d = ["one": false, "two": false]; + +fn f(k, v) { return v; } + +print a.some(f); +print d.some(f); + +a[1] = true; +d["two"] = true; + +print a.some(f); +print d.some(f); diff --git a/source/toy_literal.c b/source/toy_literal.c index 813c5b5..bde9c85 100644 --- a/source/toy_literal.c +++ b/source/toy_literal.c @@ -72,7 +72,7 @@ void Toy_freeLiteral(Toy_Literal literal) { bool Toy_private_isTruthy(Toy_Literal x) { if (TOY_IS_NULL(x)) { - fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Null is neither true nor false\n" TOY_CC_RESET); + fprintf(stderr, TOY_CC_ERROR "Null is neither true nor false\n" TOY_CC_RESET); return false; } @@ -228,7 +228,7 @@ Toy_Literal Toy_copyLiteral(Toy_Literal original) { return original; default: - fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't copy that literal type: %d\n" TOY_CC_RESET, original.type); + fprintf(stderr, TOY_CC_ERROR "Can't copy that literal type: %d\n" TOY_CC_RESET, original.type); return TOY_TO_NULL_LITERAL; } } diff --git a/test/scripts/lib/compound.toy b/test/scripts/lib/compound.toy index c87d3ca..3609aa8 100644 --- a/test/scripts/lib/compound.toy +++ b/test/scripts/lib/compound.toy @@ -45,6 +45,34 @@ import compound; } } + +//test every +{ + var a = [1, 2, 3]; + var d = ["one": 1, "two": 2]; + + var counter = 0; + fn f(k, v) { + counter++; + return v; + } + + assert a.every(f) == true, "array.every() == true failed"; + assert d.every(f) == true, "dictionary.every() == true failed"; + + assert counter == 5, "Unexpected number of calls for _every() == true"; + + counter = 0; + a[1] = false; + d["two"] = false; + + assert a.every(f) == false, "array.every() == false failed"; + assert d.every(f) == false, "dictionary.every() == false failed"; + + assert counter == 4, "Unexpected number of calls for _every() == false"; +} + + //test forEach { var counter = 0; @@ -65,6 +93,7 @@ import compound; assert counter == 4, "forEach ran an unusual number of times"; } + //test getKeys { var d = ["foo": 1, "bar": 2]; @@ -127,6 +156,33 @@ import compound; } +//test some +{ + var a = [false, false, false]; + var d = ["one": false, "two": false]; + + var counter = 0; + fn f(k, v) { + counter++; + return v; + } + + assert a.some(f) == false, "array.some() == false failed"; + assert d.some(f) == false, "dictionary.some() == false failed"; + + assert counter == 5, "Unexpected number of calls for _some() == false"; + + counter = 0; + a[1] = true; + d["two"] = true; + + assert a.some(f) == true, "array.some() == true failed"; + assert d.some(f) == true, "dictionary.some() == true failed"; + + assert counter == 4, "Unexpected number of calls for _some() == true"; +} + + //test toLower { assert "Hello World".toLower() == "hello world", "_toLower() failed";