mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03:00
LibJS: Create a class to provide common methods for object prototypes
Almost every JS prototype class defines a static "typed_this" helper to return the current "this" value as the analogous object type. This adds a PrototypeObject class to be inserted between the prototype object and the base Object class to define these methods on the prototype's behalf. Note that the generated "display_name" method must be defined static because the callers of typed_this are also static.
This commit is contained in:
parent
d38d03ce28
commit
1078d5e58a
Notes:
sideshowbarker
2024-07-18 04:13:53 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/1078d5e58ac Pull-request: https://github.com/SerenityOS/serenity/pull/9973 Reviewed-by: https://github.com/linusg ✅
81
Userland/Libraries/LibJS/Runtime/PrototypeObject.h
Normal file
81
Userland/Libraries/LibJS/Runtime/PrototypeObject.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
#define JS_PROTOTYPE_OBJECT(prototype_class, object_class, display_name_) \
|
||||
using Prototype = PrototypeObject<prototype_class, object_class>; \
|
||||
JS_OBJECT(prototype_class, Prototype) \
|
||||
static constexpr StringView display_name() { return #display_name_##sv; }
|
||||
|
||||
template<typename PrototypeType, typename ObjectType>
|
||||
class PrototypeObject : public Object {
|
||||
JS_OBJECT(PrototypeObject, Object);
|
||||
|
||||
public:
|
||||
virtual ~PrototypeObject() override = default;
|
||||
|
||||
static Object* this_object(GlobalObject& global_object)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
auto this_value = vm.this_value(global_object);
|
||||
|
||||
if (!this_value.is_object()) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, this_value);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &this_value.as_object();
|
||||
}
|
||||
|
||||
// Use typed_this_object() when the spec coerces |this| value to an object.
|
||||
static ObjectType* typed_this_object(GlobalObject& global_object)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return nullptr;
|
||||
|
||||
if (!is<ObjectType>(this_object)) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObjectOfType, PrototypeType::display_name());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<ObjectType*>(this_object);
|
||||
}
|
||||
|
||||
// Use typed_this_value() when the spec does not coerce |this| value to an object.
|
||||
static ObjectType* typed_this_value(GlobalObject& global_object)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
auto this_value = vm.this_value(global_object);
|
||||
|
||||
if (!this_value.is_object() || !is<ObjectType>(this_value.as_object())) {
|
||||
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObjectOfType, PrototypeType::display_name());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<ObjectType*>(&this_value.as_object());
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit PrototypeObject(Object& prototype)
|
||||
: Object(prototype)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user