digits builtin

This commit is contained in:
Robert Bendun 2022-12-30 15:30:50 +01:00
parent bda1e503c7
commit d7c26e5858
4 changed files with 83 additions and 1 deletions

View File

@ -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

View File

@ -1147,6 +1147,62 @@ static Result<Value> builtin_mix(Interpreter &i, std::vector<Value> args)
return result;
}
inline void append_digits(std::vector<uint8_t> &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<Number> 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<Value> builtin_digits(Interpreter &interpreter, std::vector<Value> 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<uint8_t> digits;
auto args_flattened = Try(deep_flat(interpreter, args));
for (auto const& arg : args_flattened) {
if (auto num = get_if<Number>(arg)) {
append_digits(digits, base, *num);
} else {
// TODO This may be an error. Currently we fail silently
continue;
}
}
std::vector<Value> 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<Value> builtin_call(Interpreter &i, std::vector<Value> 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);

View File

@ -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),

View File

@ -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": []
}
]
}
]
]