1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:37:35 +00:00

LibJS: Make Interpreter::throw_exception() a void function

The motivation for this change is twofold:

- Returning a JS::Value is misleading as one would expect it to carry
  some meaningful information, like maybe the error object that's being
  created, but in fact it is always empty. Supposedly to serve as a
  shortcut for the common case of "throw and return empty value", but
  that's just leading us to my second point.
- Inconsistent usage / coding style: as of this commit there are 114
  uses of throw_exception() discarding its return value and 55 uses
  directly returning the call result (in LibJS, not counting LibWeb);
  with the first style often having a more explicit empty value (or
  nullptr in some cases) return anyway.
  One more line to always make the return value obvious is should be
  worth it.

So now it's basically always these steps, which is already being used in
the majority of cases (as outlined above):

- Throw an exception. This mutates interpreter state by updating
  m_exception and unwinding, but doesn't return anything.
- Let the caller explicitly return an empty value, nullptr or anything
  else itself.
This commit is contained in:
Linus Groh 2020-08-25 12:52:32 +02:00 committed by Andreas Kling
parent 98dd034c29
commit 9ea6ef4ed1
21 changed files with 281 additions and 171 deletions

View file

@ -88,13 +88,15 @@ public:
static JS_DEFINE_NATIVE_FUNCTION(parse_cell_name)
{
if (interpreter.argument_count() != 1)
return interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to parse_cell_name()");
if (interpreter.argument_count() != 1) {
interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to parse_cell_name()");
return {};
}
auto name_value = interpreter.argument(0);
if (!name_value.is_string())
return interpreter.throw_exception<JS::TypeError>("Expected a String argument to parse_cell_name()");
if (!name_value.is_string()) {
interpreter.throw_exception<JS::TypeError>("Expected a String argument to parse_cell_name()");
return {};
}
auto position = Sheet::parse_cell_name(name_value.as_string().string());
if (!position.has_value())
return JS::js_undefined();

View file

@ -147,10 +147,11 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
} else {
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
}
return interpreter.throw_exception<TypeError>(ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
interpreter.throw_exception<TypeError>(ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
} else {
return interpreter.throw_exception<TypeError>(ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
interpreter.throw_exception<TypeError>(ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
}
return {};
}
auto& function = callee.as_function();
@ -184,9 +185,10 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
} else if (m_callee->is_super_expression()) {
auto* super_constructor = interpreter.current_environment()->current_function()->prototype();
// FIXME: Functions should track their constructor kind.
if (!super_constructor || !super_constructor->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Super constructor");
if (!super_constructor || !super_constructor->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Super constructor");
return {};
}
result = interpreter.construct(static_cast<Function&>(*super_constructor), function, move(arguments), global_object);
if (interpreter.exception())
return {};
@ -668,9 +670,10 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
super_constructor = m_super_class->execute(interpreter, global_object);
if (interpreter.exception())
return {};
if (!super_constructor.is_function() && !super_constructor.is_null())
return interpreter.throw_exception<TypeError>(ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
if (!super_constructor.is_function() && !super_constructor.is_null()) {
interpreter.throw_exception<TypeError>(ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
return {};
}
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
Object* prototype = Object::create_empty(global_object);
@ -695,9 +698,10 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
if (interpreter.exception())
return {};
if (!class_prototype.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Class prototype");
if (!class_prototype.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Class prototype");
return {};
}
for (const auto& method : m_methods) {
auto method_value = method.execute(interpreter, global_object);
if (interpreter.exception())
@ -1137,8 +1141,10 @@ void ForOfStatement::dump(int indent) const
Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
auto value = interpreter.get_variable(string(), global_object);
if (value.is_empty())
return interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, string().characters());
if (value.is_empty()) {
interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, string().characters());
return {};
}
return value;
}
@ -1259,9 +1265,10 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
if (interpreter.exception())
return {};
if (reference.is_unresolvable())
return interpreter.throw_exception<ReferenceError>(ErrorType::InvalidLeftHandAssignment);
if (reference.is_unresolvable()) {
interpreter.throw_exception<ReferenceError>(ErrorType::InvalidLeftHandAssignment);
return {};
}
update_function_name(rhs_result, get_function_name(interpreter, reference.name().to_value(interpreter)));
reference.put(interpreter, global_object, rhs_result);
@ -1797,7 +1804,8 @@ Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
auto value = m_argument->execute(interpreter, global_object);
if (interpreter.exception())
return {};
return interpreter.throw_exception(value);
interpreter.throw_exception(value);
return {};
}
Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const

View file

@ -324,7 +324,7 @@ Value Interpreter::construct(Function& function, Function& new_target, Optional<
return this_value;
}
Value Interpreter::throw_exception(Exception* exception)
void Interpreter::throw_exception(Exception* exception)
{
#ifdef INTERPRETER_DEBUG
if (exception->value().is_object() && exception->value().as_object().is_error()) {
@ -341,7 +341,6 @@ Value Interpreter::throw_exception(Exception* exception)
#endif
m_exception = exception;
unwind(ScopeType::Try);
return {};
}
GlobalObject& Interpreter::global_object()

View file

@ -176,19 +176,19 @@ public:
void clear_exception() { m_exception = nullptr; }
template<typename T, typename... Args>
Value throw_exception(Args&&... args)
void throw_exception(Args&&... args)
{
return throw_exception(T::create(global_object(), forward<Args>(args)...));
}
Value throw_exception(Exception*);
Value throw_exception(Value value)
void throw_exception(Exception*);
void throw_exception(Value value)
{
return throw_exception(heap().allocate<Exception>(global_object(), value));
}
template<typename T, typename... Args>
Value throw_exception(ErrorType type, Args&&... args)
void throw_exception(ErrorType type, Args&&... args)
{
return throw_exception(T::create(global_object(), String::format(type.message(), forward<Args>(args)...)));
}

View file

@ -53,11 +53,11 @@ ArrayIteratorPrototype::~ArrayIteratorPrototype()
JS_DEFINE_NATIVE_FUNCTION(ArrayIteratorPrototype::next)
{
auto this_value = interpreter.this_value(global_object);
if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array Iterator");
if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array Iterator");
return {};
}
auto& this_object = this_value.as_object();
auto& iterator = static_cast<ArrayIterator&>(this_object);
auto target_array = iterator.array();
if (target_array.is_undefined())

View file

@ -204,8 +204,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push)
return {};
auto argument_count = interpreter.argument_count();
auto new_length = length + argument_count;
if (new_length > MAX_ARRAY_LIKE_INDEX)
return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
if (new_length > MAX_ARRAY_LIKE_INDEX) {
interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
return {};
}
for (size_t i = 0; i < argument_count; ++i) {
this_object->put(length + i, interpreter.argument(i));
if (interpreter.exception())
@ -744,8 +746,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice)
size_t new_length = initial_length + insert_count - actual_delete_count;
if (new_length > MAX_ARRAY_LIKE_INDEX)
return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
if (new_length > MAX_ARRAY_LIKE_INDEX) {
interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
return {};
}
auto removed_elements = Array::create(global_object);

View file

@ -58,8 +58,10 @@ JS_DEFINE_NATIVE_GETTER(ErrorPrototype::name_getter)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_error())
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
if (!this_object->is_error()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return {};
}
return js_string(interpreter, static_cast<const Error*>(this_object)->name());
}
@ -83,15 +85,19 @@ JS_DEFINE_NATIVE_GETTER(ErrorPrototype::message_getter)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_error())
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
if (!this_object->is_error()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return {};
}
return js_string(interpreter, static_cast<const Error*>(this_object)->message());
}
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
{
if (!interpreter.this_value(global_object).is_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, interpreter.this_value(global_object).to_string_without_side_effects().characters());
if (!interpreter.this_value(global_object).is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, interpreter.this_value(global_object).to_string_without_side_effects().characters());
return {};
}
auto& this_object = interpreter.this_value(global_object).as_object();
String name = "Error";

View file

@ -65,15 +65,19 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
auto& function = static_cast<Function&>(*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>(ErrorType::FunctionArgsNotObject);
if (!arg_array.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::FunctionArgsNotObject);
return {};
}
auto length_property = arg_array.as_object().get("length");
if (interpreter.exception())
return {};
@ -95,9 +99,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
auto& this_function = static_cast<Function&>(*this_object);
auto bound_this_arg = interpreter.argument(0);
@ -115,8 +120,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::call)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
auto& function = static_cast<Function&>(*this_object);
auto this_arg = interpreter.argument(0);
MarkedValueList arguments(interpreter.heap());
@ -132,9 +139,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::to_string)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
String function_name = static_cast<Function*>(this_object)->name();
String function_parameters = "";
String function_body;
@ -173,9 +181,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::symbol_has_instance)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (!this_object->is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
return ordinary_has_instance(interpreter, interpreter.argument(0), this_object);
}

View file

@ -112,9 +112,10 @@ bool LexicalEnvironment::has_this_binding() const
Value LexicalEnvironment::get_this_binding() const
{
ASSERT(has_this_binding());
if (this_binding_status() == ThisBindingStatus::Uninitialized)
return interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized);
if (this_binding_status() == ThisBindingStatus::Uninitialized) {
interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized);
return {};
}
return m_this_value;
}

View file

@ -67,7 +67,8 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
} else if (this_value.is_object() && this_value.as_object().is_number_object()) {
number_value = static_cast<NumberObject&>(this_value.as_object()).value_of();
} else {
return interpreter.throw_exception<TypeError>(ErrorType::NumberIncompatibleThis, "toString");
interpreter.throw_exception<TypeError>(ErrorType::NumberIncompatibleThis, "toString");
return {};
}
int radix;
@ -78,8 +79,10 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
radix = argument.to_i32(interpreter);
}
if (interpreter.exception() || radix < 2 || radix > 36)
return interpreter.throw_exception<RangeError>(ErrorType::InvalidRadix);
if (interpreter.exception() || radix < 2 || radix > 36) {
interpreter.throw_exception<RangeError>(ErrorType::InvalidRadix);
return {};
}
if (number_value.is_positive_infinity())
return js_string(interpreter, "Infinity");

View file

@ -105,8 +105,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_prototype_of)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
{
if (interpreter.argument_count() < 2)
return interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs);
if (interpreter.argument_count() < 2) {
interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs);
return {};
}
auto* object = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception())
return {};
@ -162,10 +164,14 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptor)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
{
if (!interpreter.argument(0).is_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument");
if (!interpreter.argument(2).is_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument");
if (!interpreter.argument(0).is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument");
return {};
}
if (!interpreter.argument(2).is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument");
return {};
}
auto& object = interpreter.argument(0).as_object();
auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1));
if (interpreter.exception())
@ -191,8 +197,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
{
if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
if (!interpreter.argument_count()) {
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception())
@ -203,9 +211,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
{
if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
if (!interpreter.argument_count()) {
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception())
return {};
@ -215,9 +224,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
{
if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
if (!interpreter.argument_count()) {
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception())
return {};

View file

@ -51,22 +51,28 @@ ProxyConstructor::~ProxyConstructor()
Value ProxyConstructor::call(Interpreter& interpreter)
{
return interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
return {};
}
Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
{
if (interpreter.argument_count() < 2)
return interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
if (interpreter.argument_count() < 2) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
return {};
}
auto target = interpreter.argument(0);
auto handler = interpreter.argument(1);
if (!target.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects().characters());
if (!handler.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects().characters());
if (!target.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects().characters());
return {};
}
if (!handler.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects().characters());
return {};
}
return ProxyObject::create(global_object(), target.as_object(), handler.as_object());
}

View file

@ -375,8 +375,10 @@ Value ProxyObject::get(const PropertyName& name, Value) const
return {};
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.get(name);
if (!trap.is_function())
return interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "get");
if (!trap.is_function()) {
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "get");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
@ -388,10 +390,14 @@ Value ProxyObject::get(const PropertyName& name, Value) const
if (target_desc.has_value()) {
if (interpreter().exception())
return {};
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), trap_result, target_desc.value().value))
return interpreter().throw_exception<TypeError>(ErrorType::ProxyGetImmutableDataProperty);
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined())
return interpreter().throw_exception<TypeError>(ErrorType::ProxyGetNonConfigurableAccessor);
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), trap_result, target_desc.value().value)) {
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetImmutableDataProperty);
return {};
}
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined()) {
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetNonConfigurableAccessor);
return {};
}
}
return trap_result;
}
@ -445,8 +451,10 @@ Value ProxyObject::delete_property(const PropertyName& name)
return {};
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.delete_property(name);
if (!trap.is_function())
return interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "deleteProperty");
if (!trap.is_function()) {
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "deleteProperty");
return {};
}
MarkedValueList arguments(interpreter().heap());
arguments.append(Value(&m_target));
arguments.append(js_string(interpreter(), name.to_string()));
@ -460,8 +468,10 @@ Value ProxyObject::delete_property(const PropertyName& name)
return {};
if (!target_desc.has_value())
return Value(true);
if (!target_desc.value().attributes.is_configurable())
return interpreter().throw_exception<TypeError>(ErrorType::ProxyDeleteNonConfigurable);
if (!target_desc.value().attributes.is_configurable()) {
interpreter().throw_exception<TypeError>(ErrorType::ProxyDeleteNonConfigurable);
return {};
}
return Value(true);
}
@ -472,10 +482,12 @@ void ProxyObject::visit_children(Cell::Visitor& visitor)
visitor.visit(&m_handler);
}
Value ProxyObject::call(Interpreter& interpreter) {
if (!is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters());
Value ProxyObject::call(Interpreter& interpreter)
{
if (!is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters());
return {};
}
if (m_is_revoked) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyRevoked);
return {};
@ -485,9 +497,10 @@ Value ProxyObject::call(Interpreter& interpreter) {
return {};
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return static_cast<Function&>(m_target).call(interpreter);
if (!trap.is_function())
return interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "apply");
if (!trap.is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "apply");
return {};
}
MarkedValueList arguments(interpreter.heap());
arguments.append(Value(&m_target));
arguments.append(Value(&m_handler));
@ -501,10 +514,12 @@ Value ProxyObject::call(Interpreter& interpreter) {
return interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
}
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) {
if (!is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target)
{
if (!is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
return {};
}
if (m_is_revoked) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyRevoked);
return {};
@ -514,8 +529,10 @@ Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) {
return {};
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return static_cast<Function&>(m_target).construct(interpreter, new_target);
if (!trap.is_function())
return interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
if (!trap.is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
return {};
}
MarkedValueList arguments(interpreter.heap());
arguments.append(Value(&m_target));
@ -526,8 +543,10 @@ Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) {
arguments.append(arguments_array);
arguments.append(Value(&new_target));
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
if (!result.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
if (!result.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
return {};
}
return result;
}

View file

@ -143,8 +143,10 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::define_property)
auto* target = get_target_object_from(interpreter, "defineProperty");
if (!target)
return {};
if (!interpreter.argument(2).is_object())
return interpreter.throw_exception<TypeError>(ErrorType::ReflectBadDescriptorArgument);
if (!interpreter.argument(2).is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::ReflectBadDescriptorArgument);
return {};
}
auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1));
if (interpreter.exception())
return {};

