From d7c26e5858240a101085c1e8a1ce13928a39b112 Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Fri, 30 Dec 2022 15:30:50 +0100 Subject: [PATCH] digits builtin --- CHANGELOG.md | 1 + musique/interpreter/builtin_functions.cc | 57 ++++++++++++++++++++++++ regression-tests/builtin/digits.mq | 8 ++++ regression-tests/test_db.json | 18 +++++++- 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 regression-tests/builtin/digits.mq diff --git a/CHANGELOG.md b/CHANGELOG.md index e8bc40e..d64d89e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Printing version number on non-quiet launch, or when provided `--version` or `:version` - Builtin function documentation generation from C++ Musique implementation source code +- New builtins: digits ### Removed diff --git a/musique/interpreter/builtin_functions.cc b/musique/interpreter/builtin_functions.cc index c5b78b6..e81102b 100644 --- a/musique/interpreter/builtin_functions.cc +++ b/musique/interpreter/builtin_functions.cc @@ -1147,6 +1147,62 @@ static Result builtin_mix(Interpreter &i, std::vector args) return result; } +inline void append_digits(std::vector &digits, usize base, Number number) +{ + auto start = digits.size(); + + number.simplify_inplace(); + + auto integer_part = number.num / number.den; + number.num -= integer_part * number.den; + + do { + digits.push_back(integer_part % base); + integer_part /= base; + } while (integer_part != 0); + std::reverse(digits.begin() + start, digits.end()); + + if (number.den != 1) { + std::unordered_set repeats; + + do { + repeats.insert(number); + number.num *= base; + + auto const digit = number.floor().as_int(); + digits.push_back(digit); + + number.num = number.num - digit * number.den; + number.simplify_inplace(); + } while (number.num != 0 && !repeats.contains(number)); + } +} + +/// Converts number to array of its digits +static Result builtin_digits(Interpreter &interpreter, std::vector args) +{ + // For now it's a constant. It waits on some kind of keyword parameters + // so base can be provided nicely + auto const base = 10; + + std::vector digits; + + auto args_flattened = Try(deep_flat(interpreter, args)); + for (auto const& arg : args_flattened) { + if (auto num = get_if(arg)) { + append_digits(digits, base, *num); + } else { + // TODO This may be an error. Currently we fail silently + continue; + } + } + + std::vector result; + result.reserve(digits.size()); + std::transform(digits.begin(), digits.end(), std::back_inserter(result), [](auto digit) { return Number(digit); }); + return result; +} + /// Call operator. Calls first argument with remaining arguments static Result builtin_call(Interpreter &i, std::vector args) { @@ -1175,6 +1231,7 @@ void Interpreter::register_builtin_functions() global.force_define("call", builtin_call); global.force_define("ceil", builtin_ceil); global.force_define("chord", builtin_chord); + global.force_define("digits", builtin_digits); global.force_define("down", builtin_down); global.force_define("duration", builtin_duration); global.force_define("flat", builtin_flat); diff --git a/regression-tests/builtin/digits.mq b/regression-tests/builtin/digits.mq new file mode 100644 index 0000000..044a033 --- /dev/null +++ b/regression-tests/builtin/digits.mq @@ -0,0 +1,8 @@ +say (digits 3456), +say (digits (100/10)), +say (digits 0), +say (digits (0 - 1234)), +say (digits 0 0 0 0), +say (digits (4/3)), +say (digits 0.5), +say (digits 1234.5678), diff --git a/regression-tests/test_db.json b/regression-tests/test_db.json index 89e6fd7..000767b 100644 --- a/regression-tests/test_db.json +++ b/regression-tests/test_db.json @@ -200,7 +200,23 @@ "10" ], "stderr_lines": [] + }, + { + "name": "digits.mq", + "exit_code": 0, + "stdin_lines": [], + "stdout_lines": [ + "(3, 4, 5, 6)", + "(1, 0)", + "(0)", + "(1, 8, 4, 4, 6, 7, 4, 4, 0, 7, 3, 7, 0, 9, 5, 5, 0, 3, 8, 2)", + "(0, 0, 0, 0)", + "(1, 3)", + "(0, 5)", + "(1, 2, 3, 4, 5, 6, 7, 8)" + ], + "stderr_lines": [] } ] } -] +] \ No newline at end of file