diff --git a/include/musique.hh b/include/musique.hh index df85dca..2fa938c 100644 --- a/include/musique.hh +++ b/include/musique.hh @@ -1023,6 +1023,11 @@ struct Shape static inline auto move_from(std::vector& args) { return ::move_from(args); } static inline auto typecheck(std::vector& args) { return ::typecheck(args, Types...); } static inline auto typecheck_front(std::vector& args) { return ::typecheck_front(args, Types...); } + + static inline auto typecheck_and_move(std::vector& args) + { + return typecheck(args) ? std::optional { move_from(args) } : std::nullopt; + } }; /// Returns if type can be indexed diff --git a/src/builtin_functions.cc b/src/builtin_functions.cc index 277afdf..1926e39 100644 --- a/src/builtin_functions.cc +++ b/src/builtin_functions.cc @@ -173,6 +173,42 @@ invalid_argument_type: }; } +enum class Range_Direction { Up, Down }; +template +Result builtin_range(Interpreter&, std::vector args) +{ + using N = Shape; + using NN = Shape; + using NNN = Shape; + + auto start = Number(0), stop = Number(0), step = Number(1); + + if (0) {} + else if (auto a = N::typecheck_and_move(args)) { std::tie(stop) = *a; } + else if (auto a = NN::typecheck_and_move(args)) { std::tie(start, stop) = *a; } + else if (auto a = NNN::typecheck_and_move(args)) { std::tie(start, stop, step) = *a; } + else { + return Error { + .details = errors::Unsupported_Types_For { + .type = errors::Unsupported_Types_For::Function, + .name = "range", + .possibilities = { + "(stop: number) -> array of number", + "(start: number, stop: number) -> array of number", + "(start: number, stop: number, step: number) -> array of number", + } + }, + .location = {} + }; + } + + Array array; + for (; start < stop; start += step) { + array.elements.push_back(Value::from(start)); + } + return Value::from(std::move(array)); +} + void Interpreter::register_builtin_functions() { auto &global = *Env::global; @@ -462,7 +498,7 @@ error: return Error { .details = errors::Unsupported_Types_For { .type = errors::Unsupported_Types_For::Function, - .name = "note_off", + .name = "program_change", .possibilities = { "(number) -> nil", "(number, number) -> nil", @@ -480,4 +516,8 @@ error: global.force_define("ceil", apply_numeric_transform<&Number::ceil>); global.force_define("floor", apply_numeric_transform<&Number::floor>); global.force_define("round", apply_numeric_transform<&Number::round>); + + global.force_define("range", builtin_range); + global.force_define("up", builtin_range); + global.force_define("down", builtin_range); }