View file

@ -135,8 +135,10 @@ Value ScriptFunction::call(Interpreter& interpreter)
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
{
if (m_is_arrow_function)
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
if (m_is_arrow_function) {
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
return {};
}
return call(interpreter);
}

View file

@ -53,8 +53,10 @@ StringIteratorPrototype::~StringIteratorPrototype()
JS_DEFINE_NATIVE_FUNCTION(StringIteratorPrototype::next)
{
auto this_value = interpreter.this_value(global_object);
if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "String Iterator");
if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "String Iterator");
return {};
}
auto& this_object = this_value.as_object();
auto& iterator = static_cast<StringIterator&>(this_object);

View file

@ -140,10 +140,14 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
auto count_value = interpreter.argument(0).to_number(interpreter);
if (interpreter.exception())
return {};
if (count_value.as_double() < 0)
return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
if (count_value.is_infinity())
return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
if (count_value.as_double() < 0) {
interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
return {};
}
if (count_value.is_infinity()) {
interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
return {};
}
auto count = count_value.to_size_t(interpreter);
if (interpreter.exception())
return {};
@ -455,8 +459,10 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator)
{
auto this_object = interpreter.this_value(global_object);
if (this_object.is_undefined() || this_object.is_null())
return interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
if (this_object.is_undefined() || this_object.is_null()) {
interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
return {};
}
auto string = this_object.to_string(interpreter);
if (interpreter.exception())

View file

@ -58,8 +58,10 @@ JS_DEFINE_NATIVE_GETTER(Uint8ClampedArray::length_getter)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object)
return {};
if (StringView(this_object->class_name()) != "Uint8ClampedArray")
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray");
if (StringView(this_object->class_name()) != "Uint8ClampedArray") {
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray");
return {};
}
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length());
}

