From e5da1cc5660f6a284b9b21c7bcb1a547fac1cabe Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 10 Apr 2020 12:48:31 +0200 Subject: [PATCH] LibJS: Throw real TypeError, ReferenceError, etc objects Instead of just throwing Error objects with a name string, we now throw the real Error subclass types. :^) --- Libraries/LibJS/AST.cpp | 8 ++++---- Libraries/LibJS/Heap/Heap.cpp | 2 +- Libraries/LibJS/Runtime/Array.cpp | 2 +- Libraries/LibJS/Runtime/ArrayPrototype.cpp | 2 +- Libraries/LibJS/Runtime/BooleanPrototype.cpp | 4 ++-- Libraries/LibJS/Runtime/DatePrototype.cpp | 2 +- Libraries/LibJS/Runtime/ErrorPrototype.cpp | 11 +++++++---- Libraries/LibJS/Runtime/FunctionPrototype.cpp | 8 ++++---- Libraries/LibJS/Runtime/Object.cpp | 2 +- Libraries/LibJS/Runtime/ObjectConstructor.cpp | 10 +++++----- Libraries/LibJS/Runtime/ScriptFunction.cpp | 2 +- Libraries/LibJS/Runtime/StringPrototype.cpp | 6 +++--- Libraries/LibJS/Runtime/Value.cpp | 2 +- 13 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 07b97edd071..86f4dc0bc02 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -97,11 +97,11 @@ Value CallExpression::execute(Interpreter& interpreter) const || !callee.as_object().is_function() || (callee.as_object().is_native_function() && !static_cast(callee.as_object()).has_constructor())) - return interpreter.throw_exception("TypeError", String::format("%s is not a constructor", callee.to_string().characters())); + return interpreter.throw_exception(String::format("%s is not a constructor", callee.to_string().characters())); } if (!callee.is_object() || !callee.as_object().is_function()) - return interpreter.throw_exception("TypeError", String::format("%s is not a function", callee.to_string().characters())); + return interpreter.throw_exception(String::format("%s is not a function", callee.to_string().characters())); auto& function = static_cast(callee.as_object()); @@ -651,7 +651,7 @@ Value Identifier::execute(Interpreter& interpreter) const { auto variable = interpreter.get_variable(string()); if (!variable.has_value()) - return interpreter.throw_exception("ReferenceError", String::format("'%s' not known", string().characters())); + return interpreter.throw_exception(String::format("'%s' not known", string().characters())); return variable.value(); } @@ -711,7 +711,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const object->put(property_name, rhs_result); } } else { - return interpreter.throw_exception("ReferenceError", "Invalid left-hand side in assignment"); + return interpreter.throw_exception("Invalid left-hand side in assignment"); } return rhs_result; diff --git a/Libraries/LibJS/Heap/Heap.cpp b/Libraries/LibJS/Heap/Heap.cpp index 3dd3902ca59..ca98e33b910 100644 --- a/Libraries/LibJS/Heap/Heap.cpp +++ b/Libraries/LibJS/Heap/Heap.cpp @@ -41,7 +41,7 @@ #endif #ifdef __serenity__ -#define HEAP_DEBUG +//#define HEAP_DEBUG #endif namespace JS { diff --git a/Libraries/LibJS/Runtime/Array.cpp b/Libraries/LibJS/Runtime/Array.cpp index e779630c2cb..57589264bb9 100644 --- a/Libraries/LibJS/Runtime/Array.cpp +++ b/Libraries/LibJS/Runtime/Array.cpp @@ -66,7 +66,7 @@ Value Array::length_getter(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_array()) - return interpreter.throw_exception("TypeError", "Not an array"); + return interpreter.throw_exception("Not an array"); return Value(static_cast(this_object)->length()); } diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index 56b007158cc..26fefa99e30 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -54,7 +54,7 @@ static Array* array_from(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_array()) { - interpreter.throw_exception("TypeError", "Not an Array"); + interpreter.throw_exception("Not an Array"); return nullptr; } return static_cast(this_object); diff --git a/Libraries/LibJS/Runtime/BooleanPrototype.cpp b/Libraries/LibJS/Runtime/BooleanPrototype.cpp index a63ab9a1109..1bae1f8741b 100644 --- a/Libraries/LibJS/Runtime/BooleanPrototype.cpp +++ b/Libraries/LibJS/Runtime/BooleanPrototype.cpp @@ -47,7 +47,7 @@ Value BooleanPrototype::to_string(Interpreter& interpreter) return js_string(interpreter.heap(), this_object.as_bool() ? "true" : "false"); } if (!this_object.is_object() || !this_object.as_object().is_boolean()) { - interpreter.throw_exception("TypeError", "Not a Boolean"); + interpreter.throw_exception("Not a Boolean"); return {}; } @@ -62,7 +62,7 @@ Value BooleanPrototype::value_of(Interpreter& interpreter) return this_object; } if (!this_object.is_object() || !this_object.as_object().is_boolean()) { - interpreter.throw_exception("TypeError", "Not a Boolean"); + interpreter.throw_exception("Not a Boolean"); return {}; } diff --git a/Libraries/LibJS/Runtime/DatePrototype.cpp b/Libraries/LibJS/Runtime/DatePrototype.cpp index 5e75843e11b..9c827a0de3e 100644 --- a/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -41,7 +41,7 @@ static Date* this_date_from_interpreter(Interpreter& interpreter) if (!this_object) return nullptr; if (!this_object->is_date()) { - interpreter.throw_exception("TypeError", "object must be of type Date"); + interpreter.throw_exception("object must be of type Date"); return nullptr; } return static_cast(this_object); diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp index 3e9c923282c..f35d25c4a35 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -51,7 +51,7 @@ Value ErrorPrototype::name_getter(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_error()) - return interpreter.throw_exception("TypeError", "Not an Error object"); + return interpreter.throw_exception("Not an Error object"); return js_string(interpreter, static_cast(this_object)->name()); } @@ -61,14 +61,14 @@ Value ErrorPrototype::message_getter(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_error()) - return interpreter.throw_exception("TypeError", "Not an Error object"); + return interpreter.throw_exception("Not an Error object"); return js_string(interpreter, static_cast(this_object)->message()); } Value ErrorPrototype::to_string(Interpreter& interpreter) { if (!interpreter.this_value().is_object()) - return interpreter.throw_exception("TypeError", "Not an object"); + return interpreter.throw_exception("Not an object"); auto& this_object = interpreter.this_value().as_object(); String name = "Error"; @@ -89,7 +89,10 @@ Value ErrorPrototype::to_string(Interpreter& interpreter) } #define DEFINE_ERROR_SUBCLASS_PROTOTYPE(TitleCase, snake_case) \ - TitleCase::TitleCase() {} \ + TitleCase::TitleCase() \ + { \ + set_prototype(interpreter().error_prototype()); \ + } \ TitleCase::~TitleCase() {} \ const char* TitleCase::class_name() const { return #TitleCase; } diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index a0a976181d9..bfe63ec9f6b 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -54,14 +54,14 @@ Value FunctionPrototype::apply(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_function()) - return interpreter.throw_exception("TypeError", "Not a Function object"); + return interpreter.throw_exception("Not a Function object"); auto function = static_cast(this_object); auto this_arg = interpreter.argument(0); auto arg_array = interpreter.argument(1); if (arg_array.is_null() || arg_array.is_undefined()) return interpreter.call(function, this_arg); if (!arg_array.is_object()) - return interpreter.throw_exception("TypeError", "argument array must be an object"); + return interpreter.throw_exception("argument array must be an object"); size_t length = 0; auto length_property = arg_array.as_object().get("length"); if (length_property.has_value()) @@ -87,7 +87,7 @@ Value FunctionPrototype::call(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_function()) - return interpreter.throw_exception("TypeError", "Not a Function object"); + return interpreter.throw_exception("Not a Function object"); auto function = static_cast(this_object); auto this_arg = interpreter.argument(0); Vector arguments; @@ -104,7 +104,7 @@ Value FunctionPrototype::to_string(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_function()) - return interpreter.throw_exception("TypeError", "Not a Function object"); + return interpreter.throw_exception("Not a Function object"); // FIXME: Functions should be able to know their name, if any if (this_object->is_native_function()) { auto function_source = String::format("function () {\n [%s]\n}", this_object->class_name()); diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 15456d79c7b..9382f4d8786 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -110,7 +110,7 @@ void Object::put_own_property(Object& this_object, const FlyString& property_nam if (mode == PutOwnPropertyMode::DefineProperty && !(metadata.value().attributes & Attribute::Configurable) && attributes != metadata.value().attributes) { dbg() << "Disallow reconfig of non-configurable property"; - interpreter().throw_exception("TypeError", String::format("Cannot redefine property '%s'", property_name.characters())); + interpreter().throw_exception(String::format("Cannot redefine property '%s'", property_name.characters())); return; } diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 0ed34c26b54..ad00184707f 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -101,9 +101,9 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter) Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter) { if (interpreter.argument_count() < 2) - return interpreter.throw_exception("TypeError", "Object.getOwnPropertyDescriptor() needs 2 arguments"); + return interpreter.throw_exception("Object.getOwnPropertyDescriptor() needs 2 arguments"); if (!interpreter.argument(0).is_object()) - return interpreter.throw_exception("TypeError", "Object argument is not an object"); + return interpreter.throw_exception("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()) @@ -119,11 +119,11 @@ Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter) Value ObjectConstructor::define_property(Interpreter& interpreter) { if (interpreter.argument_count() < 3) - return interpreter.throw_exception("TypeError", "Object.defineProperty() needs 3 arguments"); + return interpreter.throw_exception("Object.defineProperty() needs 3 arguments"); if (!interpreter.argument(0).is_object()) - return interpreter.throw_exception("TypeError", "Object argument is not an object"); + return interpreter.throw_exception("Object argument is not an object"); if (!interpreter.argument(2).is_object()) - return interpreter.throw_exception("TypeError", "Descriptor argument is not an object"); + return interpreter.throw_exception("Descriptor argument is not an object"); auto& object = interpreter.argument(0).as_object(); auto& descriptor = interpreter.argument(2).as_object(); diff --git a/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Libraries/LibJS/Runtime/ScriptFunction.cpp index 8a30d7898ba..2f196bc2e08 100644 --- a/Libraries/LibJS/Runtime/ScriptFunction.cpp +++ b/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -70,7 +70,7 @@ Value ScriptFunction::length_getter(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_function()) - return interpreter.throw_exception("TypeError", "Not a function"); + return interpreter.throw_exception("Not a function"); return Value(static_cast(static_cast(this_object)->parameters().size())); } diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index fc0fbf344e9..4eb2469f166 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -120,7 +120,7 @@ Value StringPrototype::index_of(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_string_object()) - return interpreter.throw_exception("TypeError", "Not a String object"); + return interpreter.throw_exception("Not a String object"); Value needle_value = js_undefined(); if (interpreter.argument_count() >= 1) @@ -141,7 +141,7 @@ static StringObject* string_object_from(Interpreter& interpreter) if (!this_object) return nullptr; if (!this_object->is_string_object()) { - interpreter.throw_exception("TypeError", "Not a String object"); + interpreter.throw_exception("Not a String object"); return nullptr; } return static_cast(this_object); @@ -169,7 +169,7 @@ Value StringPrototype::length_getter(Interpreter& interpreter) if (!this_object) return {}; if (!this_object->is_string_object()) - return interpreter.throw_exception("TypeError", "Not a String object"); + return interpreter.throw_exception("Not a String object"); return Value((i32) static_cast(this_object)->primitive_string()->string().length()); } diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 889e4e18f68..90af4d1a26c 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -115,7 +115,7 @@ Object* Value::to_object(Heap& heap) const return heap.allocate(m_value.as_bool); if (is_null() || is_undefined()) { - heap.interpreter().throw_exception("TypeError", "ToObject on null or undefined."); + heap.interpreter().throw_exception("ToObject on null or undefined."); return nullptr; }