diff --git a/musique/interpreter/builtin_operators.cc b/musique/interpreter/builtin_operators.cc index 38306db..7a57d4e 100644 --- a/musique/interpreter/builtin_operators.cc +++ b/musique/interpreter/builtin_operators.cc @@ -60,7 +60,7 @@ inline std::optional symetric(Value &lhs, Value &rhs, auto binary) /// n: number, m: music -> music /// m: music, n: number -> music moves m by n semitones (+ goes up, - goes down) template -static Result plus_minus_operator(Interpreter &interpreter, std::vector args) +static Result builtin_operator_add_subtract(Interpreter &interpreter, std::vector args) { if (args.empty()) { return Number(0); @@ -86,7 +86,7 @@ static Result plus_minus_operator(Interpreter &interpreter, std::vector(lhs) != holds_alternative(rhs)) { - return vectorize(plus_minus_operator, interpreter, std::move(lhs), std::move(rhs)); + return vectorize(builtin_operator_add_subtract, interpreter, std::move(lhs), std::move(rhs)); } static_assert(std::is_same_v, Binary_Operation> || std::is_same_v, Binary_Operation>, @@ -107,7 +107,7 @@ static Result plus_minus_operator(Interpreter &interpreter, std::vector -static Result binary_operator(Interpreter& interpreter, std::vector args) +static Result builtin_operator_arithmetic(Interpreter& interpreter, std::vector args) { static constexpr char Name[] = { Chars..., '\0' }; if (args.empty()) { @@ -121,7 +121,7 @@ static Result binary_operator(Interpreter& interpreter, std::vector(lhs) != holds_alternative(rhs)) { - return vectorize(binary_operator, interpreter, std::move(lhs), std::move(rhs)); + return vectorize(builtin_operator_arithmetic, interpreter, std::move(lhs), std::move(rhs)); } return errors::Unsupported_Types_For { @@ -138,7 +138,7 @@ static Result binary_operator(Interpreter& interpreter, std::vector -static Result comparison_operator(Interpreter &interpreter, std::vector args) +static Result builtin_operator_compare(Interpreter &interpreter, std::vector args) { if (args.size() != 2) { return algo::pairwise_all(std::move(args), Binary_Predicate{}); @@ -167,7 +167,7 @@ static Result comparison_operator(Interpreter &interpreter, std::vector multiplication_operator(Interpreter &i, std::vector args) +static Result builtin_operator_multiply(Interpreter &i, std::vector args) { if (args.empty()) { return Number(1); @@ -185,9 +185,9 @@ static Result multiplication_operator(Interpreter &i, std::vector } } - // If binary_operator returns an error that lists all possible overloads + // 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 = binary_operator, '*'>(i, { std::move(lhs), std::move(rhs) }); + auto result = builtin_operator_arithmetic, '*'>(i, { std::move(lhs), std::move(rhs) }); if (!result.has_value()) { auto &details = result.error().details; if (auto p = std::get_if(&details)) { @@ -200,6 +200,90 @@ static Result multiplication_operator(Interpreter &i, std::vector }); } +static Result builtin_operator_index(Interpreter &interpreter, std::vector args) +{ + if (auto a = match(args)) { + auto& [coll, pos] = *a; + return coll.index(interpreter, pos.as_int()); + } + + if (auto a = match(args)) { + if (auto& [coll, pos] = *a; pos) { + return coll.index(interpreter, 0); + } + return Value{}; + } + + if (auto a = match(args)) { + auto& [source, positions] = *a; + + std::vector result; + for (size_t n = 0; n < positions.size(); ++n) { + auto const v = Try(positions.index(interpreter, n)); + + auto index = std::visit(Overloaded { + [](Number n) -> std::optional { return n.floor().as_int(); }, + [n](Bool b) -> std::optional { return b ? std::optional(n) : std::nullopt; }, + [](auto &&) -> std::optional { return std::nullopt; } + }, v.data); + + if (index) { + result.push_back(Try(source.index(interpreter, *index))); + } + } + return Array(std::move(result)); + } + + return Error { + .details = errors::Unsupported_Types_For { + .type = errors::Unsupported_Types_For::Operator, + .name = ".", + .possibilities = { + "array . bool -> bool", + "array . number -> any", + "array . (array of numbers) -> array", + }, + }, + }; +} + +static Result builtin_operator_join(Interpreter &interpreter, std::vector args) +{ + constexpr auto guard = Guard<2> { + .name = "&", + .possibilities = { + "(array, array) -> array", + "(music, music) -> music", + }, + .type = errors::Unsupported_Types_For::Operator + }; + + if (auto a = match(args)) { + auto [lhs, rhs] = *a; + auto &l = lhs.notes, &r = rhs.notes; + if (l.size() < r.size()) { + std::swap(l, r); + std::swap(lhs, rhs); + } + + // Append one set of notes to another to make bigger chord! + l.reserve(l.size() + r.size()); + std::move(r.begin(), r.end(), std::back_inserter(l)); + + return lhs; + } + + auto result = Array {}; + for (auto&& a : args) { + auto &array = *Try(guard.match(a)); + for (auto n = 0u; n < array.size(); ++n) { + result.elements.push_back(Try(array.index(interpreter, n))); + } + } + return result; +} + + using Operator_Entry = std::tuple; using power = decltype([](Number lhs, Number rhs) -> Result { @@ -208,100 +292,22 @@ using power = decltype([](Number lhs, Number rhs) -> Result { /// Operators definition table static constexpr auto Operators = std::array { - Operator_Entry { "+", plus_minus_operator> }, - Operator_Entry { "-", plus_minus_operator> }, - Operator_Entry { "*", multiplication_operator }, - Operator_Entry { "/", binary_operator, '/'> }, - Operator_Entry { "%", binary_operator, '%'> }, - Operator_Entry { "**", binary_operator }, + Operator_Entry { "+", builtin_operator_add_subtract> }, + Operator_Entry { "-", builtin_operator_add_subtract> }, + Operator_Entry { "*", builtin_operator_multiply }, + Operator_Entry { "/", builtin_operator_arithmetic, '/'> }, + Operator_Entry { "%", builtin_operator_arithmetic, '%'> }, + Operator_Entry { "**", builtin_operator_arithmetic }, - Operator_Entry { "!=", comparison_operator> }, - Operator_Entry { "<", comparison_operator> }, - Operator_Entry { "<=", comparison_operator> }, - Operator_Entry { "==", comparison_operator> }, - Operator_Entry { ">", comparison_operator> }, - Operator_Entry { ">=", comparison_operator> }, + Operator_Entry { "!=", builtin_operator_compare> }, + Operator_Entry { "<", builtin_operator_compare> }, + Operator_Entry { "<=", builtin_operator_compare> }, + Operator_Entry { "==", builtin_operator_compare> }, + Operator_Entry { ">", builtin_operator_compare> }, + Operator_Entry { ">=", builtin_operator_compare> }, - Operator_Entry { ".", - +[](Interpreter &interpreter, std::vector args) -> Result { - if (auto a = match(args)) { - auto& [coll, pos] = *a; - return coll.index(interpreter, pos.as_int()); - } - if (auto a = match(args)) { - auto& [coll, pos] = *a; - return coll.index(interpreter, pos ? 1 : 0); - } - if (auto a = match(args)) { - auto& [source, positions] = *a; - - std::vector result; - for (size_t n = 0; n < positions.size(); ++n) { - auto const v = Try(positions.index(interpreter, n)); - - auto index = std::visit(Overloaded { - [](Number n) -> std::optional { return n.floor().as_int(); }, - [](Bool b) -> std::optional { return b ? 1 : 0; }, - [](auto &&) -> std::optional { return std::nullopt; } - }, v.data); - - if (index) { - result.push_back(Try(source.index(interpreter, *index))); - } - } - return Array(std::move(result)); - } - - return Error { - .details = errors::Unsupported_Types_For { - .type = errors::Unsupported_Types_For::Operator, - .name = ".", - .possibilities = { - "array . bool -> bool", - "array . number -> any", - "array . (array of numbers) -> array", - }, - }, - }; - } - }, - - Operator_Entry { "&", - +[](Interpreter& i, std::vector args) -> Result { - constexpr auto guard = Guard<2> { - .name = "&", - .possibilities = { - "(array, array) -> array", - "(music, music) -> music", - }, - .type = errors::Unsupported_Types_For::Operator - }; - - if (auto a = match(args)) { - auto [lhs, rhs] = *a; - auto &l = lhs.notes, &r = rhs.notes; - if (l.size() < r.size()) { - std::swap(l, r); - std::swap(lhs, rhs); - } - - // Append one set of notes to another to make bigger chord! - l.reserve(l.size() + r.size()); - std::move(r.begin(), r.end(), std::back_inserter(l)); - - return lhs; - } - - auto result = Array {}; - for (auto&& a : args) { - auto &array = *Try(guard.match(a)); - for (auto n = 0u; n < array.size(); ++n) { - result.elements.push_back(Try(array.index(i, n))); - } - } - return result; - } - }, + Operator_Entry { ".", builtin_operator_index }, + Operator_Entry { "&", builtin_operator_join }, }; // All operators should be defined here except 'and' and 'or' which handle evaluation differently