mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
LibJS: Implement 'Relative Indexing Method' proposal (.at())
Still stage 3, but already implemented in major engines and unlikely to change - there isn't much to change here anyway. :^) See: - https://github.com/tc39/proposal-relative-indexing-method - https://tc39.es/proposal-relative-indexing-method/ - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
This commit is contained in:
parent
9769542bc2
commit
2d8362cceb
Notes:
sideshowbarker
2024-07-18 21:27:58 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/2d8362cceb6 Pull-request: https://github.com/SerenityOS/serenity/pull/5746
10 changed files with 155 additions and 10 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020-2021, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020, Marcin Gasperowicz <xnooga@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -81,6 +81,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
|
|||
define_native_function(vm.names.fill, fill, 1, attr);
|
||||
define_native_function(vm.names.values, values, 0, attr);
|
||||
define_native_function(vm.names.flat, flat, 0, attr);
|
||||
define_native_function(vm.names.at, at, 1, attr);
|
||||
|
||||
// Use define_property here instead of define_native_function so that
|
||||
// Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
|
||||
|
@ -1081,4 +1082,30 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat)
|
|||
return {};
|
||||
return new_array;
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::at)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return {};
|
||||
auto length = length_of_array_like(global_object, *this_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
auto relative_index = vm.argument(0).to_integer_or_infinity(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (Value(relative_index).is_infinity())
|
||||
return js_undefined();
|
||||
Checked<size_t> index { 0 };
|
||||
if (relative_index >= 0) {
|
||||
index += relative_index;
|
||||
} else {
|
||||
index += length;
|
||||
index -= -relative_index;
|
||||
}
|
||||
if (index.has_overflow() || index.value() >= length)
|
||||
return js_undefined();
|
||||
return this_object->get(index.value());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020-2021, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -67,6 +67,7 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(fill);
|
||||
JS_DECLARE_NATIVE_FUNCTION(values);
|
||||
JS_DECLARE_NATIVE_FUNCTION(flat);
|
||||
JS_DECLARE_NATIVE_FUNCTION(at);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace JS {
|
|||
P(asUintN) \
|
||||
P(asin) \
|
||||
P(asinh) \
|
||||
P(at) \
|
||||
P(atan) \
|
||||
P(atan2) \
|
||||
P(atanh) \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020-2021, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -25,6 +25,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
|
@ -82,7 +83,7 @@ void StringPrototype::initialize(GlobalObject& global_object)
|
|||
StringObject::initialize(global_object);
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
|
||||
define_native_property(vm.names.length, length_getter, {}, 0);
|
||||
define_native_property(vm.names.length, length_getter, nullptr, 0);
|
||||
define_native_function(vm.names.charAt, char_at, 1, attr);
|
||||
define_native_function(vm.names.charCodeAt, char_code_at, 1, attr);
|
||||
define_native_function(vm.names.repeat, repeat, 1, attr);
|
||||
|
@ -104,6 +105,7 @@ void StringPrototype::initialize(GlobalObject& global_object)
|
|||
define_native_function(vm.names.slice, slice, 2, attr);
|
||||
define_native_function(vm.names.split, split, 2, attr);
|
||||
define_native_function(vm.names.lastIndexOf, last_index_of, 1, attr);
|
||||
define_native_function(vm.names.at, at, 1, attr);
|
||||
define_native_function(vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
|
||||
}
|
||||
|
||||
|
@ -612,6 +614,29 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
|
|||
return Value(-1);
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at)
|
||||
{
|
||||
auto string = ak_string_from(vm, global_object);
|
||||
if (string.is_null())
|
||||
return {};
|
||||
auto length = string.length();
|
||||
auto relative_index = vm.argument(0).to_integer_or_infinity(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (Value(relative_index).is_infinity())
|
||||
return js_undefined();
|
||||
Checked<size_t> index { 0 };
|
||||
if (relative_index >= 0) {
|
||||
index += relative_index;
|
||||
} else {
|
||||
index += length;
|
||||
index -= -relative_index;
|
||||
}
|
||||
if (index.has_overflow() || index.value() >= length)
|
||||
return js_undefined();
|
||||
return js_string(vm, String::formatted("{}", string[index.value()]));
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator)
|
||||
{
|
||||
auto this_object = vm.this_value(global_object);
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
virtual ~StringPrototype() override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_GETTER(length_getter);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(char_at);
|
||||
JS_DECLARE_NATIVE_FUNCTION(char_code_at);
|
||||
JS_DECLARE_NATIVE_FUNCTION(repeat);
|
||||
|
@ -52,9 +54,6 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(pad_end);
|
||||
JS_DECLARE_NATIVE_FUNCTION(substring);
|
||||
JS_DECLARE_NATIVE_FUNCTION(substr);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(length_getter);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(trim);
|
||||
JS_DECLARE_NATIVE_FUNCTION(trim_start);
|
||||
JS_DECLARE_NATIVE_FUNCTION(trim_end);
|
||||
|
@ -63,6 +62,7 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(slice);
|
||||
JS_DECLARE_NATIVE_FUNCTION(split);
|
||||
JS_DECLARE_NATIVE_FUNCTION(last_index_of);
|
||||
JS_DECLARE_NATIVE_FUNCTION(at);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020-2021, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -39,8 +39,11 @@ void TypedArrayPrototype::initialize(GlobalObject& object)
|
|||
{
|
||||
auto& vm = this->vm();
|
||||
Object::initialize(object);
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
|
||||
// FIXME: This should be an accessor property
|
||||
define_native_property(vm.names.length, length_getter, {}, Attribute::Configurable);
|
||||
define_native_property(vm.names.length, length_getter, nullptr, Attribute::Configurable);
|
||||
define_native_function(vm.names.at, at, 1, attr);
|
||||
}
|
||||
|
||||
TypedArrayPrototype::~TypedArrayPrototype()
|
||||
|
@ -67,4 +70,27 @@ JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::length_getter)
|
|||
return Value(typed_array->array_length());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::at)
|
||||
{
|
||||
auto typed_array = typed_array_from(vm, global_object);
|
||||
if (!typed_array)
|
||||
return {};
|
||||
auto length = typed_array->array_length();
|
||||
auto relative_index = vm.argument(0).to_integer_or_infinity(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (Value(relative_index).is_infinity())
|
||||
return js_undefined();
|
||||
Checked<size_t> index { 0 };
|
||||
if (relative_index >= 0) {
|
||||
index += relative_index;
|
||||
} else {
|
||||
index += length;
|
||||
index -= -relative_index;
|
||||
}
|
||||
if (index.has_overflow() || index.value() >= length)
|
||||
return js_undefined();
|
||||
return typed_array->get(index.value());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* Copyright (c) 2020-2021, Linus Groh <mail@linusgroh.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -40,6 +40,8 @@ public:
|
|||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_GETTER(length_getter);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(at);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
test("basic functionality", () => {
|
||||
expect(Array.prototype.at).toHaveLength(1);
|
||||
|
||||
const array = ["a", "b", "c"];
|
||||
expect(array.at(0)).toBe("a");
|
||||
expect(array.at(1)).toBe("b");
|
||||
expect(array.at(2)).toBe("c");
|
||||
expect(array.at(3)).toBeUndefined();
|
||||
expect(array.at(Infinity)).toBeUndefined();
|
||||
expect(array.at(-1)).toBe("c");
|
||||
expect(array.at(-2)).toBe("b");
|
||||
expect(array.at(-3)).toBe("a");
|
||||
expect(array.at(-4)).toBeUndefined();
|
||||
expect(array.at(-Infinity)).toBeUndefined();
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
test("basic functionality", () => {
|
||||
expect(String.prototype.at).toHaveLength(1);
|
||||
|
||||
const string = "abc";
|
||||
expect(string.at(0)).toBe("a");
|
||||
expect(string.at(1)).toBe("b");
|
||||
expect(string.at(2)).toBe("c");
|
||||
expect(string.at(3)).toBeUndefined();
|
||||
expect(string.at(Infinity)).toBeUndefined();
|
||||
expect(string.at(-1)).toBe("c");
|
||||
expect(string.at(-2)).toBe("b");
|
||||
expect(string.at(-3)).toBe("a");
|
||||
expect(string.at(-4)).toBeUndefined();
|
||||
expect(string.at(-Infinity)).toBeUndefined();
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
// Update when more typed arrays get added
|
||||
const TYPED_ARRAYS = [
|
||||
Uint8Array,
|
||||
Uint16Array,
|
||||
Uint32Array,
|
||||
Int8Array,
|
||||
Int16Array,
|
||||
Int32Array,
|
||||
Float32Array,
|
||||
Float64Array,
|
||||
];
|
||||
|
||||
test("basic functionality", () => {
|
||||
TYPED_ARRAYS.forEach(T => {
|
||||
expect(T.prototype.at).toHaveLength(1);
|
||||
|
||||
const typedArray = new T(3);
|
||||
typedArray[0] = 1;
|
||||
typedArray[1] = 2;
|
||||
typedArray[2] = 3;
|
||||
|
||||
expect(typedArray.at(0)).toBe(1);
|
||||
expect(typedArray.at(1)).toBe(2);
|
||||
expect(typedArray.at(2)).toBe(3);
|
||||
expect(typedArray.at(3)).toBeUndefined();
|
||||
expect(typedArray.at(Infinity)).toBeUndefined();
|
||||
expect(typedArray.at(-1)).toBe(3);
|
||||
expect(typedArray.at(-2)).toBe(2);
|
||||
expect(typedArray.at(-3)).toBe(1);
|
||||
expect(typedArray.at(-4)).toBeUndefined();
|
||||
expect(typedArray.at(-Infinity)).toBeUndefined();
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue