mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 08:48:11 +00:00
LibJS: Add Object.defineProperty() and start caring about attributes
We now care (a little bit) about the "configurable" and "writable" property attributes. Property attributes are stored together with the property name in the Shape object. Forward transitions are not attribute-savvy and will cause poor Shape reuse in the case of multiple same-name properties with different attributes. Oh, and this patch also adds Object.getOwnPropertyDescriptor() :^)
This commit is contained in:
parent
1570e67881
commit
e6d920d87d
7 changed files with 121 additions and 16 deletions
|
@ -28,6 +28,7 @@
|
|||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/ObjectConstructor.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
|
||||
|
@ -37,6 +38,8 @@ ObjectConstructor::ObjectConstructor()
|
|||
{
|
||||
put("prototype", interpreter().object_prototype());
|
||||
|
||||
put_native_function("defineProperty", define_property, 3);
|
||||
put_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2);
|
||||
put_native_function("getOwnPropertyNames", get_own_property_names, 1);
|
||||
put_native_function("getPrototypeOf", get_prototype_of, 1);
|
||||
put_native_function("setPrototypeOf", set_prototype_of, 2);
|
||||
|
@ -88,8 +91,6 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
|
|||
{
|
||||
if (interpreter.argument_count() < 2)
|
||||
return {};
|
||||
if (!interpreter.argument(0).is_object())
|
||||
return {};
|
||||
auto* object = interpreter.argument(0).to_object(interpreter.heap());
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
|
@ -97,4 +98,45 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
|
|||
return {};
|
||||
}
|
||||
|
||||
Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
|
||||
{
|
||||
if (interpreter.argument_count() < 2)
|
||||
return interpreter.throw_exception<Error>("TypeError", "Object.getOwnPropertyDescriptor() needs 2 arguments");
|
||||
if (!interpreter.argument(0).is_object())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Object argument is not an object");
|
||||
auto& object = interpreter.argument(0).as_object();
|
||||
auto metadata = object.shape().lookup(interpreter.argument(1).to_string());
|
||||
if (!metadata.has_value())
|
||||
return js_undefined();
|
||||
auto* descriptor = interpreter.heap().allocate<Object>();
|
||||
descriptor->put("configurable", Value(!!(metadata.value().attributes & Attribute::Configurable)));
|
||||
descriptor->put("enumerable", Value(!!(metadata.value().attributes & Attribute::Enumerable)));
|
||||
descriptor->put("writable", Value(!!(metadata.value().attributes & Attribute::Writable)));
|
||||
descriptor->put("value", object.get(interpreter.argument(1).to_string()).value_or(js_undefined()));
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
Value ObjectConstructor::define_property(Interpreter& interpreter)
|
||||
{
|
||||
if (interpreter.argument_count() < 3)
|
||||
return interpreter.throw_exception<Error>("TypeError", "Object.defineProperty() needs 3 arguments");
|
||||
if (!interpreter.argument(0).is_object())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Object argument is not an object");
|
||||
if (!interpreter.argument(2).is_object())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Descriptor argument is not an object");
|
||||
auto& object = interpreter.argument(0).as_object();
|
||||
auto& descriptor = interpreter.argument(2).as_object();
|
||||
|
||||
Value value = descriptor.get("value").value_or(js_undefined());
|
||||
u8 configurable = descriptor.get("configurable").value_or(Value(false)).to_boolean() * Attribute::Configurable;
|
||||
u8 enumerable = descriptor.get("enumerable").value_or(Value(false)).to_boolean() * Attribute::Enumerable;
|
||||
u8 writable = descriptor.get("writable").value_or(Value(false)).to_boolean() * Attribute::Writable;
|
||||
u8 attributes = configurable | enumerable | writable;
|
||||
|
||||
dbg() << "Defining new property " << interpreter.argument(1).to_string() << " with descriptor { " << configurable << ", " << enumerable << ", " << writable << ", attributes=" << attributes << " }";
|
||||
|
||||
object.put_own_property(object, interpreter.argument(1).to_string(), attributes, value, PutOwnPropertyMode::DefineProperty);
|
||||
return &object;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue