diff --git a/include/musique.hh b/include/musique.hh index 70041ce..3a88d96 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -833,14 +833,15 @@ struct Value /// Using Explicit_Bool to prevent from implicit casts static Value from(Explicit_Bool b); - static Value from(Number n); ///< Create value of type number holding provided number - static Value from(std::string s); ///< Create value of type symbol holding provided symbol - static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol - static Value from(char const* s); ///< Create value of type symbol holding provided symbol - static Value from(Block &&l); ///< Create value of type block holding provided block - static Value from(Array &&array); ///< Create value of type array holding provided array - static Value from(Note n); ///< Create value of type music holding provided note - static Value from(Chord chord); ///< Create value of type music holding provided chord + static Value from(Array &&array); ///< Create value of type array holding provided array + static Value from(Block &&l); ///< Create value of type block holding provided block + static Value from(Chord chord); ///< Create value of type music holding provided chord + static Value from(Note n); ///< Create value of type music holding provided note + static Value from(Number n); ///< Create value of type number holding provided number + static Value from(char const* s); ///< Create value of type symbol holding provided symbol + static Value from(std::string s); ///< Create value of type symbol holding provided symbol + static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol + static Value from(std::vector &&array); ///< Create value of type array holding provided array enum class Type { @@ -1094,4 +1095,8 @@ static constexpr bool is_callable(Value::Type type) return type == Value::Type::Block || type == Value::Type::Intrinsic; } +/// Flattens one layer: `[[[1], 2], 3]` becomes `[[1], 2, 3]` +Result> flatten(Interpreter &i, std::span); +Result> flatten(Interpreter &i, std::vector); + #endif diff --git a/src/builtin_functions.cc b/src/builtin_functions.cc index 82a08e9..4e62e9d 100644 --- a/src/builtin_functions.cc +++ b/src/builtin_functions.cc @@ -111,6 +111,7 @@ static Result into_flat_array(Interpreter &i, std::vector args) return into_flat_array(i, std::span(args)); } + /// Helper to convert method to it's name template struct Number_Method_Name; template<> struct Number_Method_Name<&Number::floor> { static constexpr auto value = "floor"; }; @@ -466,8 +467,8 @@ static Result builtin_update(Interpreter &i, std::vector args) if (Lazy_And_Number::typecheck_front(args)) { auto [v, index] = Lazy_And_Number::move_from(args); - auto array = Try(into_flat_array(i, { Value::from(std::move(v)) })); - array.elements[index.as_int()] = std::move(args.back()); + auto array = Try(flatten(i, { Value::from(std::move(v)) })); + array[index.as_int()] = std::move(args.back()); return Value::from(std::move(array)); } @@ -500,41 +501,41 @@ static Result builtin_flat(Interpreter &i, std::vector args) static Result builtin_shuffle(Interpreter &i, std::vector args) { static std::mt19937 rnd{std::random_device{}()}; - auto array = Try(into_flat_array(i, std::move(args))); - std::shuffle(array.elements.begin(), array.elements.end(), rnd); + auto array = Try(flatten(i, std::move(args))); + std::shuffle(array.begin(), array.end(), rnd); return Value::from(std::move(array)); } /// Permute arguments static Result builtin_permute(Interpreter &i, std::vector args) { - auto array = Try(into_flat_array(i, std::move(args))); - std::next_permutation(array.elements.begin(), array.elements.end()); + auto array = Try(flatten(i, std::move(args))); + std::next_permutation(array.begin(), array.end()); return Value::from(std::move(array)); } /// Sort arguments static Result builtin_sort(Interpreter &i, std::vector args) { - auto array = Try(into_flat_array(i, std::move(args))); - std::sort(array.elements.begin(), array.elements.end()); + auto array = Try(flatten(i, std::move(args))); + std::sort(array.begin(), array.end()); return Value::from(std::move(array)); } /// Reverse arguments static Result builtin_reverse(Interpreter &i, std::vector args) { - auto array = Try(into_flat_array(i, std::move(args))); - std::reverse(array.elements.begin(), array.elements.end()); + auto array = Try(flatten(i, std::move(args))); + std::reverse(array.begin(), array.end()); return Value::from(std::move(array)); } /// Get minimum of arguments static Result builtin_min(Interpreter &i, std::vector args) { - auto array = Try(into_flat_array(i, std::move(args))); - auto min = std::min_element(array.elements.begin(), array.elements.end()); - if (min == array.elements.end()) + 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; } @@ -542,9 +543,9 @@ static Result builtin_min(Interpreter &i, std::vector args) /// Get maximum of arguments static Result builtin_max(Interpreter &i, std::vector args) { - auto array = Try(into_flat_array(i, std::move(args))); - auto max = std::max_element(array.elements.begin(), array.elements.end()); - if (max == array.elements.end()) + 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; } @@ -563,10 +564,10 @@ static Result builtin_partition(Interpreter &i, std::vector args) auto predicate = std::move(args.front()); Try(guard(is_callable, predicate)); - auto array = Try(into_flat_array(i, std::span(args).subspan(1))); + auto array = Try(flatten(i, std::span(args).subspan(1))); Array tuple[2] = {}; - for (auto &value : array.elements) { + for (auto &value : array) { tuple[Try(predicate(i, { std::move(value) })).truthy()].elements.push_back(std::move(value)); } @@ -589,13 +590,13 @@ static Result builtin_rotate(Interpreter &i, std::vector args) } auto offset = std::move(args.front()).n.as_int(); - auto array = Try(into_flat_array(i, std::span(args).subspan(1))); + auto array = Try(flatten(i, std::span(args).subspan(1))); if (offset > 0) { - offset = offset % array.elements.size(); - std::rotate(array.elements.begin(), array.elements.begin() + offset, array.elements.end()); + offset = offset % array.size(); + std::rotate(array.begin(), array.begin() + offset, array.end()); } else if (offset < 0) { - offset = -offset % array.elements.size(); - std::rotate(array.elements.rbegin(), array.elements.rbegin() + offset, array.elements.rend()); + offset = -offset % array.size(); + std::rotate(array.rbegin(), array.rbegin() + offset, array.rend()); } return Value::from(std::move(array)); } diff --git a/src/value.cc b/src/value.cc index 4229701..a871acb 100644 --- a/src/value.cc +++ b/src/value.cc @@ -130,6 +130,14 @@ Value Value::from(Array &&array) return v; } +Value Value::from(std::vector &&array) +{ + Value v; + v.type = Type::Array; + v.array = Array { .elements = std::move(array) }; + return v; +} + Value Value::from(Note n) { Value v; @@ -494,3 +502,23 @@ std::ostream& operator<<(std::ostream& os, Chord const& chord) } return os << ']'; } + +Result> flatten(Interpreter &interpreter, std::span args) +{ + std::vector result; + for (auto &x : args) { + if (is_indexable(x.type)) { + for (usize i = 0; i < x.size(); ++i) { + result.push_back(Try(x.index(interpreter, i))); + } + } else { + result.push_back(std::move(x)); + } + } + return result; +} + +Result> flatten(Interpreter &i, std::vector args) +{ + return flatten(i, std::span(args)); +}