mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:57:45 +00:00
LibJS: Add most of the Set.prototype methods
Specifically all aside from "values" and "entries" which require an implementation of the SetIterator object.
This commit is contained in:
parent
670be04c81
commit
0b0f1eda05
9 changed files with 164 additions and 0 deletions
|
@ -44,6 +44,7 @@ namespace JS {
|
||||||
P(abs) \
|
P(abs) \
|
||||||
P(acos) \
|
P(acos) \
|
||||||
P(acosh) \
|
P(acosh) \
|
||||||
|
P(add) \
|
||||||
P(all) \
|
P(all) \
|
||||||
P(allSettled) \
|
P(allSettled) \
|
||||||
P(anchor) \
|
P(anchor) \
|
||||||
|
@ -290,6 +291,7 @@ namespace JS {
|
||||||
|
|
||||||
struct CommonPropertyNames {
|
struct CommonPropertyNames {
|
||||||
FlyString catch_ { "catch" };
|
FlyString catch_ { "catch" };
|
||||||
|
FlyString delete_ { "delete" };
|
||||||
FlyString for_ { "for" };
|
FlyString for_ { "for" };
|
||||||
#define __ENUMERATE(x) FlyString x { #x };
|
#define __ENUMERATE(x) FlyString x { #x };
|
||||||
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
|
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
|
||||||
|
|
|
@ -20,6 +20,12 @@ void SetPrototype::initialize(GlobalObject& global_object)
|
||||||
Set::initialize(global_object);
|
Set::initialize(global_object);
|
||||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
|
|
||||||
|
define_native_function(vm.names.add, add, 1, attr);
|
||||||
|
define_native_function(vm.names.clear, clear, 0, attr);
|
||||||
|
define_native_function(vm.names.delete_, delete_, 1, attr);
|
||||||
|
define_native_function(vm.names.forEach, for_each, 1, attr);
|
||||||
|
define_native_function(vm.names.has, has, 1, attr);
|
||||||
|
|
||||||
define_native_property(vm.names.size, size_getter, {}, attr);
|
define_native_property(vm.names.size, size_getter, {}, attr);
|
||||||
|
|
||||||
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Set), Attribute::Configurable);
|
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Set), Attribute::Configurable);
|
||||||
|
@ -29,6 +35,62 @@ SetPrototype::~SetPrototype()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::add)
|
||||||
|
{
|
||||||
|
auto* set = typed_this(vm, global_object);
|
||||||
|
if (!set)
|
||||||
|
return {};
|
||||||
|
auto value = vm.argument(0);
|
||||||
|
if (value.is_negative_zero())
|
||||||
|
value = Value(0);
|
||||||
|
set->values().set(value, AK::HashSetExistingEntryBehavior::Keep);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::clear)
|
||||||
|
{
|
||||||
|
auto* set = typed_this(vm, global_object);
|
||||||
|
if (!set)
|
||||||
|
return {};
|
||||||
|
set->values().clear();
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::delete_)
|
||||||
|
{
|
||||||
|
auto* set = typed_this(vm, global_object);
|
||||||
|
if (!set)
|
||||||
|
return {};
|
||||||
|
return Value(set->values().remove(vm.argument(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::for_each)
|
||||||
|
{
|
||||||
|
auto* set = typed_this(vm, global_object);
|
||||||
|
if (!set)
|
||||||
|
return {};
|
||||||
|
if (!vm.argument(0).is_function()) {
|
||||||
|
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, vm.argument(0).to_string_without_side_effects());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto this_value = vm.this_value(global_object);
|
||||||
|
for (auto& value : set->values()) {
|
||||||
|
(void)vm.call(vm.argument(0).as_function(), vm.argument(1), value, value, this_value);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(SetPrototype::has)
|
||||||
|
{
|
||||||
|
auto* set = typed_this(vm, global_object);
|
||||||
|
if (!set)
|
||||||
|
return {};
|
||||||
|
auto& values = set->values();
|
||||||
|
return Value(values.find(vm.argument(0)) != values.end());
|
||||||
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_GETTER(SetPrototype::size_getter)
|
JS_DEFINE_NATIVE_GETTER(SetPrototype::size_getter)
|
||||||
{
|
{
|
||||||
auto* set = typed_this(vm, global_object);
|
auto* set = typed_this(vm, global_object);
|
||||||
|
|
|
@ -19,6 +19,12 @@ public:
|
||||||
virtual ~SetPrototype() override;
|
virtual ~SetPrototype() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(add);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(clear);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(delete_);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(for_each);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(has);
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_GETTER(size_getter);
|
JS_DECLARE_NATIVE_GETTER(size_getter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,5 +27,10 @@ describe("normal behavior", () => {
|
||||||
var a = new Set([0, 1, 2]);
|
var a = new Set([0, 1, 2]);
|
||||||
expect(a instanceof Set).toBeTrue();
|
expect(a instanceof Set).toBeTrue();
|
||||||
expect(a).toHaveSize(3);
|
expect(a).toHaveSize(3);
|
||||||
|
var seen = [false, false, false];
|
||||||
|
a.forEach(x => {
|
||||||
|
seen[x] = true;
|
||||||
|
});
|
||||||
|
expect(seen[0] && seen[1] && seen[2]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
test("basic functionality", () => {
|
||||||
|
expect(Set.prototype.add).toHaveLength(1);
|
||||||
|
|
||||||
|
const set = new Set(["a", "b", "c"]);
|
||||||
|
expect(set).toHaveSize(3);
|
||||||
|
expect(set.add("d")).toBe(set);
|
||||||
|
expect(set).toHaveSize(4);
|
||||||
|
expect(set.add("a")).toBe(set);
|
||||||
|
expect(set).toHaveSize(4);
|
||||||
|
});
|
|
@ -0,0 +1,8 @@
|
||||||
|
test("basic functionality", () => {
|
||||||
|
expect(Set.prototype.clear).toHaveLength(0);
|
||||||
|
|
||||||
|
const set = new Set(["a", "b", "c"]);
|
||||||
|
expect(set).toHaveSize(3);
|
||||||
|
set.clear();
|
||||||
|
expect(set).toHaveSize(0);
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
test("basic functionality", () => {
|
||||||
|
expect(Set.prototype.delete).toHaveLength(1);
|
||||||
|
|
||||||
|
const set = new Set(["a", "b", "c"]);
|
||||||
|
expect(set).toHaveSize(3);
|
||||||
|
expect(set.delete("b")).toBeTrue();
|
||||||
|
expect(set).toHaveSize(2);
|
||||||
|
expect(set.delete("b")).toBeFalse();
|
||||||
|
expect(set).toHaveSize(2);
|
||||||
|
});
|
|
@ -0,0 +1,48 @@
|
||||||
|
test("length is 1", () => {
|
||||||
|
expect(Set.prototype.forEach).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("requires at least one argument", () => {
|
||||||
|
expect(() => {
|
||||||
|
new Set().forEach();
|
||||||
|
}).toThrowWithMessage(TypeError, "undefined is not a function");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("callback must be a function", () => {
|
||||||
|
expect(() => {
|
||||||
|
new Set().forEach(undefined);
|
||||||
|
}).toThrowWithMessage(TypeError, "undefined is not a function");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("normal behavior", () => {
|
||||||
|
test("never calls callback with empty set", () => {
|
||||||
|
var callbackCalled = 0;
|
||||||
|
expect(
|
||||||
|
new Set().forEach(() => {
|
||||||
|
callbackCalled++;
|
||||||
|
})
|
||||||
|
).toBeUndefined();
|
||||||
|
expect(callbackCalled).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("calls callback once for every item", () => {
|
||||||
|
var callbackCalled = 0;
|
||||||
|
expect(
|
||||||
|
new Set([1, 2, 3]).forEach(() => {
|
||||||
|
callbackCalled++;
|
||||||
|
})
|
||||||
|
).toBeUndefined();
|
||||||
|
expect(callbackCalled).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("callback receives value twice and set", () => {
|
||||||
|
var a = new Set([1, 2, 3]);
|
||||||
|
a.forEach((value1, value2, set) => {
|
||||||
|
expect(a.has(value1)).toBeTrue();
|
||||||
|
expect(value1).toBe(value2);
|
||||||
|
expect(set).toBe(a);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
test("length is 1", () => {
|
||||||
|
expect(Set.prototype.has).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("basic functionality", () => {
|
||||||
|
var set = new Set(["hello", "friends", 1, 2, false]);
|
||||||
|
|
||||||
|
expect(new Set().has()).toBeFalse();
|
||||||
|
expect(new Set([undefined]).has()).toBeTrue();
|
||||||
|
expect(set.has("hello")).toBeTrue();
|
||||||
|
expect(set.has(1)).toBeTrue();
|
||||||
|
expect(set.has("serenity")).toBeFalse();
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue