mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
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. :^)
This commit is contained in:
parent
58ab76269c
commit
e5da1cc566
Notes:
sideshowbarker
2024-07-19 07:44:57 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e5da1cc5660
13 changed files with 32 additions and 29 deletions
|
@ -97,11 +97,11 @@ Value CallExpression::execute(Interpreter& interpreter) const
|
||||||
|| !callee.as_object().is_function()
|
|| !callee.as_object().is_function()
|
||||||
|| (callee.as_object().is_native_function()
|
|| (callee.as_object().is_native_function()
|
||||||
&& !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))
|
&& !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))
|
||||||
return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a constructor", callee.to_string().characters()));
|
return interpreter.throw_exception<TypeError>(String::format("%s is not a constructor", callee.to_string().characters()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callee.is_object() || !callee.as_object().is_function())
|
if (!callee.is_object() || !callee.as_object().is_function())
|
||||||
return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a function", callee.to_string().characters()));
|
return interpreter.throw_exception<TypeError>(String::format("%s is not a function", callee.to_string().characters()));
|
||||||
|
|
||||||
auto& function = static_cast<Function&>(callee.as_object());
|
auto& function = static_cast<Function&>(callee.as_object());
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ Value Identifier::execute(Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto variable = interpreter.get_variable(string());
|
auto variable = interpreter.get_variable(string());
|
||||||
if (!variable.has_value())
|
if (!variable.has_value())
|
||||||
return interpreter.throw_exception<Error>("ReferenceError", String::format("'%s' not known", string().characters()));
|
return interpreter.throw_exception<ReferenceError>(String::format("'%s' not known", string().characters()));
|
||||||
return variable.value();
|
return variable.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,7 +711,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const
|
||||||
object->put(property_name, rhs_result);
|
object->put(property_name, rhs_result);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return interpreter.throw_exception<Error>("ReferenceError", "Invalid left-hand side in assignment");
|
return interpreter.throw_exception<ReferenceError>("Invalid left-hand side in assignment");
|
||||||
}
|
}
|
||||||
|
|
||||||
return rhs_result;
|
return rhs_result;
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __serenity__
|
#ifdef __serenity__
|
||||||
#define HEAP_DEBUG
|
//#define HEAP_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
|
@ -66,7 +66,7 @@ Value Array::length_getter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_array())
|
if (!this_object->is_array())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not an array");
|
return interpreter.throw_exception<TypeError>("Not an array");
|
||||||
return Value(static_cast<const Array*>(this_object)->length());
|
return Value(static_cast<const Array*>(this_object)->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ static Array* array_from(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_array()) {
|
if (!this_object->is_array()) {
|
||||||
interpreter.throw_exception<Error>("TypeError", "Not an Array");
|
interpreter.throw_exception<TypeError>("Not an Array");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<Array*>(this_object);
|
return static_cast<Array*>(this_object);
|
||||||
|
|
|
@ -47,7 +47,7 @@ Value BooleanPrototype::to_string(Interpreter& interpreter)
|
||||||
return js_string(interpreter.heap(), this_object.as_bool() ? "true" : "false");
|
return js_string(interpreter.heap(), this_object.as_bool() ? "true" : "false");
|
||||||
}
|
}
|
||||||
if (!this_object.is_object() || !this_object.as_object().is_boolean()) {
|
if (!this_object.is_object() || !this_object.as_object().is_boolean()) {
|
||||||
interpreter.throw_exception<Error>("TypeError", "Not a Boolean");
|
interpreter.throw_exception<TypeError>("Not a Boolean");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ Value BooleanPrototype::value_of(Interpreter& interpreter)
|
||||||
return this_object;
|
return this_object;
|
||||||
}
|
}
|
||||||
if (!this_object.is_object() || !this_object.as_object().is_boolean()) {
|
if (!this_object.is_object() || !this_object.as_object().is_boolean()) {
|
||||||
interpreter.throw_exception<Error>("TypeError", "Not a Boolean");
|
interpreter.throw_exception<TypeError>("Not a Boolean");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ static Date* this_date_from_interpreter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_date()) {
|
if (!this_object->is_date()) {
|
||||||
interpreter.throw_exception<Error>("TypeError", "object must be of type Date");
|
interpreter.throw_exception<TypeError>("object must be of type Date");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<Date*>(this_object);
|
return static_cast<Date*>(this_object);
|
||||||
|
|
|
@ -51,7 +51,7 @@ Value ErrorPrototype::name_getter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_error())
|
if (!this_object->is_error())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not an Error object");
|
return interpreter.throw_exception<TypeError>("Not an Error object");
|
||||||
return js_string(interpreter, static_cast<const Error*>(this_object)->name());
|
return js_string(interpreter, static_cast<const Error*>(this_object)->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,14 +61,14 @@ Value ErrorPrototype::message_getter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_error())
|
if (!this_object->is_error())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not an Error object");
|
return interpreter.throw_exception<TypeError>("Not an Error object");
|
||||||
return js_string(interpreter, static_cast<const Error*>(this_object)->message());
|
return js_string(interpreter, static_cast<const Error*>(this_object)->message());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ErrorPrototype::to_string(Interpreter& interpreter)
|
Value ErrorPrototype::to_string(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (!interpreter.this_value().is_object())
|
if (!interpreter.this_value().is_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not an object");
|
return interpreter.throw_exception<TypeError>("Not an object");
|
||||||
auto& this_object = interpreter.this_value().as_object();
|
auto& this_object = interpreter.this_value().as_object();
|
||||||
|
|
||||||
String name = "Error";
|
String name = "Error";
|
||||||
|
@ -89,7 +89,10 @@ Value ErrorPrototype::to_string(Interpreter& interpreter)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFINE_ERROR_SUBCLASS_PROTOTYPE(TitleCase, snake_case) \
|
#define DEFINE_ERROR_SUBCLASS_PROTOTYPE(TitleCase, snake_case) \
|
||||||
TitleCase::TitleCase() {} \
|
TitleCase::TitleCase() \
|
||||||
|
{ \
|
||||||
|
set_prototype(interpreter().error_prototype()); \
|
||||||
|
} \
|
||||||
TitleCase::~TitleCase() {} \
|
TitleCase::~TitleCase() {} \
|
||||||
const char* TitleCase::class_name() const { return #TitleCase; }
|
const char* TitleCase::class_name() const { return #TitleCase; }
|
||||||
|
|
||||||
|
|
|
@ -54,14 +54,14 @@ Value FunctionPrototype::apply(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function())
|
if (!this_object->is_function())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
return interpreter.throw_exception<TypeError>("Not a Function object");
|
||||||
auto function = static_cast<Function*>(this_object);
|
auto function = static_cast<Function*>(this_object);
|
||||||
auto this_arg = interpreter.argument(0);
|
auto this_arg = interpreter.argument(0);
|
||||||
auto arg_array = interpreter.argument(1);
|
auto arg_array = interpreter.argument(1);
|
||||||
if (arg_array.is_null() || arg_array.is_undefined())
|
if (arg_array.is_null() || arg_array.is_undefined())
|
||||||
return interpreter.call(function, this_arg);
|
return interpreter.call(function, this_arg);
|
||||||
if (!arg_array.is_object())
|
if (!arg_array.is_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "argument array must be an object");
|
return interpreter.throw_exception<TypeError>("argument array must be an object");
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
auto length_property = arg_array.as_object().get("length");
|
auto length_property = arg_array.as_object().get("length");
|
||||||
if (length_property.has_value())
|
if (length_property.has_value())
|
||||||
|
@ -87,7 +87,7 @@ Value FunctionPrototype::call(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function())
|
if (!this_object->is_function())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
return interpreter.throw_exception<TypeError>("Not a Function object");
|
||||||
auto function = static_cast<Function*>(this_object);
|
auto function = static_cast<Function*>(this_object);
|
||||||
auto this_arg = interpreter.argument(0);
|
auto this_arg = interpreter.argument(0);
|
||||||
Vector<Value> arguments;
|
Vector<Value> arguments;
|
||||||
|
@ -104,7 +104,7 @@ Value FunctionPrototype::to_string(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function())
|
if (!this_object->is_function())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
return interpreter.throw_exception<TypeError>("Not a Function object");
|
||||||
// FIXME: Functions should be able to know their name, if any
|
// FIXME: Functions should be able to know their name, if any
|
||||||
if (this_object->is_native_function()) {
|
if (this_object->is_native_function()) {
|
||||||
auto function_source = String::format("function () {\n [%s]\n}", this_object->class_name());
|
auto function_source = String::format("function () {\n [%s]\n}", this_object->class_name());
|
||||||
|
|
|
@ -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) {
|
if (mode == PutOwnPropertyMode::DefineProperty && !(metadata.value().attributes & Attribute::Configurable) && attributes != metadata.value().attributes) {
|
||||||
dbg() << "Disallow reconfig of non-configurable property";
|
dbg() << "Disallow reconfig of non-configurable property";
|
||||||
interpreter().throw_exception<Error>("TypeError", String::format("Cannot redefine property '%s'", property_name.characters()));
|
interpreter().throw_exception<TypeError>(String::format("Cannot redefine property '%s'", property_name.characters()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,9 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
|
||||||
Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
|
Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 2)
|
if (interpreter.argument_count() < 2)
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Object.getOwnPropertyDescriptor() needs 2 arguments");
|
return interpreter.throw_exception<TypeError>("Object.getOwnPropertyDescriptor() needs 2 arguments");
|
||||||
if (!interpreter.argument(0).is_object())
|
if (!interpreter.argument(0).is_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Object argument is not an object");
|
return interpreter.throw_exception<TypeError>("Object argument is not an object");
|
||||||
auto& object = interpreter.argument(0).as_object();
|
auto& object = interpreter.argument(0).as_object();
|
||||||
auto metadata = object.shape().lookup(interpreter.argument(1).to_string());
|
auto metadata = object.shape().lookup(interpreter.argument(1).to_string());
|
||||||
if (!metadata.has_value())
|
if (!metadata.has_value())
|
||||||
|
@ -119,11 +119,11 @@ Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
|
||||||
Value ObjectConstructor::define_property(Interpreter& interpreter)
|
Value ObjectConstructor::define_property(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 3)
|
if (interpreter.argument_count() < 3)
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Object.defineProperty() needs 3 arguments");
|
return interpreter.throw_exception<TypeError>("Object.defineProperty() needs 3 arguments");
|
||||||
if (!interpreter.argument(0).is_object())
|
if (!interpreter.argument(0).is_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Object argument is not an object");
|
return interpreter.throw_exception<TypeError>("Object argument is not an object");
|
||||||
if (!interpreter.argument(2).is_object())
|
if (!interpreter.argument(2).is_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Descriptor argument is not an object");
|
return interpreter.throw_exception<TypeError>("Descriptor argument is not an object");
|
||||||
auto& object = interpreter.argument(0).as_object();
|
auto& object = interpreter.argument(0).as_object();
|
||||||
auto& descriptor = interpreter.argument(2).as_object();
|
auto& descriptor = interpreter.argument(2).as_object();
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ Value ScriptFunction::length_getter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function())
|
if (!this_object->is_function())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a function");
|
return interpreter.throw_exception<TypeError>("Not a function");
|
||||||
return Value(static_cast<i32>(static_cast<const ScriptFunction*>(this_object)->parameters().size()));
|
return Value(static_cast<i32>(static_cast<const ScriptFunction*>(this_object)->parameters().size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ Value StringPrototype::index_of(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_string_object())
|
if (!this_object->is_string_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a String object");
|
return interpreter.throw_exception<TypeError>("Not a String object");
|
||||||
|
|
||||||
Value needle_value = js_undefined();
|
Value needle_value = js_undefined();
|
||||||
if (interpreter.argument_count() >= 1)
|
if (interpreter.argument_count() >= 1)
|
||||||
|
@ -141,7 +141,7 @@ static StringObject* string_object_from(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_string_object()) {
|
if (!this_object->is_string_object()) {
|
||||||
interpreter.throw_exception<Error>("TypeError", "Not a String object");
|
interpreter.throw_exception<TypeError>("Not a String object");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<StringObject*>(this_object);
|
return static_cast<StringObject*>(this_object);
|
||||||
|
@ -169,7 +169,7 @@ Value StringPrototype::length_getter(Interpreter& interpreter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_string_object())
|
if (!this_object->is_string_object())
|
||||||
return interpreter.throw_exception<Error>("TypeError", "Not a String object");
|
return interpreter.throw_exception<TypeError>("Not a String object");
|
||||||
return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length());
|
return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ Object* Value::to_object(Heap& heap) const
|
||||||
return heap.allocate<BooleanObject>(m_value.as_bool);
|
return heap.allocate<BooleanObject>(m_value.as_bool);
|
||||||
|
|
||||||
if (is_null() || is_undefined()) {
|
if (is_null() || is_undefined()) {
|
||||||
heap.interpreter().throw_exception<Error>("TypeError", "ToObject on null or undefined.");
|
heap.interpreter().throw_exception<TypeError>("ToObject on null or undefined.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue