summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-06-09 00:14:08 +0300
committerLinus Groh <mail@linusgroh.de>2021-06-09 11:48:04 +0100
commit0b0f1eda059615bd8d16daa9261239463a1554ec (patch)
tree01ba201a90ba5a73b0cfe2c282cc3b5bc6c3378b /Userland/Libraries
parent670be04c816b978e6308e18e8b18a0f784bf577c (diff)
downloadserenity-0b0f1eda059615bd8d16daa9261239463a1554ec.zip
LibJS: Add most of the Set.prototype methods
Specifically all aside from "values" and "entries" which require an implementation of the SetIterator object.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/SetPrototype.cpp62
-rw-r--r--Userland/Libraries/LibJS/Runtime/SetPrototype.h6
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.js5
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js10
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js8
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js10
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js48
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js13
9 files changed, 164 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
index 06a3e77015..52dc0ef420 100644
--- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
+++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
@@ -44,6 +44,7 @@ namespace JS {
P(abs) \
P(acos) \
P(acosh) \
+ P(add) \
P(all) \
P(allSettled) \
P(anchor) \
@@ -290,6 +291,7 @@ namespace JS {
struct CommonPropertyNames {
FlyString catch_ { "catch" };
+ FlyString delete_ { "delete" };
FlyString for_ { "for" };
#define __ENUMERATE(x) FlyString x { #x };
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
diff --git a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp
index e2cc0c7a5d..bfd842c1fe 100644
--- a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp
@@ -20,6 +20,12 @@ void SetPrototype::initialize(GlobalObject& global_object)
Set::initialize(global_object);
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_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)
{
auto* set = typed_this(vm, global_object);
diff --git a/Userland/Libraries/LibJS/Runtime/SetPrototype.h b/Userland/Libraries/LibJS/Runtime/SetPrototype.h
index 55e7e88035..a7908c2317 100644
--- a/Userland/Libraries/LibJS/Runtime/SetPrototype.h
+++ b/Userland/Libraries/LibJS/Runtime/SetPrototype.h
@@ -19,6 +19,12 @@ public:
virtual ~SetPrototype() override;
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);
};
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js
index 2216354feb..034f1bfe17 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js
@@ -27,5 +27,10 @@ describe("normal behavior", () => {
var a = new Set([0, 1, 2]);
expect(a instanceof Set).toBeTrue();
expect(a).toHaveSize(3);
+ var seen = [false, false, false];
+ a.forEach(x => {
+ seen[x] = true;
+ });
+ expect(seen[0] && seen[1] && seen[2]);
});
});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js
new file mode 100644
index 0000000000..e4dbb3dc72
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js
@@ -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);
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js
new file mode 100644
index 0000000000..956acc50fc
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js
@@ -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);
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js
new file mode 100644
index 0000000000..d1775c9d73
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js
@@ -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);
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js
new file mode 100644
index 0000000000..ab677dcd2a
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js
@@ -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);
+ });
+ });
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js
new file mode 100644
index 0000000000..3a797d025d
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js
@@ -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();
+});