From 2a65db7c1253e4a070e8ac101faa2404dc7af99e Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Mon, 13 Apr 2020 02:19:53 -0700 Subject: [PATCH] LibJS: Implement Error.prototype.name setter (#1776) The MDN example for creating a custom error type in javascript uses: function CustomError(foo, message, fileName, lineNumber) { var instance = new Error(message, fileName, lineNumber); instance.name = 'CustomError'; instance.foo = foo; Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); return instance; } The name property on the Error prototype needs to be settable for this to work properly. --- Libraries/LibJS/Runtime/Error.h | 2 ++ Libraries/LibJS/Runtime/ErrorPrototype.cpp | 15 ++++++++++++++- Libraries/LibJS/Runtime/ErrorPrototype.h | 2 ++ Libraries/LibJS/Tests/Error.prototype.name.js | 12 ++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Libraries/LibJS/Tests/Error.prototype.name.js diff --git a/Libraries/LibJS/Runtime/Error.h b/Libraries/LibJS/Runtime/Error.h index 76615b4b9e9..ac15e7bbbd4 100644 --- a/Libraries/LibJS/Runtime/Error.h +++ b/Libraries/LibJS/Runtime/Error.h @@ -39,6 +39,8 @@ public: const FlyString& name() const { return m_name; } const String& message() const { return m_message; } + void set_name(const FlyString& name) { m_name = name; } + private: virtual bool is_error() const final { return true; } virtual const char* class_name() const override { return "Error"; } diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp index 1e193a567bd..0251fe779f6 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -36,7 +36,7 @@ namespace JS { ErrorPrototype::ErrorPrototype() { - put_native_property("name", name_getter, nullptr); + put_native_property("name", name_getter, name_setter); put_native_property("message", message_getter, nullptr); put_native_function("toString", to_string); } @@ -55,6 +55,19 @@ Value ErrorPrototype::name_getter(Interpreter& interpreter) return js_string(interpreter, static_cast(this_object)->name()); } +void ErrorPrototype::name_setter(Interpreter& interpreter, Value value) +{ + auto* this_object = interpreter.this_value().to_object(interpreter.heap()); + if (!this_object) + return; + if (!this_object->is_error()) { + interpreter.throw_exception("Not an Error object"); + return; + } + auto name = FlyString(value.to_string()); + static_cast(this_object)->set_name(name); +} + Value ErrorPrototype::message_getter(Interpreter& interpreter) { auto* this_object = interpreter.this_value().to_object(interpreter.heap()); diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.h b/Libraries/LibJS/Runtime/ErrorPrototype.h index ffc13a83459..a851407fee6 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.h +++ b/Libraries/LibJS/Runtime/ErrorPrototype.h @@ -41,6 +41,8 @@ private: static Value to_string(Interpreter&); static Value name_getter(Interpreter&); + static void name_setter(Interpreter&, Value); + static Value message_getter(Interpreter&); }; diff --git a/Libraries/LibJS/Tests/Error.prototype.name.js b/Libraries/LibJS/Tests/Error.prototype.name.js new file mode 100644 index 00000000000..991cb92aeee --- /dev/null +++ b/Libraries/LibJS/Tests/Error.prototype.name.js @@ -0,0 +1,12 @@ +try { + var changedInstance = new Error(""); + changedInstance.name = 'NewCustomError'; + assert(changedInstance.name === "NewCustomError"); + + var normalInstance = new Error(""); + assert(normalInstance.name === "Error"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e.message); +}