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

LibJS: Add the WeakSet built-in object

This commit is contained in:
Idan Horowitz 2021-06-09 19:23:04 +03:00 committed by Linus Groh
parent ee9fe288b2
commit 8b6beac5ce
10 changed files with 250 additions and 1 deletions

View file

@ -97,6 +97,9 @@ set(SOURCES
Runtime/TypedArrayPrototype.cpp Runtime/TypedArrayPrototype.cpp
Runtime/VM.cpp Runtime/VM.cpp
Runtime/Value.cpp Runtime/Value.cpp
Runtime/WeakSet.cpp
Runtime/WeakSetConstructor.cpp
Runtime/WeakSetPrototype.cpp
Runtime/WithScope.cpp Runtime/WithScope.cpp
SyntaxHighlighter.cpp SyntaxHighlighter.cpp
Token.cpp Token.cpp

View file

@ -39,7 +39,8 @@
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \ __JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \
__JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \ __JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \ __JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) __JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) \
__JS_ENUMERATE(WeakSet, weak_set, WeakSetPrototype, WeakSetConstructor, void)
#define JS_ENUMERATE_NATIVE_OBJECTS \ #define JS_ENUMERATE_NATIVE_OBJECTS \
JS_ENUMERATE_NATIVE_OBJECTS_EXCLUDING_TEMPLATES \ JS_ENUMERATE_NATIVE_OBJECTS_EXCLUDING_TEMPLATES \

View file

@ -60,6 +60,8 @@
#include <LibJS/Runtime/TypedArrayConstructor.h> #include <LibJS/Runtime/TypedArrayConstructor.h>
#include <LibJS/Runtime/TypedArrayPrototype.h> #include <LibJS/Runtime/TypedArrayPrototype.h>
#include <LibJS/Runtime/Value.h> #include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/WeakSetConstructor.h>
#include <LibJS/Runtime/WeakSetPrototype.h>
namespace JS { namespace JS {
@ -143,6 +145,7 @@ void GlobalObject::initialize_global_object()
add_constructor(vm.names.Set, m_set_constructor, m_set_prototype); add_constructor(vm.names.Set, m_set_constructor, m_set_prototype);
add_constructor(vm.names.String, m_string_constructor, m_string_prototype); add_constructor(vm.names.String, m_string_constructor, m_string_prototype);
add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype); add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype);
add_constructor(vm.names.WeakSet, m_weak_set_constructor, m_weak_set_prototype);
initialize_constructor(vm.names.TypedArray, m_typed_array_constructor, m_typed_array_prototype); initialize_constructor(vm.names.TypedArray, m_typed_array_constructor, m_typed_array_prototype);

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/WeakSet.h>
namespace JS {
WeakSet* WeakSet::create(GlobalObject& global_object)
{
return global_object.heap().allocate<WeakSet>(global_object, *global_object.weak_set_prototype());
}
WeakSet::WeakSet(Object& prototype)
: Object(prototype)
{
}
WeakSet::~WeakSet()
{
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/HashTable.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class WeakSet : public Object {
JS_OBJECT(WeakSet, Object);
public:
static WeakSet* create(GlobalObject&);
explicit WeakSet(Object& prototype);
virtual ~WeakSet() override;
HashTable<Object*> const& values() const { return m_values; };
HashTable<Object*>& values() { return m_values; };
private:
HashTable<Object*> m_values;
};
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/WeakSet.h>
#include <LibJS/Runtime/WeakSetConstructor.h>
namespace JS {
WeakSetConstructor::WeakSetConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.WeakSet, *global_object.function_prototype())
{
}
void WeakSetConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.weak_set_prototype(), 0);
define_property(vm.names.length, Value(0), Attribute::Configurable);
}
WeakSetConstructor::~WeakSetConstructor()
{
}
Value WeakSetConstructor::call()
{
auto& vm = this->vm();
vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, vm.names.WeakSet);
return {};
}
Value WeakSetConstructor::construct(Function&)
{
auto& vm = this->vm();
if (vm.argument(0).is_nullish())
return WeakSet::create(global_object());
auto* weak_set = WeakSet::create(global_object());
auto adder = weak_set->get(vm.names.add);
if (vm.exception())
return {};
if (!adder.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'add' property of WeakSet");
return {};
}
get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) {
if (vm.exception())
return IterationDecision::Break;
(void)vm.call(adder.as_function(), Value(weak_set), iterator_value);
return vm.exception() ? IterationDecision::Break : IterationDecision::Continue;
});
if (vm.exception())
return {};
return weak_set;
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/NativeFunction.h>
namespace JS {
class WeakSetConstructor final : public NativeFunction {
JS_OBJECT(WeakSetConstructor, NativeFunction);
public:
explicit WeakSetConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~WeakSetConstructor() override;
virtual Value call() override;
virtual Value construct(Function&) override;
private:
virtual bool has_constructor() const override { return true; }
};
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/HashTable.h>
#include <LibJS/Runtime/WeakSetPrototype.h>
namespace JS {
WeakSetPrototype::WeakSetPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void WeakSetPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakSet), Attribute::Configurable);
}
WeakSetPrototype::~WeakSetPrototype()
{
}
WeakSet* WeakSetPrototype::typed_this(VM& vm, GlobalObject& global_object)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!is<WeakSet>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "WeakSet");
return nullptr;
}
return static_cast<WeakSet*>(this_object);
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/WeakSet.h>
namespace JS {
class WeakSetPrototype final : public Object {
JS_OBJECT(WeakSetPrototype, Object);
public:
WeakSetPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~WeakSetPrototype() override;
private:
static WeakSet* typed_this(VM&, GlobalObject&);
}

View file

@ -0,0 +1,30 @@
test("constructor properties", () => {
expect(WeakSet).toHaveLength(0);
expect(WeakSet.name).toBe("WeakSet");
});
describe("errors", () => {
test("invalid array iterators", () => {
[-100, Infinity, NaN, {}, 152n].forEach(value => {
expect(() => {
new WeakSet(value);
}).toThrowWithMessage(TypeError, "is not iterable");
});
});
test("called without new", () => {
expect(() => {
WeakSet();
}).toThrowWithMessage(TypeError, "WeakSet constructor must be called with 'new'");
});
});
describe("normal behavior", () => {
test("typeof", () => {
expect(typeof new WeakSet()).toBe("object");
});
test("constructor with single array argument", () => {
var a = new WeakSet([{ a: 1 }, { a: 2 }, { a: 3 }]);
expect(a instanceof WeakSet).toBeTrue();
});
});