1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:07:44 +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) static JS_DEFINE_NATIVE_FUNCTION(parse_cell_name)
{ {
if (interpreter.argument_count() != 1) if (interpreter.argument_count() != 1) {
return interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to parse_cell_name()"); interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to parse_cell_name()");
return {};
}
auto name_value = interpreter.argument(0); auto name_value = interpreter.argument(0);
if (!name_value.is_string()) if (!name_value.is_string()) {
return interpreter.throw_exception<JS::TypeError>("Expected a String argument to parse_cell_name()"); 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()); auto position = Sheet::parse_cell_name(name_value.as_string().string());
if (!position.has_value()) if (!position.has_value())
return JS::js_undefined(); return JS::js_undefined();

View file

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

View file

@ -176,19 +176,19 @@ public:
void clear_exception() { m_exception = nullptr; } void clear_exception() { m_exception = nullptr; }
template<typename T, typename... Args> 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)...)); return throw_exception(T::create(global_object(), forward<Args>(args)...));
} }
Value throw_exception(Exception*); void throw_exception(Exception*);
Value throw_exception(Value value) void throw_exception(Value value)
{ {
return throw_exception(heap().allocate<Exception>(global_object(), value)); return throw_exception(heap().allocate<Exception>(global_object(), value));
} }
template<typename T, typename... Args> 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)...))); 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) JS_DEFINE_NATIVE_FUNCTION(ArrayIteratorPrototype::next)
{ {
auto this_value = interpreter.this_value(global_object); auto this_value = interpreter.this_value(global_object);
if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object()) if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array Iterator"); interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array Iterator");
return {};
}
auto& this_object = this_value.as_object(); auto& this_object = this_value.as_object();
auto& iterator = static_cast<ArrayIterator&>(this_object); auto& iterator = static_cast<ArrayIterator&>(this_object);
auto target_array = iterator.array(); auto target_array = iterator.array();
if (target_array.is_undefined()) if (target_array.is_undefined())

View file

@ -204,8 +204,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push)
return {}; return {};
auto argument_count = interpreter.argument_count(); auto argument_count = interpreter.argument_count();
auto new_length = length + argument_count; auto new_length = length + argument_count;
if (new_length > MAX_ARRAY_LIKE_INDEX) if (new_length > MAX_ARRAY_LIKE_INDEX) {
return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize); interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
return {};
}
for (size_t i = 0; i < argument_count; ++i) { for (size_t i = 0; i < argument_count; ++i) {
this_object->put(length + i, interpreter.argument(i)); this_object->put(length + i, interpreter.argument(i));
if (interpreter.exception()) if (interpreter.exception())
@ -744,8 +746,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice)
size_t new_length = initial_length + insert_count - actual_delete_count; size_t new_length = initial_length + insert_count - actual_delete_count;
if (new_length > MAX_ARRAY_LIKE_INDEX) if (new_length > MAX_ARRAY_LIKE_INDEX) {
return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize); interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
return {};
}
auto removed_elements = Array::create(global_object); 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_error()) if (!this_object->is_error()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error"); interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return {};
}
return js_string(interpreter, static_cast<const Error*>(this_object)->name()); 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_error()) if (!this_object->is_error()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error"); interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return {};
}
return js_string(interpreter, static_cast<const Error*>(this_object)->message()); return js_string(interpreter, static_cast<const Error*>(this_object)->message());
} }
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string) JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
{ {
if (!interpreter.this_value(global_object).is_object()) 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()); 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(); auto& this_object = interpreter.this_value(global_object).as_object();
String name = "Error"; String name = "Error";
@ -123,10 +129,10 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \ #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
PrototypeName::PrototypeName(GlobalObject& global_object) \ PrototypeName::PrototypeName(GlobalObject& global_object) \
: Object(*global_object.error_prototype()) \ : Object(*global_object.error_prototype()) \
{ \ { \
} \ } \
PrototypeName::~PrototypeName() { } PrototypeName::~PrototypeName() {}
JS_ENUMERATE_ERROR_SUBCLASSES JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE #undef __JS_ENUMERATE

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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
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<TypeError>(ErrorType::FunctionArgsNotObject); interpreter.throw_exception<TypeError>(ErrorType::FunctionArgsNotObject);
return {};
}
auto length_property = arg_array.as_object().get("length"); auto length_property = arg_array.as_object().get("length");
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -95,9 +99,10 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
auto& this_function = static_cast<Function&>(*this_object); auto& this_function = static_cast<Function&>(*this_object);
auto bound_this_arg = interpreter.argument(0); 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
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);
MarkedValueList arguments(interpreter.heap()); 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
String function_name = static_cast<Function*>(this_object)->name(); String function_name = static_cast<Function*>(this_object)->name();
String function_parameters = ""; String function_parameters = "";
String function_body; 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
return {};
}
return ordinary_has_instance(interpreter, interpreter.argument(0), this_object); 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 Value LexicalEnvironment::get_this_binding() const
{ {
ASSERT(has_this_binding()); ASSERT(has_this_binding());
if (this_binding_status() == ThisBindingStatus::Uninitialized) if (this_binding_status() == ThisBindingStatus::Uninitialized) {
return interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized); interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized);
return {};
}
return m_this_value; 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()) { } else if (this_value.is_object() && this_value.as_object().is_number_object()) {
number_value = static_cast<NumberObject&>(this_value.as_object()).value_of(); number_value = static_cast<NumberObject&>(this_value.as_object()).value_of();
} else { } else {
return interpreter.throw_exception<TypeError>(ErrorType::NumberIncompatibleThis, "toString"); interpreter.throw_exception<TypeError>(ErrorType::NumberIncompatibleThis, "toString");
return {};
} }
int radix; int radix;
@ -78,8 +79,10 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
radix = argument.to_i32(interpreter); radix = argument.to_i32(interpreter);
} }
if (interpreter.exception() || radix < 2 || radix > 36) if (interpreter.exception() || radix < 2 || radix > 36) {
return interpreter.throw_exception<RangeError>(ErrorType::InvalidRadix); interpreter.throw_exception<RangeError>(ErrorType::InvalidRadix);
return {};
}
if (number_value.is_positive_infinity()) if (number_value.is_positive_infinity())
return js_string(interpreter, "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) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
{ {
if (interpreter.argument_count() < 2) if (interpreter.argument_count() < 2) {
return interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs); interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs);
return {};
}
auto* object = interpreter.argument(0).to_object(interpreter, global_object); auto* object = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -162,10 +164,14 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptor)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
{ {
if (!interpreter.argument(0).is_object()) if (!interpreter.argument(0).is_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument"); interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument");
if (!interpreter.argument(2).is_object()) return {};
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument"); }
if (!interpreter.argument(2).is_object()) {
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument");
return {};
}
auto& object = interpreter.argument(0).as_object(); auto& object = interpreter.argument(0).as_object();
auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1)); auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1));
if (interpreter.exception()) if (interpreter.exception())
@ -191,8 +197,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count()) {
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject); interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object); auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception()) if (interpreter.exception())
@ -203,9 +211,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count()) {
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject); interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object); auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -215,9 +224,10 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count()) {
return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject); interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object); auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

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

