diff --git a/repl/lib_compound.c b/repl/lib_compound.c index a314c05..3fa7ed4 100644 --- a/repl/lib_compound.c +++ b/repl/lib_compound.c @@ -996,6 +996,97 @@ static int nativeSome(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) return 1; } +static void swapLiteralsUtil(Toy_Literal* lhs, Toy_Literal* rhs) { + Toy_Literal tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + +//https://www.youtube.com/watch?v=MZaf_9IZCrc +static void recursiveLiteralQuicksortUtil(Toy_Interpreter* interpreter, Toy_Literal* ptr, int literalCount, Toy_Literal fnCompareLiteral) { + //base case + if (literalCount <= 1) { + return; + } + + int runner = 0; + + //iterate through the array + for (int checker = 0; checker < literalCount - 1; checker++) { + Toy_LiteralArray arguments; + Toy_LiteralArray returns; + + Toy_initLiteralArray(&arguments); + Toy_initLiteralArray(&returns); + + Toy_pushLiteralArray(&arguments, ptr[literalCount - 1]); //backwards + Toy_pushLiteralArray(&arguments, ptr[checker]); + + Toy_callLiteralFn(interpreter, fnCompareLiteral, &arguments, &returns); + + Toy_Literal lessThan = Toy_popLiteralArray(&returns); + + Toy_freeLiteralArray(&arguments); + Toy_freeLiteralArray(&returns); + + if (TOY_IS_TRUTHY(lessThan)) { + swapLiteralsUtil(&ptr[runner++], &ptr[checker]); + } + + Toy_freeLiteral(lessThan); + } + + //"shift everything up" so the pivot is in the middle + swapLiteralsUtil(&ptr[runner], &ptr[literalCount - 1]); + + //recurse on each end + recursiveLiteralQuicksortUtil(interpreter, &ptr[0], runner, fnCompareLiteral); + recursiveLiteralQuicksortUtil(interpreter, &ptr[runner + 1], literalCount - runner - 1, fnCompareLiteral); +} + +static int nativeSort(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { + //no arguments + if (arguments->count != 2) { + interpreter->errorOutput("Incorrect number of arguments to _sort\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_FUNCTION(fnLiteral) || TOY_IS_FUNCTION_NATIVE(fnLiteral) )) { + interpreter->errorOutput("Incorrect argument type passed to _sort\n"); + Toy_freeLiteral(selfLiteral); + Toy_freeLiteral(fnLiteral); + return -1; + } + + //call the quicksort util + if (TOY_IS_ARRAY(selfLiteral)) { + recursiveLiteralQuicksortUtil(interpreter, TOY_AS_ARRAY(selfLiteral)->literals, TOY_AS_ARRAY(selfLiteral)->count, fnLiteral); + } + + Toy_pushLiteralArray(&interpreter->stack, selfLiteral); + + Toy_freeLiteral(fnLiteral); + Toy_freeLiteral(selfLiteral); + + return 1; +} + static int nativeToLower(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) { //no arguments if (arguments->count != 1) { @@ -1451,7 +1542,7 @@ int Toy_hookCompound(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L {"_map", nativeMap}, //array, dictionary {"_reduce", nativeReduce}, //array, dictionary {"_some", nativeSome}, //array, dictionary - // {"_sort", native}, //array + {"_sort", nativeSort}, //array {"_toLower", nativeToLower}, //string {"_toString", nativeToString}, //array, dictionary {"_toUpper", nativeToUpper}, //string diff --git a/scripts/small.toy b/scripts/small.toy index 43428aa..d954e85 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1,22 +1,27 @@ -//polyfill the _insert function -fn _insert(self, k, v) { - var tmp1 = v; - var tmp2; - for (var i = k; i < self.length(); i++) { - tmp2 = self[i]; - self[i] = tmp1; - tmp1 = tmp2; - } +import compound; - self.push(tmp1); - return self; +fn less(a, b) { + return a < b; } -var a = [1, 2, 3]; +fn greater(a, b) { + return a > b; +} -a = a.insert(1, 42); +var a = [7, 2, 1, 8, 6, 3, 5, 4]; +var b = [7, 2, 1, 4, 6, 3, 5, 8]; +var c = [1, 2, 3, 4, 5, 6, 7, 8]; +var d = [7, 2, 1, 8, 6, 3, 5, 4]; -assert a == [1, 5, 2, 3], "index assignment left failed"; +a = a.sort(less); +b = b.sort(less); +c = c.sort(less); +d = d.sort(greater); + +assert a == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) failed"; +assert b == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) with pivot high failed"; +assert c == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) pre-sorted array failed"; +assert d == [8, 7, 6, 5, 4, 3, 2, 1], "array.sort(greater) failed"; -print "All good"; \ No newline at end of file +print "All good"; diff --git a/test/scripts/lib/compound.toy b/test/scripts/lib/compound.toy index 5d7b753..eaa16bc 100644 --- a/test/scripts/lib/compound.toy +++ b/test/scripts/lib/compound.toy @@ -228,6 +228,33 @@ import compound; } +//test sort +{ + fn less(a, b) { + return a < b; + } + + fn greater(a, b) { + return a > b; + } + + var a = [7, 2, 1, 8, 6, 3, 5, 4]; + var b = [7, 2, 1, 4, 6, 3, 5, 8]; + var c = [1, 2, 3, 4, 5, 6, 7, 8]; + var d = [7, 2, 1, 8, 6, 3, 5, 4]; + + a = a.sort(less); + b = b.sort(less); + c = c.sort(less); + d = d.sort(greater); + + assert a == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) failed"; + assert b == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) with pivot high failed"; + assert c == [1, 2, 3, 4, 5, 6, 7, 8], "array.sort(less) pre-sorted array failed"; + assert d == [8, 7, 6, 5, 4, 3, 2, 1], "array.sort(greater) failed"; +} + + //test toLower { assert "Hello World".toLower() == "hello world", "_toLower() failed";