diff --git a/CHANGELOG.md b/CHANGELOG.md index 06bb7aa..647e91b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved from ';' to ',' notation for expression separator - Moved 'if', 'while' from beeing functions to macros - side effect of new notation - Build system uses now Docker +- Array repetition using `number * array` like `3 * (c, e) == (c, e, c, e, c, e)` ### Fixed diff --git a/musique/interpreter/builtin_operators.cc b/musique/interpreter/builtin_operators.cc index c2ee6cf..8fb9922 100644 --- a/musique/interpreter/builtin_operators.cc +++ b/musique/interpreter/builtin_operators.cc @@ -44,7 +44,10 @@ static Result vectorize(auto &&operation, Interpreter &interpreter, std:: /// /// Calls binary if values matches types any permutation of {t1, t2}, always in shape (t1, t2) template -inline std::optional symetric(Value &lhs, Value &rhs, auto binary) +inline auto symetric(Value &lhs, Value &rhs, auto binary) + -> std::optional(lhs, rhs)) + )> { if (auto a = match(lhs, rhs)) { return std::apply(std::move(binary), *a); @@ -167,14 +170,14 @@ static Result builtin_operator_compare(Interpreter &interpreter, std::vec return Binary_Predicate{}(std::move(args.front()), std::move(args.back())); } -static Result builtin_operator_multiply(Interpreter &i, std::vector args) +static Result builtin_operator_multiply(Interpreter &interpreter, std::vector args) { if (args.empty()) { return Number(1); } auto init = std::move(args.front()); - return algo::fold(std::span(args).subspan(1), std::move(init), [&i](Value lhs, Value &rhs) -> Result { + return algo::fold(std::span(args).subspan(1), std::move(init), [&interpreter](Value lhs, Value &rhs) -> Result { { auto result = symetric(lhs, rhs, [](Number lhs, Chord &rhs) { return Array { std::vector(lhs.floor().as_int(), std::move(rhs)) }; @@ -184,10 +187,26 @@ static Result builtin_operator_multiply(Interpreter &i, std::vector(lhs, rhs, [&interpreter](Number lhs, Collection &rhs) -> Result { + std::vector values; + values.reserve(rhs.size() * lhs.floor().as_int()); + for (unsigned j = 0; j < lhs.floor().as_int(); ++j) { + for (unsigned i = 0; i < rhs.size(); ++i) { + values.push_back(Try(rhs.index(interpreter, i))); + } + } + return values; + }); + + if (result.has_value()) { + return *std::move(result); + } + } // If builtin_operator_arithmetic returns an error that lists all possible overloads // of this operator we must inject overloads that we provided above - auto result = builtin_operator_arithmetic, '*'>(i, { std::move(lhs), std::move(rhs) }); + auto result = builtin_operator_arithmetic, '*'>(interpreter, { std::move(lhs), std::move(rhs) }); if (!result.has_value()) { auto &details = result.error().details; if (auto p = std::get_if(&details)) { diff --git a/musique/value/note.cc b/musique/value/note.cc index 39f2a8f..05c7916 100644 --- a/musique/value/note.cc +++ b/musique/value/note.cc @@ -63,7 +63,7 @@ endloop: ; } - if (note && literal.size()) { + if (note && note->base && literal.size()) { auto &octave = note->octave.emplace(); auto [p, ec] = std::from_chars(&literal.front(), 1 + &literal.back(), octave); ensure(p == &literal.back() + 1, "Parser must have failed in recognizing what is considered a valid note token #1");