From bc5736bf35415a48f0c83c98bb1adfdd884f49be Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Sun, 25 Sep 2022 10:40:36 +0200 Subject: [PATCH] Started builtins refactoring and testing --- musique/interpreter/builtin_functions.cc | 53 +++++++++++++++++------- musique/interpreter/interpreter.cc | 2 + musique/value/intrinsic.hh | 2 +- regression-tests/builtin/call.mq | 8 ++++ regression-tests/builtin/if.mq | 13 ++++++ regression-tests/builtin/max.mq | 6 +++ regression-tests/builtin/min.mq | 6 +++ regression-tests/builtin/reverse.mq | 4 ++ 8 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 regression-tests/builtin/call.mq create mode 100644 regression-tests/builtin/if.mq create mode 100644 regression-tests/builtin/max.mq create mode 100644 regression-tests/builtin/min.mq create mode 100644 regression-tests/builtin/reverse.mq diff --git a/musique/interpreter/builtin_functions.cc b/musique/interpreter/builtin_functions.cc index 3fd54e0..8270883 100644 --- a/musique/interpreter/builtin_functions.cc +++ b/musique/interpreter/builtin_functions.cc @@ -31,6 +31,28 @@ concept Iterable = (With_Index_Method || With_Index_Operator) && requires { t.size() } -> std::convertible_to; }; +static Result> deep_flat(Interpreter &interpreter, Iterable auto const& array) +{ + std::vector result; + + for (auto i = 0u; i < array.size(); ++i) { + Value element; + if constexpr (With_Index_Method) { + element = Try(array.index(interpreter, i)); + } else { + element = std::move(array[i]); + } + + if (auto collection = get_if(element)) { + std::ranges::move(Try(deep_flat(interpreter, *collection)), std::back_inserter(result)); + } else { + result.push_back(std::move(element)); + } + } + + return result; +} + /// Create chord out of given notes template static inline std::optional create_chord(std::vector &chord, Interpreter &interpreter, T&& args) @@ -543,7 +565,7 @@ static Result builtin_fold(Interpreter &interpreter, std::vector a /// Execute blocks depending on condition static Result builtin_if(Interpreter &i, std::vector args) { - constexpr auto guard = Guard<2> { + static constexpr auto guard = Guard<2> { .name = "if", .possibilities = { "(any, function) -> any", @@ -656,7 +678,7 @@ static Result builtin_shuffle(Interpreter &i, std::vector args) { static std::mt19937 rnd{std::random_device{}()}; auto array = Try(flatten(i, std::move(args))); - std::shuffle(array.begin(), array.end(), rnd); + std::ranges::shuffle(array, rnd); return array; } @@ -664,7 +686,7 @@ static Result builtin_shuffle(Interpreter &i, std::vector args) static Result builtin_permute(Interpreter &i, std::vector args) { auto array = Try(flatten(i, std::move(args))); - std::next_permutation(array.begin(), array.end()); + std::ranges::next_permutation(array); return array; } @@ -672,7 +694,7 @@ static Result builtin_permute(Interpreter &i, std::vector args) static Result builtin_sort(Interpreter &i, std::vector args) { auto array = Try(flatten(i, std::move(args))); - std::sort(array.begin(), array.end()); + std::ranges::sort(array); return array; } @@ -680,28 +702,26 @@ static Result builtin_sort(Interpreter &i, std::vector args) static Result builtin_reverse(Interpreter &i, std::vector args) { auto array = Try(flatten(i, std::move(args))); - std::reverse(array.begin(), array.end()); + std::ranges::reverse(array); return array; } /// Get minimum of arguments static Result builtin_min(Interpreter &i, std::vector args) { - auto array = Try(flatten(i, std::move(args))); - auto min = std::min_element(array.begin(), array.end()); - if (min == array.end()) - return Value{}; - return *min; + auto array = Try(deep_flat(i, std::move(args))); + if (auto min = std::ranges::min_element(array); min != array.end()) + return *min; + return Value{}; } /// Get maximum of arguments static Result builtin_max(Interpreter &i, std::vector args) { - auto array = Try(flatten(i, std::move(args))); - auto max = std::max_element(array.begin(), array.end()); - if (max == array.end()) - return Value{}; - return *max; + auto array = Try(deep_flat(i, std::move(args))); + if (auto max = std::ranges::max_element(array); max != array.end()) + return *max; + return Value{}; } /// Parition arguments into 2 arrays based on predicate @@ -935,7 +955,8 @@ static Result builtin_call(Interpreter &i, std::vector args) return guard.yield_error(); } - auto &callable = *Try(guard.match(args.front())); + auto fst = std::move(args.front()); + auto &callable = *Try(guard.match(fst)); args.erase(args.begin()); return callable(i, std::move(args)); } diff --git a/musique/interpreter/interpreter.cc b/musique/interpreter/interpreter.cc index ac8f7dc..9534e45 100644 --- a/musique/interpreter/interpreter.cc +++ b/musique/interpreter/interpreter.cc @@ -205,6 +205,8 @@ Result Interpreter::eval(Ast &&ast) } } + std::cout << ast.type << std::endl; + std::cout << ast.token.type << std::endl; unreachable(); } diff --git a/musique/value/intrinsic.hh b/musique/value/intrinsic.hh index eafa687..a91ad58 100644 --- a/musique/value/intrinsic.hh +++ b/musique/value/intrinsic.hh @@ -22,7 +22,7 @@ struct Intrinsic : Function constexpr ~Intrinsic() = default; /// Calls underlying function pointer - Result operator()(Interpreter&, std::vector) const; + Result operator()(Interpreter&, std::vector) const override; /// Compares if function pointers are equal bool operator==(Intrinsic const&) const = default; diff --git a/regression-tests/builtin/call.mq b/regression-tests/builtin/call.mq new file mode 100644 index 0000000..1774317 --- /dev/null +++ b/regression-tests/builtin/call.mq @@ -0,0 +1,8 @@ +-- Call executes blocks without parameters +say (call [42]); + +-- Call executes block passing parameters +say (call [n | n + 1] 10); + +-- Call executes builtin functions +call say 43; diff --git a/regression-tests/builtin/if.mq b/regression-tests/builtin/if.mq new file mode 100644 index 0000000..5acf312 --- /dev/null +++ b/regression-tests/builtin/if.mq @@ -0,0 +1,13 @@ +-- If executes then first block when condition is true +if true [say 1]; +if true [say 2] [say 3]; + +-- If executes second block when condition is false +if false [say 4] [say 5]; + +-- If returns nil when without else block +say (if false [say 6]); + +-- If returns block execution value +say (if true [7]); +say (if false [say 100; 8] [say 200; 9]); diff --git a/regression-tests/builtin/max.mq b/regression-tests/builtin/max.mq new file mode 100644 index 0000000..026854f --- /dev/null +++ b/regression-tests/builtin/max.mq @@ -0,0 +1,6 @@ +say (max 1 2 5 4 3); +say (max (200 + up 10)); +say (max (100 + down 10)); + +-- Max should do deep search +say (max 1 2 [3; 4; [5; 10; 8]; 1] 2); diff --git a/regression-tests/builtin/min.mq b/regression-tests/builtin/min.mq new file mode 100644 index 0000000..fe982b8 --- /dev/null +++ b/regression-tests/builtin/min.mq @@ -0,0 +1,6 @@ +say (min 1 2 5 4 3); +say (min (200 + up 10)); +say (min (100 + down 10)); + +-- Min should do deep search +say (min 1 2 [3; 4; [5; 0; 8]; 1] 2); diff --git a/regression-tests/builtin/reverse.mq b/regression-tests/builtin/reverse.mq new file mode 100644 index 0000000..ee80fa3 --- /dev/null +++ b/regression-tests/builtin/reverse.mq @@ -0,0 +1,4 @@ +say (reverse []); +say (reverse (up 10)); +say (reverse (reverse (up 10))); +say (reverse [[1; 2; 3]; 4; 5] 6 7 [[8; 9]]);