1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:47:34 +00:00

LibJS: add Array.prototype.reduceRight()

This patch adds `Array.prototype.reduceRight()` method to LibJS Runtime. The implementation is (to my best knowledge) conformant to https://tc39.es/ecma262/#sec-array.prototype.reduceright.

Short test in `LibJS/Tests/Array.prototype-generic-functions.js` demonstrates that the function can be applied to other objects besides `Array`.
This commit is contained in:
Marcin Gasperowicz 2020-05-24 04:00:06 +02:00 committed by Andreas Kling
parent 9c8d390682
commit 99991761fd
4 changed files with 216 additions and 7 deletions

View file

@ -59,6 +59,7 @@ ArrayPrototype::ArrayPrototype()
put_native_function("slice", slice, 2, attr);
put_native_function("indexOf", index_of, 1, attr);
put_native_function("reduce", reduce, 1, attr);
put_native_function("reduceRight", reduce_right, 1, attr);
put_native_function("reverse", reverse, 0, attr);
put_native_function("lastIndexOf", last_index_of, 1, attr);
put_native_function("includes", includes, 1, attr);
@ -398,6 +399,10 @@ Value ArrayPrototype::reduce(Interpreter& interpreter)
if (interpreter.exception())
return {};
auto* callback_function = callback_from_args(interpreter, "reduce");
if (!callback_function)
return {};
size_t start = 0;
auto accumulator = js_undefined();
@ -420,10 +425,6 @@ Value ArrayPrototype::reduce(Interpreter& interpreter)
}
}
auto* callback_function = callback_from_args(interpreter, "reduce");
if (!callback_function)
return {};
auto this_value = js_undefined();
for (size_t i = start; i < initial_length; ++i) {
@ -447,6 +448,65 @@ Value ArrayPrototype::reduce(Interpreter& interpreter)
return accumulator;
}
Value ArrayPrototype::reduce_right(Interpreter& interpreter)
{
auto* this_object = interpreter.this_value().to_object(interpreter);
if (!this_object)
return {};
auto initial_length = get_length(interpreter, *this_object);
if (interpreter.exception())
return {};
auto* callback_function = callback_from_args(interpreter, "reduceRight");
if (!callback_function)
return {};
int start = initial_length - 1;
auto accumulator = js_undefined();
if (interpreter.argument_count() > 1) {
accumulator = interpreter.argument(1);
} else {
bool start_found = false;
while (!start_found && start >= 0) {
auto value = this_object->get_by_index(start);
if (interpreter.exception())
return {};
start_found = !value.is_empty();
if (start_found)
accumulator = value;
start -= 1;
}
if (!start_found) {
interpreter.throw_exception<TypeError>("Reduce of empty array with no initial value");
return {};
}
}
auto this_value = js_undefined();
for (int i = start; i >= 0; --i) {
auto value = this_object->get_by_index(i);
if (interpreter.exception())
return {};
if (value.is_empty())
continue;
MarkedValueList arguments(interpreter.heap());
arguments.append(accumulator);
arguments.append(value);
arguments.append(Value(i));
arguments.append(this_object);
accumulator = interpreter.call(*callback_function, this_value, move(arguments));
if (interpreter.exception())
return {};
}
return accumulator;
}
Value ArrayPrototype::reverse(Interpreter& interpreter)
{
auto* array = array_from(interpreter);

View file

@ -52,6 +52,7 @@ private:
static Value slice(Interpreter&);
static Value index_of(Interpreter&);
static Value reduce(Interpreter&);
static Value reduce_right(Interpreter&);
static Value reverse(Interpreter&);
static Value last_index_of(Interpreter&);
static Value includes(Interpreter&);