View file

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

View file

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

View file

@ -53,8 +53,10 @@ StringIteratorPrototype::~StringIteratorPrototype()
JS_DEFINE_NATIVE_FUNCTION(StringIteratorPrototype::next) JS_DEFINE_NATIVE_FUNCTION(StringIteratorPrototype::next)
{ {
auto this_value = interpreter.this_value(global_object); auto this_value = interpreter.this_value(global_object);
if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "String Iterator"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "String Iterator");
return {};
}
auto& this_object = this_value.as_object(); auto& this_object = this_value.as_object();
auto& iterator = static_cast<StringIterator&>(this_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); auto count_value = interpreter.argument(0).to_number(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (count_value.as_double() < 0) if (count_value.as_double() < 0) {
return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive"); interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
if (count_value.is_infinity()) return {};
return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite"); }
if (count_value.is_infinity()) {
interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
return {};
}
auto count = count_value.to_size_t(interpreter); auto count = count_value.to_size_t(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -455,8 +459,10 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator)
{ {
auto this_object = interpreter.this_value(global_object); auto this_object = interpreter.this_value(global_object);
if (this_object.is_undefined() || this_object.is_null()) if (this_object.is_undefined() || this_object.is_null()) {
return interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef); interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
return {};
}
auto string = this_object.to_string(interpreter); auto string = this_object.to_string(interpreter);
if (interpreter.exception()) 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); auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
if (!this_object) if (!this_object)
return {}; return {};
if (StringView(this_object->class_name()) != "Uint8ClampedArray") if (StringView(this_object->class_name()) != "Uint8ClampedArray") {
return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray");
return {};
}
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length()); 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) Value in(Interpreter& interpreter, Value lhs, Value rhs)
{ {
if (!rhs.is_object()) if (!rhs.is_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject); interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject);
return {};
}
auto lhs_string = lhs.to_string(interpreter); auto lhs_string = lhs.to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -696,22 +698,25 @@ Value in(Interpreter& interpreter, Value lhs, Value rhs)
Value instance_of(Interpreter& interpreter, Value lhs, Value rhs) Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
{ {
if (!rhs.is_object()) if (!rhs.is_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters()); 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()); 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_empty()) {
if (!has_instance_method.is_function()) if (!has_instance_method.is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters()); interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
return {};
}
MarkedValueList arguments(interpreter.heap()); MarkedValueList arguments(interpreter.heap());
arguments.append(lhs); arguments.append(lhs);
return Value(interpreter.call(has_instance_method.as_function(), rhs, move(arguments)).to_boolean()); return Value(interpreter.call(has_instance_method.as_function(), rhs, move(arguments)).to_boolean());
} }
if (!rhs.is_function()) if (!rhs.is_function()) {
return interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters()); interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters());
return {};
}
return ordinary_has_instance(interpreter, lhs, rhs); return ordinary_has_instance(interpreter, lhs, rhs);
} }
@ -734,9 +739,10 @@ Value ordinary_has_instance(Interpreter& interpreter, Value lhs, Value rhs)
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (!rhs_prototype.is_object()) if (!rhs_prototype.is_object()) {
return interpreter.throw_exception<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters()); interpreter.throw_exception<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters());
return {};
}
while (true) { while (true) {
lhs_object = lhs_object->prototype(); lhs_object = lhs_object->prototype();
if (interpreter.exception()) if (interpreter.exception())

View file

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

View file

@ -645,12 +645,13 @@ void generate_implementation(const IDL::Interface& interface)
out() << " if (!impl)"; out() << " if (!impl)";
out() << " return {};"; out() << " return {};";
if (function.length() > 0) { if (function.length() > 0) {
out() << " if (interpreter.argument_count() < " << function.length() << ")"; out() << " if (interpreter.argument_count() < " << function.length() << ") {";
if (function.length() == 1) 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 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; StringBuilder arguments_builder;