View file

@ -686,8 +686,10 @@ Value exp(Interpreter& interpreter, Value lhs, Value rhs)
Value in(Interpreter& interpreter, Value lhs, Value rhs)
{
if (!rhs.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject);
if (!rhs.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject);
return {};
}
auto lhs_string = lhs.to_string(interpreter);
if (interpreter.exception())
return {};
@ -696,22 +698,25 @@ Value in(Interpreter& interpreter, Value lhs, Value rhs)
Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
{
if (!rhs.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
if (!rhs.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
return {};
}
auto has_instance_method = rhs.as_object().get(interpreter.well_known_symbol_has_instance());
if (!has_instance_method.is_empty()) {
if (!has_instance_method.is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
if (!has_instance_method.is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
return {};
}
MarkedValueList arguments(interpreter.heap());
arguments.append(lhs);
return Value(interpreter.call(has_instance_method.as_function(), rhs, move(arguments)).to_boolean());
}
if (!rhs.is_function())
return interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters());
if (!rhs.is_function()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters());
return {};
}
return ordinary_has_instance(interpreter, lhs, rhs);
}
@ -734,9 +739,10 @@ Value ordinary_has_instance(Interpreter& interpreter, Value lhs, Value rhs)
if (interpreter.exception())
return {};
if (!rhs_prototype.is_object())
return interpreter.throw_exception<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters());
if (!rhs_prototype.is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters());
return {};
}
while (true) {
lhs_object = lhs_object->prototype();
if (interpreter.exception())

View file

@ -139,14 +139,17 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_interval)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
return {};
}
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
if (!callback_object)
return {};
if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
if (!callback_object->is_function()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
return {};
}
i32 interval = 0;
if (interpreter.argument_count() >= 2) {
interval = interpreter.argument(1).to_i32(interpreter);
@ -165,14 +168,17 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_timeout)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
return {};
}
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
if (!callback_object)
return {};
if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
if (!callback_object->is_function()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
return {};
}
i32 interval = 0;
if (interpreter.argument_count() >= 2) {
interval = interpreter.argument(1).to_i32(interpreter);
@ -191,8 +197,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_timeout)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearTimeout");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearTimeout");
return {};
}
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
if (interpreter.exception())
return {};
@ -205,8 +213,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_interval)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearInterval");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearInterval");
return {};
}
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
if (interpreter.exception())
return {};
@ -219,13 +229,17 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::request_animation_frame)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
return {};
}
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
if (!callback_object)
return {};
if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
if (!callback_object->is_function()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
return {};
}
return JS::Value(impl->request_animation_frame(*static_cast<JS::Function*>(callback_object)));
}
@ -234,8 +248,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::cancel_animation_frame)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
return {};
}
auto id = interpreter.argument(0).to_i32(interpreter);
if (interpreter.exception())
return {};
@ -248,8 +264,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::atob)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "atob");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "atob");
return {};
}
auto string = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception())
return {};
@ -264,8 +282,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::btoa)
auto* impl = impl_from(interpreter, global_object);
if (!impl)
return {};
if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "btoa");
if (!interpreter.argument_count()) {
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "btoa");
return {};
}
auto string = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception())
return {};
@ -273,8 +293,10 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::btoa)
Vector<u8> byte_string;
byte_string.ensure_capacity(string.length());
for (u32 code_point : Utf8View(string)) {
if (code_point > 0xff)
return interpreter.throw_exception<JS::InvalidCharacterError>(JS::ErrorType::NotAByteString, "btoa");
if (code_point > 0xff) {
interpreter.throw_exception<JS::InvalidCharacterError>(JS::ErrorType::NotAByteString, "btoa");
return {};
}
byte_string.append(code_point);
}

View file

@ -645,12 +645,13 @@ void generate_implementation(const IDL::Interface& interface)
out() << " if (!impl)";
out() << " return {};";
if (function.length() > 0) {
out() << " if (interpreter.argument_count() < " << function.length() << ")";
out() << " if (interpreter.argument_count() < " << function.length() << ") {";
if (function.length() == 1)
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, \"" << function.name << "\");";
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, \"" << function.name << "\");";
else
out() << " return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
out() << " return {};";
out() << " }";
}
StringBuilder arguments_builder;