From 7f6d3818a2e296ccd50c493c97a156152dbbb0db Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sat, 12 Jun 2021 01:41:07 +0300 Subject: [PATCH] LibJS: Add the Object::define_native_accessor method This is very similar to Object::define_native_property, but here the native functions are exported as standalone JS getter and setter functions, instead of being transparently called by interactions with the property. --- Userland/Libraries/LibJS/Runtime/Object.cpp | 34 +++++++++++++++++++++ Userland/Libraries/LibJS/Runtime/Object.h | 1 + 2 files changed, 35 insertions(+) diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 7935cbf358..29df7bf2c3 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -543,6 +543,40 @@ bool Object::define_property(const PropertyName& property_name, Value value, Pro return put_own_property(property_name.to_string_or_symbol(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions); } +bool Object::define_native_accessor(const StringOrSymbol& property_name, AK::Function getter, AK::Function setter, PropertyAttributes attribute) +{ + auto& vm = this->vm(); + String formatted_property_name; + if (property_name.is_string()) { + formatted_property_name = property_name.as_string(); + } else { + formatted_property_name = String::formatted("[{}]", property_name.as_symbol()->description()); + } + Function* getter_function = nullptr; + if (getter) { + auto name = String::formatted("get {}", formatted_property_name); + getter_function = NativeFunction::create(global_object(), name, move(getter)); + getter_function->define_property_without_transition(vm.names.length, Value(0), Attribute::Configurable); + if (vm.exception()) + return {}; + getter_function->define_property_without_transition(vm.names.name, js_string(vm.heap(), name), Attribute::Configurable); + if (vm.exception()) + return {}; + } + Function* setter_function = nullptr; + if (setter) { + auto name = String::formatted("set {}", formatted_property_name); + setter_function = NativeFunction::create(global_object(), name, move(setter)); + setter_function->define_property_without_transition(vm.names.length, Value(1), Attribute::Configurable); + if (vm.exception()) + return {}; + setter_function->define_property_without_transition(vm.names.name, js_string(vm.heap(), name), Attribute::Configurable); + if (vm.exception()) + return {}; + } + return define_accessor(property_name, getter_function, setter_function, attribute); +} + bool Object::define_accessor(const PropertyName& property_name, Function* getter, Function* setter, PropertyAttributes attributes, bool throw_exceptions) { VERIFY(property_name.is_valid()); diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index fa40ef18d9..e69328b969 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -95,6 +95,7 @@ public: bool define_native_function(const StringOrSymbol& property_name, AK::Function, i32 length = 0, PropertyAttributes attributes = default_attributes); bool define_native_property(const StringOrSymbol& property_name, AK::Function getter, AK::Function setter, PropertyAttributes attributes = default_attributes); + bool define_native_accessor(StringOrSymbol const& property_name, AK::Function getter, AK::Function setter, PropertyAttributes attributes = default_attributes); void define_properties(Value properties);