LibJS: Consolidate error messages into ErrorTypes.h

Now, exceptions can be thrown with
interpreter.throw_exception<T>(ErrorType:TYPE, "format", "args",
"here").
This commit is contained in:
Matthew Olsson 2020-06-09 22:48:01 -07:00 committed by Andreas Kling
parent 9940a7f6de
commit 78155a6668
Notes: sideshowbarker 2024-07-19 05:43:14 +09:00
63 changed files with 439 additions and 223 deletions

View file

@ -120,15 +120,15 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
auto call_type = is_new_expression() ? "constructor" : "function"; auto call_type = is_new_expression() ? "constructor" : "function";
if (m_callee->is_identifier() || m_callee->is_member_expression()) { if (m_callee->is_identifier() || m_callee->is_member_expression()) {
String expression_string; String expression_string;
if (m_callee->is_identifier()) if (m_callee->is_identifier()) {
expression_string = static_cast<const Identifier&>(*m_callee).string(); expression_string = static_cast<const Identifier&>(*m_callee).string();
else } else {
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation(); expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
error_message = String::format("%s is not a %s (evaluated from '%s')", callee.to_string_without_side_effects().characters(), call_type, expression_string.characters()); }
return interpreter.throw_exception<TypeError>(ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
} else { } else {
error_message = String::format("%s is not a %s", callee.to_string_without_side_effects().characters(), call_type); return interpreter.throw_exception<TypeError>(ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
} }
return interpreter.throw_exception<TypeError>(error_message);
} }
auto& function = callee.as_function(); auto& function = callee.as_function();
@ -156,7 +156,7 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
for (auto ch : static_cast<const StringObject&>(value.as_object()).primitive_string().string()) for (auto ch : static_cast<const StringObject&>(value.as_object()).primitive_string().string())
arguments.append(Value(js_string(interpreter, String::format("%c", ch)))); arguments.append(Value(js_string(interpreter, String::format("%c", ch))));
} else { } else {
interpreter.throw_exception<TypeError>(String::format("%s is not iterable", value.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotIterable, value.to_string_without_side_effects().characters());
} }
} else { } else {
arguments.append(value); arguments.append(value);
@ -412,7 +412,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
// FIXME: We need to properly implement the iterator protocol // FIXME: We need to properly implement the iterator protocol
auto is_iterable = rhs_result.is_array() || rhs_result.is_string() || (rhs_result.is_object() && rhs_result.as_object().is_string_object()); auto is_iterable = rhs_result.is_array() || rhs_result.is_string() || (rhs_result.is_object() && rhs_result.as_object().is_string_object());
if (!is_iterable) if (!is_iterable)
return interpreter.throw_exception<TypeError>("for..of right-hand side must be iterable"); return interpreter.throw_exception<TypeError>(ErrorType::ForOfNotIterable);
size_t index = 0; size_t index = 0;
auto next = [&]() -> Optional<Value> { auto next = [&]() -> Optional<Value> {
@ -985,7 +985,7 @@ Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object)
{ {
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>(String::format("'%s' not known", string().characters())); return interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, string().characters());
return value; return value;
} }
@ -1107,7 +1107,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
return {}; return {};
if (reference.is_unresolvable()) if (reference.is_unresolvable())
return interpreter.throw_exception<ReferenceError>("Invalid left-hand side in assignment"); return interpreter.throw_exception<ReferenceError>(ErrorType::InvalidLeftHandAssignment);
update_function_name(rhs_result, reference.name().as_string()); update_function_name(rhs_result, reference.name().as_string());
reference.put(interpreter, rhs_result); reference.put(interpreter, rhs_result);
@ -1523,7 +1523,7 @@ Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
array->indexed_properties().append(js_string(interpreter, string_to_spread.substring(i, 1))); array->indexed_properties().append(js_string(interpreter, string_to_spread.substring(i, 1)));
continue; continue;
} }
interpreter.throw_exception<TypeError>(String::format("%s is not iterable", value.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotIterable, value.to_string_without_side_effects().characters());
return {}; return {};
} }
} }
@ -1573,7 +1573,7 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& glo
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (!tag.is_function()) { if (!tag.is_function()) {
interpreter.throw_exception<TypeError>(String::format("%s is not a function", tag.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, tag.to_string_without_side_effects().characters());
return {}; return {};
} }
auto& tag_function = tag.as_function(); auto& tag_function = tag.as_function();

View file

@ -27,6 +27,7 @@ set(SOURCES
Runtime/ErrorConstructor.cpp Runtime/ErrorConstructor.cpp
Runtime/Error.cpp Runtime/Error.cpp
Runtime/ErrorPrototype.cpp Runtime/ErrorPrototype.cpp
Runtime/ErrorTypes.cpp
Runtime/Exception.cpp Runtime/Exception.cpp
Runtime/FunctionConstructor.cpp Runtime/FunctionConstructor.cpp
Runtime/Function.cpp Runtime/Function.cpp

View file

@ -156,7 +156,7 @@ void Interpreter::set_variable(const FlyString& name, Value value, GlobalObject&
auto possible_match = environment->get(name); auto possible_match = environment->get(name);
if (possible_match.has_value()) { if (possible_match.has_value()) {
if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) { if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) {
throw_exception<TypeError>("Assignment to constant variable"); throw_exception<TypeError>(ErrorType::InvalidAssignToConst);
return; return;
} }

View file

@ -35,6 +35,7 @@
#include <LibJS/Console.h> #include <LibJS/Console.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibJS/Heap/Heap.h> #include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/ErrorTypes.h>
#include <LibJS/Runtime/Exception.h> #include <LibJS/Runtime/Exception.h>
#include <LibJS/Runtime/LexicalEnvironment.h> #include <LibJS/Runtime/LexicalEnvironment.h>
#include <LibJS/Runtime/MarkedValueList.h> #include <LibJS/Runtime/MarkedValueList.h>
@ -175,6 +176,12 @@ public:
return throw_exception(heap().allocate<Exception>(value)); return throw_exception(heap().allocate<Exception>(value));
} }
template<typename T, typename... Args>
Value throw_exception(ErrorType type, Args&&... args)
{
return throw_exception(T::create(global_object(), String::format(type.message(), forward<Args>(args)...)));
}
Value last_value() const { return m_last_value; } Value last_value() const { return m_last_value; }
bool underscore_is_last_value() const { return m_underscore_is_last_value; } bool underscore_is_last_value() const { return m_underscore_is_last_value; }

View file

@ -55,7 +55,7 @@ Array* array_from(Interpreter& interpreter, GlobalObject& global_object)
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_array()) { if (!this_object->is_array()) {
interpreter.throw_exception<TypeError>("Not an Array"); interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array");
return nullptr; return nullptr;
} }
return static_cast<Array*>(this_object); return static_cast<Array*>(this_object);
@ -78,7 +78,7 @@ void Array::length_setter(Interpreter& interpreter, Value value)
if (interpreter.exception()) if (interpreter.exception())
return; return;
if (length.is_nan() || length.is_infinity() || length.as_double() < 0) { if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
interpreter.throw_exception<RangeError>("Invalid array length"); interpreter.throw_exception<RangeError>(ErrorType::ArrayInvalidLength);
return; return;
} }
array->indexed_properties().set_array_like_size(length.as_double()); array->indexed_properties().set_array_like_size(length.as_double());

View file

@ -59,7 +59,7 @@ Value ArrayConstructor::call(Interpreter& interpreter)
if (interpreter.argument_count() == 1 && interpreter.argument(0).is_number()) { if (interpreter.argument_count() == 1 && interpreter.argument(0).is_number()) {
auto array_length_value = interpreter.argument(0); auto array_length_value = interpreter.argument(0);
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) { if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) {
interpreter.throw_exception<TypeError>("Invalid array length"); interpreter.throw_exception<TypeError>(ErrorType::ArrayInvalidLength);
return {}; return {};
} }
auto* array = Array::create(interpreter.global_object()); auto* array = Array::create(interpreter.global_object());

View file

@ -80,12 +80,12 @@ ArrayPrototype::~ArrayPrototype()
static Function* callback_from_args(Interpreter& interpreter, const String& name) static Function* callback_from_args(Interpreter& interpreter, const String& name)
{ {
if (interpreter.argument_count() < 1) { if (interpreter.argument_count() < 1) {
interpreter.throw_exception<TypeError>(String::format("Array.prototype.%s() requires at least one argument", name.characters())); interpreter.throw_exception<TypeError>(ErrorType::ArrayPrototypeOneArg, name.characters());
return nullptr; return nullptr;
} }
auto callback = interpreter.argument(0); auto callback = interpreter.argument(0);
if (!callback.is_function()) { if (!callback.is_function()) {
interpreter.throw_exception<TypeError>(String::format("%s is not a function", callback.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, callback.to_string_without_side_effects().characters());
return nullptr; return nullptr;
} }
return &callback.as_function(); return &callback.as_function();
@ -194,7 +194,7 @@ Value ArrayPrototype::push(Interpreter& interpreter)
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>("Maximum array size exceeded"); return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
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())
@ -467,7 +467,7 @@ Value ArrayPrototype::reduce(Interpreter& interpreter)
start += 1; start += 1;
} }
if (!start_found) { if (!start_found) {
interpreter.throw_exception<TypeError>("Reduce of empty array with no initial value"); interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
return {}; return {};
} }
} }
@ -526,7 +526,7 @@ Value ArrayPrototype::reduce_right(Interpreter& interpreter)
start -= 1; start -= 1;
} }
if (!start_found) { if (!start_found) {
interpreter.throw_exception<TypeError>("Reduce of empty array with no initial value"); interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
return {}; return {};
} }
} }
@ -734,7 +734,7 @@ Value ArrayPrototype::splice(Interpreter& interpreter)
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>("Maximum array size exceeded"); return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
auto removed_elements = Array::create(interpreter.global_object()); auto removed_elements = Array::create(interpreter.global_object());

View file

@ -56,7 +56,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
return {}; return {};
if (primitive.is_number()) { if (primitive.is_number()) {
if (!primitive.is_integer()) { if (!primitive.is_integer()) {
interpreter.throw_exception<RangeError>("BigInt argument must be an integer"); interpreter.throw_exception<RangeError>(ErrorType::BigIntIntArgument);
return {}; return {};
} }
return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() }); return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() });
@ -69,7 +69,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
Value BigIntConstructor::construct(Interpreter& interpreter) Value BigIntConstructor::construct(Interpreter& interpreter)
{ {
interpreter.throw_exception<TypeError>("BigInt is not a constructor"); interpreter.throw_exception<TypeError>(ErrorType::NotACtor, "BigInt");
return {}; return {};
} }

View file

@ -51,7 +51,7 @@ static BigIntObject* bigint_object_from(Interpreter& interpreter, GlobalObject&
if (!this_object) if (!this_object)
return nullptr; return nullptr;
if (!this_object->is_bigint_object()) { if (!this_object->is_bigint_object()) {
interpreter.throw_exception<TypeError>("Not a BigInt object"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "BigInt");
return nullptr; return nullptr;
} }
return static_cast<BigIntObject*>(this_object); return static_cast<BigIntObject*>(this_object);

View file

@ -48,7 +48,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<TypeError>("Not a Boolean"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Boolean");
return {}; return {};
} }
@ -63,7 +63,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<TypeError>("Not a Boolean"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Boolean");
return {}; return {};
} }

View file

@ -42,7 +42,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<TypeError>("object must be of type Date"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Date");
return nullptr; return nullptr;
} }
return static_cast<Date*>(this_object); return static_cast<Date*>(this_object);

View file

@ -54,7 +54,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<TypeError>("Not an Error object"); return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return js_string(interpreter, static_cast<const Error*>(this_object)->name()); return js_string(interpreter, static_cast<const Error*>(this_object)->name());
} }
@ -64,7 +64,7 @@ void ErrorPrototype::name_setter(Interpreter& interpreter, Value value)
if (!this_object) if (!this_object)
return; return;
if (!this_object->is_error()) { if (!this_object->is_error()) {
interpreter.throw_exception<TypeError>("Not an Error object"); interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
return; return;
} }
auto name = value.to_string(interpreter); auto name = value.to_string(interpreter);
@ -79,14 +79,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<TypeError>("Not an Error object"); return interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
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(interpreter.global_object()).is_object()) if (!interpreter.this_value(interpreter.global_object()).is_object())
return interpreter.throw_exception<TypeError>("Not an object"); return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, interpreter.this_value(interpreter.global_object()).to_string_without_side_effects().characters());
auto& this_object = interpreter.this_value(interpreter.global_object()).as_object(); auto& this_object = interpreter.this_value(interpreter.global_object()).as_object();
String name = "Error"; String name = "Error";

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <LibJS/Runtime/ErrorTypes.h>
namespace JS {
#define __ENUMERATE_JS_ERROR(name, message) \
const ErrorType ErrorType::name = ErrorType(message);
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
#undef __ENUMERATE_JS_ERROR
}

View file

@ -0,0 +1,172 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define JS_ENUMERATE_ERROR_TYPES(M) \
M(ArrayInvalidLength, "Invalid array length") \
M(ArrayMaxSize, "Maximum array size exceeded") \
M(ArrayPrototypeOneArg, "Array.prototype.%s() requires at least one argument") \
M(AccessorBadField, "Accessor descriptor's '%s' field must be a function or undefined") \
M(AccessorValueOrWritable, "Accessor property descriptor cannot specify a value or writable key") \
M(BigIntBadOperator, "Cannot use %s operator with BigInt") \
M(BigIntBadOperatorOtherType, "Cannot use %s operator with BigInt and other type") \
M(BigIntIntArgument, "BigInt argument must be an integer") \
M(BigIntInvalidValue, "Invalid value for BigInt: %s") \
M(Convert, "Cannot convert %s to %s") \
M(ConvertUndefinedToObject, "Cannot convert undefined to object") \
M(DescChangeNonConfigurable, "Cannot change attributes of non-configurable property '%s'") \
M(ForOfNotIterable, "for..of right-hand side must be iterable") \
M(FunctionArgsNotObject, "Argument array must be an object") \
M(InOperatorWithObject, "'in' operator must be used on an object") \
M(InstanceOfOperatorBadPrototype, "Prototype property of %s is not an object") \
M(InvalidAssignToConst, "Invalid assignment to const variable") \
M(InvalidLeftHandAssignment, "Invalid left-hand side in assignment") \
M(IsNotA, "%s is not a %s") \
M(IsNotAEvaluatedFrom, "%s is not a %s (evaluated from '%s')") \
M(NotA, "Not a %s object") \
M(NotACtor, "%s is not a constructor") \
M(NotAFunction, "%s is not a function") \
M(NotAFunctionNoParam, "Not a function") \
M(NotAn, "Not an %s object") \
M(NotAnObject, "%s is not an object") \
M(NotASymbol, "%s is not a symbol") \
M(NotIterable, "%s is not iterable") \
M(NonExtensibleDefine, "Cannot define property %s on non-extensible object") \
M(ObjectDefinePropertyReturnedFalse, "Object's [[DefineProperty]] method returned false") \
M(ObjectSetPrototypeOfReturnedFalse, "Object's [[SetPrototypeOf]] method returned false") \
M(ObjectSetPrototypeOfTwoArgs, "Object.setPrototypeOf requires at least two arguments") \
M(ObjectPreventExtensionsReturnedFalse, "Object's [[PreventExtensions]] method returned false") \
M(ObjectPrototypeWrongType, "Prototype must be an object or null") \
M(ProxyCallWithNew, "Proxy must be called with the 'new' operator") \
M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s") \
M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates " \
"invariant: a property cannot be defined as non-configurable if it already exists on the " \
"target object as a configurable property") \
M(ProxyDefinePropIncompatibleDescriptor, "Proxy handler's defineProperty trap violates " \
"invariant: the new descriptor is not compatible with the existing descriptor of the " \
"property on the target") \
M(ProxyDefinePropNonConfigurableNonExisting, "Proxy handler's defineProperty trap " \
"violates invariant: a property cannot be defined as non-configurable if it does not " \
"already exist on the target object") \
M(ProxyDefinePropNonExtensible, "Proxy handler's defineProperty trap violates invariant: " \
"a property cannot be reported as being defined if the property does not exist on " \
"the target and the target is non-extensible") \
M(ProxyDeleteNonConfigurable, "Proxy handler's deleteProperty trap violates invariant: " \
"cannot report a non-configurable own property of the target as deleted") \
M(ProxyGetImmutableDataProperty, "Proxy handler's get trap violates invariant: the " \
"returned value must match the value on the target if the property exists on the " \
"target as a non-writable, non-configurable own data property") \
M(ProxyGetNonConfigurableAccessor, "Proxy handler's get trap violates invariant: the " \
"returned value must be undefined if the property exists on the target as a " \
"non-configurable accessor property with an undefined get attribute") \
M(ProxyGetOwnDescriptorExistingConfigurable, "Proxy handler's getOwnPropertyDescriptor " \
"trap violates invariant: a property cannot be defined as non-configurable if it " \
"already exists on the target object as a configurable property") \
M(ProxyGetOwnDescriptorInvalidDescriptor, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: invalid property descriptor for existing property on the target") \
M(ProxyGetOwnDescriptorInvalidNonConfig, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot report target's property as non-configurable if the " \
"property does not exist, or if it is configurable") \
M(ProxyGetOwnDescriptorNonConfigurable, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot return undefined for a property on the target which is " \
"a non-configurable property") \
M(ProxyGetOwnDescriptorReturn, "Proxy handler's getOwnPropertyDescriptor trap violates " \
"invariant: must return an object or undefined") \
M(ProxyGetOwnDescriptorUndefReturn, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot report a property as being undefined if it exists as an " \
"own property of the target and the target is non-extensible") \
M(ProxyGetPrototypeOfNonExtensible, "Proxy handler's getPrototypeOf trap violates " \
"invariant: cannot return a different prototype object for a non-extensible target") \
M(ProxyGetPrototypeOfReturn, "Proxy handler's getPrototypeOf trap violates invariant: " \
"must return an object or null") \
M(ProxyHasExistingNonConfigurable, "Proxy handler's has trap violates invariant: a " \
"property cannot be reported as non-existent if it exists on the target as a " \
"non-configurable property") \
M(ProxyHasExistingNonExtensible, "Proxy handler's has trap violates invariant: a property " \
"cannot be reported as non-existent if it exists on the target and the target is " \
"non-extensible") \
M(ProxyInvalidTrap, "Proxy handler's %s trap wasn't undefined, null, or callable") \
M(ProxyIsExtensibleReturn, "Proxy handler's isExtensible trap violates invariant: " \
"return value must match the target's extensibility") \
M(ProxyPreventExtensionsReturn, "Proxy handler's preventExtensions trap violates " \
"invariant: cannot return true if the target object is extensible") \
M(ProxyRevoked, "An operation was performed on a revoked Proxy object") \
M(ProxySetImmutableDataProperty, "Proxy handler's set trap violates invariant: cannot " \
"return true for a property on the target which is a non-configurable, non-writable " \
"own data property") \
M(ProxySetNonConfigurableAccessor, "Proxy handler's set trap violates invariant: cannot " \
"return true for a property on the target which is a non-configurable own accessor " \
"property with an undefined set attribute") \
M(ProxySetPrototypeOfNonExtensible, "Proxy handler's setPrototypeOf trap violates " \
"invariant: the argument must match the prototype of the target if the " \
"target is non-extensible") \
M(ProxyTwoArguments, "Proxy constructor requires at least two arguments") \
M(ReduceNoInitial, "Reduce of empty array with no initial value") \
M(ReferencePrimitiveAssignment, "Cannot assign property %s to primitive value") \
M(ReferenceUnresolvable, "Unresolvable reference") \
M(ReflectArgumentMustBeAFunction, "First argument of Reflect.%s() must be a function") \
M(ReflectArgumentMustBeAnObject, "First argument of Reflect.%s() must be an object") \
M(ReflectBadArgumentsList, "Arguments list must be an object") \
M(ReflectBadNewTarget, "Optional third argument of Reflect.construct() must be a constructor") \
M(ReflectBadDescriptorArgument, "Descriptor argument is not an object") \
M(StringRawCannotConvert, "Cannot convert property 'raw' to object from %s") \
M(StringRepeatCountMustBe, "repeat count must be a %s number") \
M(ToObjectNullOrUndef, "ToObject on null or undefined") \
M(UnknownIdentifier, "'%s' is not defined") \
/* LibWeb bindings */ \
M(BadArgCountOne, "%s() needs one argument") \
M(BadArgCountAtLeastOne, "%s() needs at least one argument") \
M(BadArgCountMany, "%s() needs %s arguments") \
M(DrawImageArgumentCount, "drawImage() needs three arguments") \
M(FillBadWindingRule, "fill() winding rule must be either 'nonzero' or 'evenodd'") \
M(FillNonString, "fill() called with non-string") \
M(ImageIsAn, "Image is not an HTMLImageElement, it's an %s") \
M(PutImageDataBadCall, "putImageData() called with non-ImageData") \
namespace JS {
class ErrorType {
public:
#define __ENUMERATE_JS_ERROR(name, message) \
static const ErrorType name;
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
#undef __ENUMERATE_JS_ERROR
const char* message() const { return m_message; };
private:
explicit ErrorType(const char* message)
: m_message(message)
{
}
const char* m_message;
};
}

View file

@ -64,14 +64,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<TypeError>("Not a Function object"); return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
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>("argument array must be an object"); return interpreter.throw_exception<TypeError>(ErrorType::FunctionArgsNotObject);
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 {};
@ -94,7 +94,7 @@ Value FunctionPrototype::bind(Interpreter& interpreter)
if (!this_object) if (!this_object)
return {}; return {};
if (!this_object->is_function()) if (!this_object->is_function())
return interpreter.throw_exception<TypeError>("Not a Function object"); return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
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);
@ -114,7 +114,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<TypeError>("Not a Function object"); return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
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());
@ -131,7 +131,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<TypeError>("Not a Function object"); return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
String function_name = static_cast<Function*>(this_object)->name(); String function_name = static_cast<Function*>(this_object)->name();
String function_parameters = ""; String function_parameters = "";

View file

@ -352,7 +352,7 @@ bool Object::define_property(const FlyString& property_name, const Object& descr
if (is_accessor_property) { if (is_accessor_property) {
if (descriptor.has_property("value") || descriptor.has_property("writable")) { if (descriptor.has_property("value") || descriptor.has_property("writable")) {
if (throw_exceptions) if (throw_exceptions)
interpreter().throw_exception<TypeError>("Accessor property descriptors cannot specify a value or writable key"); interpreter().throw_exception<TypeError>(ErrorType::AccessorValueOrWritable);
return false; return false;
} }
@ -369,14 +369,14 @@ bool Object::define_property(const FlyString& property_name, const Object& descr
if (getter.is_function()) { if (getter.is_function()) {
getter_function = &getter.as_function(); getter_function = &getter.as_function();
} else if (!getter.is_undefined()) { } else if (!getter.is_undefined()) {
interpreter().throw_exception<TypeError>("Accessor descriptor's 'get' field must be a function or undefined"); interpreter().throw_exception<TypeError>(ErrorType::AccessorBadField, "get");
return false; return false;
} }
if (setter.is_function()) { if (setter.is_function()) {
setter_function = &setter.as_function(); setter_function = &setter.as_function();
} else if (!setter.is_undefined()) { } else if (!setter.is_undefined()) {
interpreter().throw_exception<TypeError>("Accessor descriptor's 'set' field must be a function or undefined"); interpreter().throw_exception<TypeError>(ErrorType::AccessorBadField, "set");
return false; return false;
} }
@ -424,7 +424,7 @@ bool Object::put_own_property(Object& this_object, const FlyString& property_nam
if (!is_extensible()) { if (!is_extensible()) {
dbg() << "Disallow define_property of non-extensible object"; dbg() << "Disallow define_property of non-extensible object";
if (throw_exceptions && interpreter().in_strict_mode()) if (throw_exceptions && interpreter().in_strict_mode())
interpreter().throw_exception<TypeError>(String::format("Cannot define property %s on non-extensible object", property_name.characters())); interpreter().throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_name.characters());
return false; return false;
} }
@ -459,7 +459,7 @@ bool Object::put_own_property(Object& this_object, const FlyString& property_nam
if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !metadata.value().attributes.is_configurable() && attributes != metadata.value().attributes) { if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !metadata.value().attributes.is_configurable() && attributes != metadata.value().attributes) {
dbg() << "Disallow reconfig of non-configurable property"; dbg() << "Disallow reconfig of non-configurable property";
if (throw_exceptions) if (throw_exceptions)
interpreter().throw_exception<TypeError>(String::format("Cannot change attributes of non-configurable property '%s'", property_name.characters())); interpreter().throw_exception<TypeError>(ErrorType::DescChangeNonConfigurable, property_name.characters());
return false; return false;
} }
@ -498,7 +498,7 @@ bool Object::put_own_property_by_index(Object& this_object, u32 property_index,
if (!is_extensible()) { if (!is_extensible()) {
dbg() << "Disallow define_property of non-extensible object"; dbg() << "Disallow define_property of non-extensible object";
if (throw_exceptions && interpreter().in_strict_mode()) if (throw_exceptions && interpreter().in_strict_mode())
interpreter().throw_exception<TypeError>(String::format("Cannot define property %d on non-extensible object", property_index)); interpreter().throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_index);
return false; return false;
} }
@ -517,7 +517,7 @@ bool Object::put_own_property_by_index(Object& this_object, u32 property_index,
if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !existing_attributes.is_configurable() && attributes != existing_attributes) { if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !existing_attributes.is_configurable() && attributes != existing_attributes) {
dbg() << "Disallow reconfig of non-configurable property"; dbg() << "Disallow reconfig of non-configurable property";
if (throw_exceptions) if (throw_exceptions)
interpreter().throw_exception<TypeError>(String::format("Cannot change attributes of non-configurable property %d", property_index)); interpreter().throw_exception<TypeError>(ErrorType::DescChangeNonConfigurable, property_index);
return false; return false;
} }
@ -778,7 +778,7 @@ Value Object::to_string() const
auto& interpreter = const_cast<Object*>(this)->interpreter(); auto& interpreter = const_cast<Object*>(this)->interpreter();
auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this)); auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this));
if (to_string_result.is_object()) if (to_string_result.is_object())
interpreter.throw_exception<TypeError>("Cannot convert object to string"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "object", "string");
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
auto* string = to_string_result.to_primitive_string(interpreter); auto* string = to_string_result.to_primitive_string(interpreter);
@ -796,7 +796,7 @@ Value Object::invoke(const FlyString& property_name, Optional<MarkedValueList> a
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (!property.is_function()) { if (!property.is_function()) {
interpreter.throw_exception<TypeError>(String::format("%s is not a function", property.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, property.to_string_without_side_effects().characters());
return {}; return {};
} }
return interpreter.call(property.as_function(), this, move(arguments)); return interpreter.call(property.as_function(), this, move(arguments));

View file

@ -98,7 +98,7 @@ Value ObjectConstructor::get_prototype_of(Interpreter& interpreter)
Value ObjectConstructor::set_prototype_of(Interpreter& interpreter) Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
{ {
if (interpreter.argument_count() < 2) if (interpreter.argument_count() < 2)
return interpreter.throw_exception<TypeError>("Object.setPrototypeOf requires at least two arguments"); return interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs);
auto* object = interpreter.argument(0).to_object(interpreter); auto* object = interpreter.argument(0).to_object(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -109,12 +109,12 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
} else if (prototype_value.is_object()) { } else if (prototype_value.is_object()) {
prototype = &prototype_value.as_object(); prototype = &prototype_value.as_object();
} else { } else {
interpreter.throw_exception<TypeError>("Prototype must be null or object"); interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeWrongType);
return {}; return {};
} }
if (!object->set_prototype(prototype)) { if (!object->set_prototype(prototype)) {
if (!interpreter.exception()) if (!interpreter.exception())
interpreter.throw_exception<TypeError>("Object's setPrototypeOf method returned false"); interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfReturnedFalse);
return {}; return {};
} }
return object; return object;
@ -135,7 +135,7 @@ Value ObjectConstructor::prevent_extensions(Interpreter& interpreter)
return argument; return argument;
if (!argument.as_object().prevent_extensions()) { if (!argument.as_object().prevent_extensions()) {
if (!interpreter.exception()) if (!interpreter.exception())
interpreter.throw_exception<TypeError>("Proxy preventExtensions handler returned false"); interpreter.throw_exception<TypeError>(ErrorType::ObjectPreventExtensionsReturnedFalse);
return {}; return {};
} }
return argument; return argument;
@ -155,9 +155,9 @@ Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
Value ObjectConstructor::define_property_(Interpreter& interpreter) Value ObjectConstructor::define_property_(Interpreter& interpreter)
{ {
if (!interpreter.argument(0).is_object()) if (!interpreter.argument(0).is_object())
return interpreter.throw_exception<TypeError>("Object argument is not an object"); return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument");
if (!interpreter.argument(2).is_object()) if (!interpreter.argument(2).is_object())
return interpreter.throw_exception<TypeError>("Descriptor argument is not an object"); return interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument");
auto& object = interpreter.argument(0).as_object(); auto& object = interpreter.argument(0).as_object();
auto property_key = interpreter.argument(1).to_string(interpreter); auto property_key = interpreter.argument(1).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
@ -166,9 +166,9 @@ Value ObjectConstructor::define_property_(Interpreter& interpreter)
if (!object.define_property(property_key, descriptor)) { if (!object.define_property(property_key, descriptor)) {
if (!interpreter.exception()) { if (!interpreter.exception()) {
if (object.is_proxy_object()) { if (object.is_proxy_object()) {
interpreter.throw_exception<TypeError>("Proxy handler's defineProperty method returned false"); interpreter.throw_exception<TypeError>(ErrorType::ObjectDefinePropertyReturnedFalse);
} else { } else {
interpreter.throw_exception<TypeError>("Unable to define property on non-extensible object"); interpreter.throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_key.characters());
} }
} }
return {}; return {};
@ -184,7 +184,7 @@ Value ObjectConstructor::is(Interpreter& interpreter)
Value ObjectConstructor::keys(Interpreter& interpreter) Value ObjectConstructor::keys(Interpreter& interpreter)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>("Can't convert undefined to object"); return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
auto* obj_arg = interpreter.argument(0).to_object(interpreter); auto* obj_arg = interpreter.argument(0).to_object(interpreter);
if (interpreter.exception()) if (interpreter.exception())
@ -196,7 +196,7 @@ Value ObjectConstructor::keys(Interpreter& interpreter)
Value ObjectConstructor::values(Interpreter& interpreter) Value ObjectConstructor::values(Interpreter& interpreter)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>("Can't convert undefined to object"); return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
auto* obj_arg = interpreter.argument(0).to_object(interpreter); auto* obj_arg = interpreter.argument(0).to_object(interpreter);
if (interpreter.exception()) if (interpreter.exception())
@ -208,7 +208,7 @@ Value ObjectConstructor::values(Interpreter& interpreter)
Value ObjectConstructor::entries(Interpreter& interpreter) Value ObjectConstructor::entries(Interpreter& interpreter)
{ {
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<TypeError>("Can't convert undefined to object"); return interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
auto* obj_arg = interpreter.argument(0).to_object(interpreter); auto* obj_arg = interpreter.argument(0).to_object(interpreter);
if (interpreter.exception()) if (interpreter.exception())

View file

@ -46,21 +46,21 @@ ProxyConstructor::~ProxyConstructor()
Value ProxyConstructor::call(Interpreter& interpreter) Value ProxyConstructor::call(Interpreter& interpreter)
{ {
return interpreter.throw_exception<TypeError>("Proxy must be called with the \"new\" operator"); return interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
} }
Value ProxyConstructor::construct(Interpreter& interpreter) Value ProxyConstructor::construct(Interpreter& interpreter)
{ {
if (interpreter.argument_count() < 2) if (interpreter.argument_count() < 2)
return interpreter.throw_exception<TypeError>("Proxy requires at least two arguments"); return interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
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>(String::format("Expected target argument of Proxy constructor to be object, got %s", target.to_string_without_side_effects().characters())); return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects().characters());
if (!handler.is_object()) if (!handler.is_object())
return interpreter.throw_exception<TypeError>(String::format("Expected handler argument of Proxy constructor to be object, got %s", handler.to_string_without_side_effects().characters())); return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects().characters());
return ProxyObject::create(global_object(), target.as_object(), handler.as_object()); return ProxyObject::create(global_object(), target.as_object(), handler.as_object());
} }

View file

@ -76,7 +76,7 @@ ProxyObject::~ProxyObject()
Object* ProxyObject::prototype() Object* ProxyObject::prototype()
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return nullptr; return nullptr;
} }
auto trap = m_handler.get("getPrototypeOf"); auto trap = m_handler.get("getPrototypeOf");
@ -85,7 +85,7 @@ Object* ProxyObject::prototype()
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.prototype(); return m_target.prototype();
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's getPrototypeOf trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getPrototypeOf");
return nullptr; return nullptr;
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -94,7 +94,7 @@ Object* ProxyObject::prototype()
if (interpreter().exception()) if (interpreter().exception())
return nullptr; return nullptr;
if (!trap_result.is_object() && !trap_result.is_null()) { if (!trap_result.is_object() && !trap_result.is_null()) {
interpreter().throw_exception<TypeError>("Proxy handler's getPrototypeOf trap violates invariant: must return an object or null"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetPrototypeOfReturn);
return nullptr; return nullptr;
} }
if (m_target.is_extensible()) { if (m_target.is_extensible()) {
@ -108,7 +108,7 @@ Object* ProxyObject::prototype()
if (interpreter().exception()) if (interpreter().exception())
return nullptr; return nullptr;
if (!same_value(interpreter(), trap_result, Value(target_proto))) { if (!same_value(interpreter(), trap_result, Value(target_proto))) {
interpreter().throw_exception<TypeError>("Proxy handler's getPrototypeOf trap violates invariant: cannot return a different prototype object for a non-extensible target"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetPrototypeOfNonExtensible);
return nullptr; return nullptr;
} }
return &trap_result.as_object(); return &trap_result.as_object();
@ -117,7 +117,7 @@ Object* ProxyObject::prototype()
const Object* ProxyObject::prototype() const const Object* ProxyObject::prototype() const
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return nullptr; return nullptr;
} }
return const_cast<const Object*>(const_cast<ProxyObject*>(this)->prototype()); return const_cast<const Object*>(const_cast<ProxyObject*>(this)->prototype());
@ -126,7 +126,7 @@ const Object* ProxyObject::prototype() const
bool ProxyObject::set_prototype(Object* object) bool ProxyObject::set_prototype(Object* object)
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("setPrototypeOf"); auto trap = m_handler.get("setPrototypeOf");
@ -135,7 +135,7 @@ bool ProxyObject::set_prototype(Object* object)
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.set_prototype(object); return m_target.set_prototype(object);
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's setPrototypeOf trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "setPrototypeOf");
return false; return false;
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -150,7 +150,7 @@ bool ProxyObject::set_prototype(Object* object)
if (interpreter().exception()) if (interpreter().exception())
return false; return false;
if (!same_value(interpreter(), Value(object), Value(target_proto))) { if (!same_value(interpreter(), Value(object), Value(target_proto))) {
interpreter().throw_exception<TypeError>("Proxy handler's setPrototypeOf trap violates invariant: the argument must match the prototype of the target if the target is non-extensible"); interpreter().throw_exception<TypeError>(ErrorType::ProxySetPrototypeOfNonExtensible);
return false; return false;
} }
return true; return true;
@ -159,7 +159,7 @@ bool ProxyObject::set_prototype(Object* object)
bool ProxyObject::is_extensible() const bool ProxyObject::is_extensible() const
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("isExtensible"); auto trap = m_handler.get("isExtensible");
@ -168,7 +168,7 @@ bool ProxyObject::is_extensible() const
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.is_extensible(); return m_target.is_extensible();
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's isExtensible trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "isExtensible");
return {}; return {};
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -178,7 +178,7 @@ bool ProxyObject::is_extensible() const
return false; return false;
if (trap_result != m_target.is_extensible()) { if (trap_result != m_target.is_extensible()) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's isExtensible trap violates invariant: return value must match the target's extensibility"); interpreter().throw_exception<TypeError>(ErrorType::ProxyIsExtensibleReturn);
return false; return false;
} }
return trap_result; return trap_result;
@ -187,7 +187,7 @@ bool ProxyObject::is_extensible() const
bool ProxyObject::prevent_extensions() bool ProxyObject::prevent_extensions()
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("preventExtensions"); auto trap = m_handler.get("preventExtensions");
@ -196,7 +196,7 @@ bool ProxyObject::prevent_extensions()
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.prevent_extensions(); return m_target.prevent_extensions();
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's preventExtensions trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "preventExtensions");
return {}; return {};
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -206,7 +206,7 @@ bool ProxyObject::prevent_extensions()
return false; return false;
if (trap_result && m_target.is_extensible()) { if (trap_result && m_target.is_extensible()) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's preventExtensions trap violates invariant: cannot return true if the target object is extensible"); interpreter().throw_exception<TypeError>(ErrorType::ProxyPreventExtensionsReturn);
return false; return false;
} }
return trap_result; return trap_result;
@ -215,7 +215,7 @@ bool ProxyObject::prevent_extensions()
Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyName name) const Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyName name) const
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return {}; return {};
} }
auto trap = m_handler.get("getOwnPropertyDescriptor"); auto trap = m_handler.get("getOwnPropertyDescriptor");
@ -224,7 +224,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.get_own_property_descriptor(name); return m_target.get_own_property_descriptor(name);
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getOwnPropertyDescriptor");
return {}; return {};
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -234,7 +234,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa
if (interpreter().exception()) if (interpreter().exception())
return {}; return {};
if (!trap_result.is_object() && !trap_result.is_undefined()) { if (!trap_result.is_object() && !trap_result.is_undefined()) {
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: must return an object or undefined"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorReturn);
return {}; return {};
} }
auto target_desc = m_target.get_own_property_descriptor(name); auto target_desc = m_target.get_own_property_descriptor(name);
@ -244,12 +244,12 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa
if (!target_desc.has_value()) if (!target_desc.has_value())
return {}; return {};
if (!target_desc.value().attributes.is_configurable()) { if (!target_desc.value().attributes.is_configurable()) {
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot return undefined for a property on the target which is a non-configurable property"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorNonConfigurable);
return {}; return {};
} }
if (!m_target.is_extensible()) { if (!m_target.is_extensible()) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report a property as being undefined if it exists as an own property of the target and the target is non-extensible"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorUndefReturn);
return {}; return {};
} }
return {}; return {};
@ -259,11 +259,11 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa
return {}; return {};
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), result_desc, target_desc)) { if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), result_desc, target_desc)) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorInvalidDescriptor);
return {}; return {};
} }
if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) { if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) {
interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report target's property as non-configurable if the property does not exist, or if it is configurable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorInvalidNonConfig);
return {}; return {};
} }
return result_desc; return result_desc;
@ -272,7 +272,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa
bool ProxyObject::define_property(const FlyString& property_name, const Object& descriptor, bool throw_exceptions) bool ProxyObject::define_property(const FlyString& property_name, const Object& descriptor, bool throw_exceptions)
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("defineProperty"); auto trap = m_handler.get("defineProperty");
@ -281,7 +281,7 @@ bool ProxyObject::define_property(const FlyString& property_name, const Object&
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.define_property(property_name, descriptor, throw_exceptions); return m_target.define_property(property_name, descriptor, throw_exceptions);
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "defineProperty");
return false; return false;
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -302,21 +302,21 @@ bool ProxyObject::define_property(const FlyString& property_name, const Object&
if (!target_desc.has_value()) { if (!target_desc.has_value()) {
if (!m_target.is_extensible()) { if (!m_target.is_extensible()) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: a property cannot be reported as being defined if the property does not exist on the target and the target is non-extensible"); interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropNonExtensible);
return false; return false;
} }
if (setting_config_false) { if (setting_config_false) {
interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it does not already exist on the target object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropNonConfigurableNonExisting);
return false; return false;
} }
} else { } else {
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), PropertyDescriptor::from_dictionary(interpreter(), descriptor), target_desc)) { if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), PropertyDescriptor::from_dictionary(interpreter(), descriptor), target_desc)) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: the new descriptor is not compatible with the existing descriptor of the property on the target"); interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropIncompatibleDescriptor);
return false; return false;
} }
if (setting_config_false && target_desc.value().attributes.is_configurable()) { if (setting_config_false && target_desc.value().attributes.is_configurable()) {
interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it already exists on the target object as a configurable property"); interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropExistingConfigurable);
return false; return false;
} }
} }
@ -326,7 +326,7 @@ bool ProxyObject::define_property(const FlyString& property_name, const Object&
bool ProxyObject::has_property(PropertyName name) const bool ProxyObject::has_property(PropertyName name) const
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("has"); auto trap = m_handler.get("has");
@ -335,7 +335,7 @@ bool ProxyObject::has_property(PropertyName name) const
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.has_property(name); return m_target.has_property(name);
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's has trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "has");
return false; return false;
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -350,12 +350,12 @@ bool ProxyObject::has_property(PropertyName name) const
return false; return false;
if (target_desc.has_value()) { if (target_desc.has_value()) {
if (!target_desc.value().attributes.is_configurable()) { if (!target_desc.value().attributes.is_configurable()) {
interpreter().throw_exception<TypeError>("Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exists on the target as a non-configurable property"); interpreter().throw_exception<TypeError>(ErrorType::ProxyHasExistingNonConfigurable);
return false; return false;
} }
if (!m_target.is_extensible()) { if (!m_target.is_extensible()) {
if (!interpreter().exception()) if (!interpreter().exception())
interpreter().throw_exception<TypeError>("Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exist on the target and the target is non-extensible"); interpreter().throw_exception<TypeError>(ErrorType::ProxyHasExistingNonExtensible);
return false; return false;
} }
} }
@ -366,7 +366,7 @@ bool ProxyObject::has_property(PropertyName name) const
Value ProxyObject::get(PropertyName name) const Value ProxyObject::get(PropertyName name) const
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return {}; return {};
} }
auto trap = m_handler.get("get"); auto trap = m_handler.get("get");
@ -375,7 +375,7 @@ Value ProxyObject::get(PropertyName name) const
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>("Proxy handler's get trap wasn't undefined, null, or callable"); return interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "get");
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
arguments.values().append(Value(&m_target)); arguments.values().append(Value(&m_target));
arguments.values().append(js_string(interpreter(), name.to_string())); arguments.values().append(js_string(interpreter(), name.to_string()));
@ -388,9 +388,9 @@ Value ProxyObject::get(PropertyName name) const
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>("Proxy handler's get trap violates invariant: the returned value must match the value on the target if the property exists on the target as a non-writable, non-configurable own data property"); return interpreter().throw_exception<TypeError>(ErrorType::ProxyGetImmutableDataProperty);
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined()) if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined())
return interpreter().throw_exception<TypeError>("Proxy handler's get trap violates invariant: the returned value must be undefined if the property exists on the target as a non-configurable accessor property with an undefined get attribute"); return interpreter().throw_exception<TypeError>(ErrorType::ProxyGetNonConfigurableAccessor);
} }
return trap_result; return trap_result;
} }
@ -398,7 +398,7 @@ Value ProxyObject::get(PropertyName name) const
bool ProxyObject::put(PropertyName name, Value value) bool ProxyObject::put(PropertyName name, Value value)
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return false; return false;
} }
auto trap = m_handler.get("set"); auto trap = m_handler.get("set");
@ -407,7 +407,7 @@ bool ProxyObject::put(PropertyName name, Value value)
if (trap.is_empty() || trap.is_undefined() || trap.is_null()) if (trap.is_empty() || trap.is_undefined() || trap.is_null())
return m_target.put(name, value); return m_target.put(name, value);
if (!trap.is_function()) { if (!trap.is_function()) {
interpreter().throw_exception<TypeError>("Proxy handler's set trap wasn't undefined, null, or callable"); interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "set");
return false; return false;
} }
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
@ -423,11 +423,11 @@ bool ProxyObject::put(PropertyName name, Value value)
return false; return false;
if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) { if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) {
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), value, target_desc.value().value)) { if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), value, target_desc.value().value)) {
interpreter().throw_exception<TypeError>("Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable, non-writable own data property"); interpreter().throw_exception<TypeError>(ErrorType::ProxySetImmutableDataProperty);
return false; return false;
} }
if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) { if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) {
interpreter().throw_exception<TypeError>("Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable own accessor property with an undefined set attribute"); interpreter().throw_exception<TypeError>(ErrorType::ProxySetNonConfigurableAccessor);
} }
} }
return true; return true;
@ -436,7 +436,7 @@ bool ProxyObject::put(PropertyName name, Value value)
Value ProxyObject::delete_property(PropertyName name) Value ProxyObject::delete_property(PropertyName name)
{ {
if (m_is_revoked) { if (m_is_revoked) {
interpreter().throw_exception<TypeError>("An operation was performed on a revoked Proxy object"); interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
return {}; return {};
} }
auto trap = m_handler.get("deleteProperty"); auto trap = m_handler.get("deleteProperty");
@ -445,7 +445,7 @@ Value ProxyObject::delete_property(PropertyName name)
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>("Proxy handler's delete trap wasn't undefined, null, or callable"); return interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "deleteProperty");
MarkedValueList arguments(interpreter().heap()); MarkedValueList arguments(interpreter().heap());
arguments.values().append(Value(&m_target)); arguments.values().append(Value(&m_target));
arguments.values().append(js_string(interpreter(), name.to_string())); arguments.values().append(js_string(interpreter(), name.to_string()));
@ -460,7 +460,7 @@ Value ProxyObject::delete_property(PropertyName name)
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>("Proxy handler's delete trap violates invariant: cannot report a non-configurable own property of the target as deleted"); return interpreter().throw_exception<TypeError>(ErrorType::ProxyDeleteNonConfigurable);
return Value(true); return Value(true);
} }

View file

@ -51,7 +51,7 @@ void Reference::put(Interpreter& interpreter, Value value)
} }
if (!base().is_object() && interpreter.in_strict_mode()) { if (!base().is_object() && interpreter.in_strict_mode()) {
interpreter.throw_exception<TypeError>(String::format("Can't assign property %s to primitive value", m_name.to_string().characters())); interpreter.throw_exception<TypeError>(ErrorType::ReferencePrimitiveAssignment, m_name.to_string().characters());
return; return;
} }
@ -66,11 +66,11 @@ void Reference::throw_reference_error(Interpreter& interpreter)
{ {
auto property_name = m_name.to_string(); auto property_name = m_name.to_string();
String message; String message;
if (property_name.is_empty()) if (property_name.is_empty()) {
message = "Unresolvable reference"; interpreter.throw_exception<ReferenceError>(ErrorType::ReferenceUnresolvable);
else } else {
message = String::format("'%s' not known", property_name.characters()); interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, property_name.characters());
interpreter.throw_exception<ReferenceError>(message); }
} }
Value Reference::get(Interpreter& interpreter) Value Reference::get(Interpreter& interpreter)

View file

@ -38,7 +38,7 @@ static Object* get_target_object_from(Interpreter& interpreter, const String& na
{ {
auto target = interpreter.argument(0); auto target = interpreter.argument(0);
if (!target.is_object()) { if (!target.is_object()) {
interpreter.throw_exception<TypeError>(String::format("First argument of Reflect.%s() must be an object", name.characters())); interpreter.throw_exception<TypeError>(ErrorType::ReflectArgumentMustBeAnObject, name.characters());
return nullptr; return nullptr;
} }
return static_cast<Object*>(&target.as_object()); return static_cast<Object*>(&target.as_object());
@ -48,7 +48,7 @@ static Function* get_target_function_from(Interpreter& interpreter, const String
{ {
auto target = interpreter.argument(0); auto target = interpreter.argument(0);
if (!target.is_function()) { if (!target.is_function()) {
interpreter.throw_exception<TypeError>(String::format("First argument of Reflect.%s() must be a function", name.characters())); interpreter.throw_exception<TypeError>(ErrorType::ReflectArgumentMustBeAFunction, name.characters());
return nullptr; return nullptr;
} }
return &target.as_function(); return &target.as_function();
@ -57,7 +57,7 @@ static Function* get_target_function_from(Interpreter& interpreter, const String
static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments) static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments)
{ {
if (!value.is_object()) { if (!value.is_object()) {
interpreter.throw_exception<TypeError>("Arguments list must be an object"); interpreter.throw_exception<TypeError>(ErrorType::ReflectBadArgumentsList);
return; return;
} }
auto& arguments_list = value.as_object(); auto& arguments_list = value.as_object();
@ -125,7 +125,7 @@ Value ReflectObject::construct(Interpreter& interpreter)
auto new_target_value = interpreter.argument(2); auto new_target_value = interpreter.argument(2);
if (!new_target_value.is_function() if (!new_target_value.is_function()
|| (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) { || (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
interpreter.throw_exception<TypeError>("Optional third argument of Reflect.construct() must be a constructor"); interpreter.throw_exception<TypeError>(ErrorType::ReflectBadNewTarget);
return {}; return {};
} }
new_target = &new_target_value.as_function(); new_target = &new_target_value.as_function();
@ -139,7 +139,7 @@ Value ReflectObject::define_property(Interpreter& interpreter)
if (!target) if (!target)
return {}; return {};
if (!interpreter.argument(2).is_object()) if (!interpreter.argument(2).is_object())
return interpreter.throw_exception<TypeError>("Descriptor argument is not an object"); return interpreter.throw_exception<TypeError>(ErrorType::ReflectBadDescriptorArgument);
auto property_key = interpreter.argument(1).to_string(interpreter); auto property_key = interpreter.argument(1).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -257,7 +257,7 @@ Value ReflectObject::set_prototype_of(Interpreter& interpreter)
return {}; return {};
auto prototype_value = interpreter.argument(1); auto prototype_value = interpreter.argument(1);
if (!prototype_value.is_object() && !prototype_value.is_null()) { if (!prototype_value.is_object() && !prototype_value.is_null()) {
interpreter.throw_exception<TypeError>("Prototype must be an object or null"); interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeWrongType);
return {}; return {};
} }
Object* prototype = nullptr; Object* prototype = nullptr;

View file

@ -41,7 +41,7 @@ static ScriptFunction* script_function_from(Interpreter& interpreter)
if (!this_object) if (!this_object)
return nullptr; return nullptr;
if (!this_object->is_function()) { if (!this_object->is_function()) {
interpreter.throw_exception<TypeError>("Not a function"); interpreter.throw_exception<TypeError>(ErrorType::NotAFunctionNoParam);
return nullptr; return nullptr;
} }
return static_cast<ScriptFunction*>(this_object); return static_cast<ScriptFunction*>(this_object);
@ -126,7 +126,7 @@ Value ScriptFunction::call(Interpreter& interpreter)
Value ScriptFunction::construct(Interpreter& interpreter) Value ScriptFunction::construct(Interpreter& interpreter)
{ {
if (m_is_arrow_function) if (m_is_arrow_function)
return interpreter.throw_exception<TypeError>(String::format("%s is not a constructor", m_name.characters())); return interpreter.throw_exception<TypeError>(ErrorType::NotACtor, m_name.characters());
return call(interpreter); return call(interpreter);
} }

View file

@ -82,7 +82,7 @@ Value StringConstructor::raw(Interpreter& interpreter)
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
if (raw.is_empty() || raw.is_undefined() || raw.is_null()) { if (raw.is_empty() || raw.is_undefined() || raw.is_null()) {
interpreter.throw_exception<TypeError>(String::format("Cannot convert property 'raw' to object from %s", raw.is_null() ? "null" : "undefined")); interpreter.throw_exception<TypeError>(ErrorType::StringRawCannotConvert, raw.is_null() ? "null" : "undefined");
return {}; return {};
} }
if (!raw.is_array()) if (!raw.is_array())

View file

@ -45,7 +45,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<TypeError>("Not a String object"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "String");
return nullptr; return nullptr;
} }
return static_cast<StringObject*>(this_object); return static_cast<StringObject*>(this_object);
@ -115,9 +115,9 @@ Value StringPrototype::repeat(Interpreter& 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>("repeat count must be a positive number"); return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
if (count_value.is_infinity()) if (count_value.is_infinity())
return interpreter.throw_exception<RangeError>("repeat count must be a finite number"); return interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
auto count = count_value.to_size_t(interpreter); auto count = count_value.to_size_t(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

@ -71,7 +71,7 @@ Value SymbolConstructor::call(Interpreter& interpreter)
Value SymbolConstructor::construct(Interpreter& interpreter) Value SymbolConstructor::construct(Interpreter& interpreter)
{ {
interpreter.throw_exception<TypeError>("Symbol is not a constructor"); interpreter.throw_exception<TypeError>(ErrorType::NotACtor, "Symbol");
return {}; return {};
} }
@ -91,7 +91,7 @@ Value SymbolConstructor::key_for(Interpreter& interpreter)
{ {
auto argument = interpreter.argument(0); auto argument = interpreter.argument(0);
if (!argument.is_symbol()) { if (!argument.is_symbol()) {
interpreter.throw_exception<TypeError>(String::format("%s is not a symbol", argument.to_string_without_side_effects().characters())); interpreter.throw_exception<TypeError>(ErrorType::NotASymbol, argument.to_string_without_side_effects().characters());
return {}; return {};
} }

View file

@ -58,7 +58,7 @@ static SymbolObject* this_symbol_from_interpreter(Interpreter& interpreter)
if (!this_object) if (!this_object)
return nullptr; return nullptr;
if (!this_object->is_symbol_object()) { if (!this_object->is_symbol_object()) {
interpreter.throw_exception<TypeError>("object must be of type Symbol"); interpreter.throw_exception<TypeError>(ErrorType::NotA, "Symbol");
return nullptr; return nullptr;
} }
return static_cast<SymbolObject*>(this_object); return static_cast<SymbolObject*>(this_object);

View file

@ -59,7 +59,7 @@ Value Uint8ClampedArray::length_getter(Interpreter& interpreter)
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>("Not a Uint8ClampedArray"); return interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray");
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length()); return Value(static_cast<const Uint8ClampedArray*>(this_object)->length());
} }

View file

@ -154,7 +154,7 @@ String Value::to_string(Interpreter& interpreter) const
case Type::String: case Type::String:
return m_value.as_string->string(); return m_value.as_string->string();
case Type::Symbol: case Type::Symbol:
interpreter.throw_exception<TypeError>("Can't convert symbol to string"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "string");
return {}; return {};
case Type::BigInt: case Type::BigInt:
return m_value.as_bigint->big_integer().to_base10(); return m_value.as_bigint->big_integer().to_base10();
@ -206,7 +206,7 @@ Object* Value::to_object(Interpreter& interpreter) const
switch (m_type) { switch (m_type) {
case Type::Undefined: case Type::Undefined:
case Type::Null: case Type::Null:
interpreter.throw_exception<TypeError>("ToObject on null or undefined."); interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
return nullptr; return nullptr;
case Type::Boolean: case Type::Boolean:
return BooleanObject::create(interpreter.global_object(), m_value.as_bool); return BooleanObject::create(interpreter.global_object(), m_value.as_bool);
@ -262,10 +262,10 @@ Value Value::to_number(Interpreter& interpreter) const
return Value(parsed_double); return Value(parsed_double);
} }
case Type::Symbol: case Type::Symbol:
interpreter.throw_exception<TypeError>("Can't convert symbol to number"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "number");
return {}; return {};
case Type::BigInt: case Type::BigInt:
interpreter.throw_exception<TypeError>("Can't convert BigInt to number"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "BigInt", "number");
return {}; return {};
case Type::Object: { case Type::Object: {
auto primitive = m_value.as_object->to_primitive(PreferredType::Number); auto primitive = m_value.as_object->to_primitive(PreferredType::Number);
@ -285,10 +285,10 @@ BigInt* Value::to_bigint(Interpreter& interpreter) const
return nullptr; return nullptr;
switch (primitive.type()) { switch (primitive.type()) {
case Type::Undefined: case Type::Undefined:
interpreter.throw_exception<TypeError>("Can't convert undefined to BigInt"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "undefined", "BigInt");
return nullptr; return nullptr;
case Type::Null: case Type::Null:
interpreter.throw_exception<TypeError>("Can't convert null to BigInt"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "null", "BigInt");
return nullptr; return nullptr;
case Type::Boolean: { case Type::Boolean: {
auto value = primitive.as_bool() ? 1 : 0; auto value = primitive.as_bool() ? 1 : 0;
@ -297,18 +297,18 @@ BigInt* Value::to_bigint(Interpreter& interpreter) const
case Type::BigInt: case Type::BigInt:
return &primitive.as_bigint(); return &primitive.as_bigint();
case Type::Number: case Type::Number:
interpreter.throw_exception<TypeError>("Can't convert number to BigInt"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "number", "BigInt");
return {}; return {};
case Type::String: { case Type::String: {
auto& string = primitive.as_string().string(); auto& string = primitive.as_string().string();
if (!is_valid_bigint_value(string)) { if (!is_valid_bigint_value(string)) {
interpreter.throw_exception<SyntaxError>(String::format("Invalid value for BigInt: %s", string.characters())); interpreter.throw_exception<SyntaxError>(ErrorType::BigIntInvalidValue, string.characters());
return {}; return {};
} }
return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace())); return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace()));
} }
case Type::Symbol: case Type::Symbol:
interpreter.throw_exception<TypeError>("Can't convert symbol to BigInt"); interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "BigInt");
return {}; return {};
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -404,7 +404,7 @@ Value bitwise_and(Interpreter& interpreter, Value lhs, Value rhs)
return Value((i32)lhs_numeric.as_double() & (i32)rhs_numeric.as_double()); return Value((i32)lhs_numeric.as_double() & (i32)rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use bitwise AND operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise AND");
return {}; return {};
} }
@ -427,7 +427,7 @@ Value bitwise_or(Interpreter& interpreter, Value lhs, Value rhs)
} }
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use bitwise OR operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise OR");
return {}; return {};
} }
@ -443,7 +443,7 @@ Value bitwise_xor(Interpreter& interpreter, Value lhs, Value rhs)
return Value((i32)lhs_numeric.as_double() ^ (i32)rhs_numeric.as_double()); return Value((i32)lhs_numeric.as_double() ^ (i32)rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use bitwise XOR operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise XOR");
return {}; return {};
} }
@ -499,7 +499,7 @@ Value left_shift(Interpreter& interpreter, Value lhs, Value rhs)
} }
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
TODO(); TODO();
interpreter.throw_exception<TypeError>("Can't use left-shift operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "left-shift");
return {}; return {};
} }
@ -520,7 +520,7 @@ Value right_shift(Interpreter& interpreter, Value lhs, Value rhs)
} }
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
TODO(); TODO();
interpreter.throw_exception<TypeError>("Can't use right-shift operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "right-shift");
return {}; return {};
} }
@ -539,7 +539,7 @@ Value unsigned_right_shift(Interpreter& interpreter, Value lhs, Value rhs)
return lhs_numeric; return lhs_numeric;
return Value((unsigned)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double()); return Value((unsigned)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double());
} }
interpreter.throw_exception<TypeError>("Can't use unsigned right-shift operator with BigInt"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperator, "unsigned right-shift");
return {}; return {};
} }
@ -575,7 +575,7 @@ Value add(Interpreter& interpreter, Value lhs, Value rhs)
return Value(lhs_numeric.as_double() + rhs_numeric.as_double()); return Value(lhs_numeric.as_double() + rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().plus(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().plus(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use addition operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "addition");
return {}; return {};
} }
@ -591,7 +591,7 @@ Value sub(Interpreter& interpreter, Value lhs, Value rhs)
return Value(lhs_numeric.as_double() - rhs_numeric.as_double()); return Value(lhs_numeric.as_double() - rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().minus(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().minus(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use subtraction operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "subtraction");
return {}; return {};
} }
@ -607,7 +607,7 @@ Value mul(Interpreter& interpreter, Value lhs, Value rhs)
return Value(lhs_numeric.as_double() * rhs_numeric.as_double()); return Value(lhs_numeric.as_double() * rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().multiplied_by(rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().multiplied_by(rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use multiplication operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "multiplication");
return {}; return {};
} }
@ -623,7 +623,7 @@ Value div(Interpreter& interpreter, Value lhs, Value rhs)
return Value(lhs_numeric.as_double() / rhs_numeric.as_double()); return Value(lhs_numeric.as_double() / rhs_numeric.as_double());
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient);
interpreter.throw_exception<TypeError>("Can't use division operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "division");
return {}; return {};
} }
@ -645,7 +645,7 @@ Value mod(Interpreter& interpreter, Value lhs, Value rhs)
} }
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder); return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder);
interpreter.throw_exception<TypeError>("Can't use modulo operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo");
return {}; return {};
} }
@ -661,14 +661,14 @@ Value exp(Interpreter& interpreter, Value lhs, Value rhs)
return Value(pow(lhs_numeric.as_double(), rhs_numeric.as_double())); return Value(pow(lhs_numeric.as_double(), rhs_numeric.as_double()));
if (both_bigint(lhs_numeric, rhs_numeric)) if (both_bigint(lhs_numeric, rhs_numeric))
return js_bigint(interpreter, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer())); return js_bigint(interpreter, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer()));
interpreter.throw_exception<TypeError>("Can't use exponentiation operator with BigInt and other type"); interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation");
return {}; return {};
} }
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>("'in' operator must be used on object"); return interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject);
auto lhs_string = lhs.to_string(interpreter); auto lhs_string = lhs.to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

@ -33,8 +33,8 @@ try {
}, { }, {
error: TypeError, error: TypeError,
message: typeof value === "symbol" message: typeof value === "symbol"
? "Can't convert symbol to BigInt" ? "Cannot convert symbol to BigInt"
: `Can't convert ${value} to BigInt` : `Cannot convert ${value} to BigInt`
}); });
}); });

View file

@ -12,7 +12,7 @@ try {
Boolean.prototype.toString.call("foo"); Boolean.prototype.toString.call("foo");
}, { }, {
error: TypeError, error: TypeError,
message: "Not a Boolean" message: "Not a Boolean object"
}); });
console.log("PASS"); console.log("PASS");

View file

@ -12,7 +12,7 @@ try {
Boolean.prototype.valueOf.call("foo"); Boolean.prototype.valueOf.call("foo");
}, { }, {
error: TypeError, error: TypeError,
message: "Not a Boolean" message: "Not a Boolean object"
}); });
console.log("PASS"); console.log("PASS");

View file

@ -104,7 +104,7 @@ try {
}); });
}, { }, {
error: TypeError, error: TypeError,
message: "Accessor property descriptors cannot specify a value or writable key", message: "Accessor property descriptor cannot specify a value or writable key",
}); });
assertThrowsError(() => { assertThrowsError(() => {
@ -114,7 +114,7 @@ try {
}); });
}, { }, {
error: TypeError, error: TypeError,
message: "Accessor property descriptors cannot specify a value or writable key", message: "Accessor property descriptor cannot specify a value or writable key",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -13,14 +13,14 @@ try {
Object.entries(null); Object.entries(null);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
assertThrowsError(() => { assertThrowsError(() => {
Object.entries(undefined); Object.entries(undefined);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
let entries = Object.entries({ foo: 1, bar: 2, baz: 3 }); let entries = Object.entries({ foo: 1, bar: 2, baz: 3 });

View file

@ -13,14 +13,14 @@ try {
Object.keys(null); Object.keys(null);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
assertThrowsError(() => { assertThrowsError(() => {
Object.keys(undefined); Object.keys(undefined);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
let keys = Object.keys({ foo: 1, bar: 2, baz: 3 }); let keys = Object.keys({ foo: 1, bar: 2, baz: 3 });

View file

@ -27,7 +27,7 @@ try {
Object.defineProperty(o, "baz", { value: "baz" }); Object.defineProperty(o, "baz", { value: "baz" });
}, { }, {
error: TypeError, error: TypeError,
message: "Unable to define property on non-extensible object", message: "Cannot define property baz on non-extensible object",
}); });
assert(o.baz === undefined); assert(o.baz === undefined);

View file

@ -10,12 +10,12 @@ try {
message: "Object.setPrototypeOf requires at least two arguments", message: "Object.setPrototypeOf requires at least two arguments",
}); });
// assertThrowsError(() => { assertThrowsError(() => {
// Object.setPrototypeOf({}, "foo"); Object.setPrototypeOf({}, "foo");
// }, { }, {
// error: TypeError, error: TypeError,
// message: "Prototype must be null or object" message: "Prototype must be an object or null"
// }); });
o = {}; o = {};
p = {}; p = {};
@ -26,7 +26,7 @@ try {
Object.setPrototypeOf(o, {}); Object.setPrototypeOf(o, {});
}, { }, {
error: TypeError, error: TypeError,
message: "Object's setPrototypeOf method returned false" message: "Object's [[SetPrototypeOf]] method returned false"
}); });
assert(Object.setPrototypeOf(o, p) === o); assert(Object.setPrototypeOf(o, p) === o);

View file

@ -13,14 +13,14 @@ try {
Object.values(null); Object.values(null);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
assertThrowsError(() => { assertThrowsError(() => {
Object.values(undefined); Object.values(undefined);
}, { }, {
error: TypeError, error: TypeError,
message: "ToObject on null or undefined.", message: "ToObject on null or undefined",
}); });
let values = Object.values({ foo: 1, bar: 2, baz: 3 }); let values = Object.values({ foo: 1, bar: 2, baz: 3 });

View file

@ -62,7 +62,7 @@ try {
Object.defineProperty(p, "foo", {}); Object.defineProperty(p, "foo", {});
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy handler's defineProperty method returned false", message: "Object's [[DefineProperty]] method returned false",
}); });
o = {}; o = {};

View file

@ -47,7 +47,7 @@ try {
delete p.foo; delete p.foo;
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy handler's delete trap violates invariant: cannot report a non-configurable own property of the target as deleted", message: "Proxy handler's deleteProperty trap violates invariant: cannot report a non-configurable own property of the target as deleted",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -53,7 +53,7 @@ try {
"bar" in p; "bar" in p;
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exist on the target and the target is non-extensible", message: "Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exists on the target and the target is non-extensible",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -30,7 +30,7 @@ try {
Object.preventExtensions(p); Object.preventExtensions(p);
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy preventExtensions handler returned false", message: "Object's [[PreventExtensions]] method returned false",
}); });
o = {}; o = {};

View file

@ -57,7 +57,7 @@ try {
Object.setPrototypeOf(p, {}); Object.setPrototypeOf(p, {});
}, { }, {
error: TypeError, error: TypeError,
message: "Object's setPrototypeOf method returned false" message: "Object's [[SetPrototypeOf]] method returned false",
}); });
assert(Object.getPrototypeOf(p) === childProto); assert(Object.getPrototypeOf(p) === childProto);

View file

@ -7,14 +7,14 @@ try {
new Proxy(); new Proxy();
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy requires at least two arguments", message: "Proxy constructor requires at least two arguments",
}); });
assertThrowsError(() => { assertThrowsError(() => {
Proxy(); Proxy();
}, { }, {
error: TypeError, error: TypeError,
message: "Proxy must be called with the \"new\" operator", message: "Proxy must be called with the 'new' operator",
}); });
assertThrowsError(() => { assertThrowsError(() => {

View file

@ -21,7 +21,7 @@ try {
Symbol.for(Symbol()); Symbol.for(Symbol());
}, { }, {
error: TypeError, error: TypeError,
message: "Can't convert symbol to string", message: "Cannot convert symbol to string",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -17,7 +17,7 @@ try {
Symbol(Symbol('foo')); Symbol(Symbol('foo'));
}, { }, {
error: TypeError, error: TypeError,
message: "Can't convert symbol to string" message: "Cannot convert symbol to string"
}) })
console.log("PASS"); console.log("PASS");

View file

@ -11,14 +11,14 @@ try {
s1 + ""; s1 + "";
}, { }, {
error: TypeError, error: TypeError,
message: "Can't convert symbol to string", message: "Cannot convert symbol to string",
}); });
assertThrowsError(() => { assertThrowsError(() => {
s1 + 1; s1 + 1;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't convert symbol to number", message: "Cannot convert symbol to number",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -13,7 +13,7 @@ try {
Symbol.prototype.valueOf.call("foo"); Symbol.prototype.valueOf.call("foo");
}, { }, {
error: TypeError, error: TypeError,
message: "object must be of type Symbol" message: "Not a Symbol object",
}); });
console.log("PASS"); console.log("PASS");

View file

@ -11,7 +11,7 @@ try {
+bigint; +bigint;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't convert BigInt to number" message: "Cannot convert BigInt to number"
}); });
assert(12n + 34n === 46n); assert(12n + 34n === 46n);

View file

@ -6,73 +6,73 @@ try {
1n + value; 1n + value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use addition operator with BigInt and other type" message: "Cannot use addition operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n - value; 1n - value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use subtraction operator with BigInt and other type" message: "Cannot use subtraction operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n * value; 1n * value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use multiplication operator with BigInt and other type" message: "Cannot use multiplication operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n / value; 1n / value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use division operator with BigInt and other type" message: "Cannot use division operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n % value; 1n % value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use modulo operator with BigInt and other type" message: "Cannot use modulo operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n ** value; 1n ** value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use exponentiation operator with BigInt and other type" message: "Cannot use exponentiation operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n | value; 1n | value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use bitwise OR operator with BigInt and other type" message: "Cannot use bitwise OR operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n & value; 1n & value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use bitwise AND operator with BigInt and other type" message: "Cannot use bitwise AND operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n ^ value; 1n ^ value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use bitwise XOR operator with BigInt and other type" message: "Cannot use bitwise XOR operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n << value; 1n << value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use left-shift operator with BigInt and other type" message: "Cannot use left-shift operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n >> value; 1n >> value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use right-shift operator with BigInt and other type" message: "Cannot use right-shift operator with BigInt and other type"
}); });
assertThrowsError(() => { assertThrowsError(() => {
1n >>> value; 1n >>> value;
}, { }, {
error: TypeError, error: TypeError,
message: "Can't use unsigned right-shift operator with BigInt" message: "Cannot use unsigned right-shift operator with BigInt"
}); });
}); });

View file

@ -7,7 +7,7 @@ try {
} }
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'foo' not known" message: "'foo' is not defined"
}); });
assertThrowsError(() => { assertThrowsError(() => {
@ -16,7 +16,7 @@ try {
} }
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'foo' not known" message: "'foo' is not defined"
}); });
var loopCount = 0; var loopCount = 0;
@ -26,7 +26,7 @@ try {
} }
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'foo' not known" message: "'foo' is not defined"
}); });
assert(loopCount === 1); assert(loopCount === 1);

View file

@ -6,7 +6,7 @@ try {
"prop" in value; "prop" in value;
}, { }, {
error: TypeError, error: TypeError,
message: "'in' operator must be used on object" message: "'in' operator must be used on an object"
}); });
}); });

View file

@ -8,7 +8,7 @@ try {
primitive.foo = "bar"; primitive.foo = "bar";
}, { }, {
error: TypeError, error: TypeError,
message: "Can't assign property foo to primitive value" message: "Cannot assign property foo to primitive value"
}); });
}); });

View file

@ -5,7 +5,7 @@ try {
foo`bar${baz}`; foo`bar${baz}`;
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'foo' not known" message: "'foo' is not defined"
}); });
assertThrowsError(() => { assertThrowsError(() => {
@ -13,7 +13,7 @@ try {
foo`bar${baz}`; foo`bar${baz}`;
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'baz' not known" message: "'baz' is not defined"
}); });
assertThrowsError(() => { assertThrowsError(() => {

View file

@ -36,7 +36,7 @@ try {
`${b}`; `${b}`;
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'b' not known" message: "'b' is not defined",
}) })
console.log("PASS"); console.log("PASS");

View file

@ -5,7 +5,7 @@ try {
++x; ++x;
}, { }, {
error: ReferenceError, error: ReferenceError,
message: "'x' not known" message: "'x' is not defined",
}); });
var n = 0; var n = 0;

View file

@ -7,7 +7,7 @@ try {
constantValue = 2; constantValue = 2;
}, { }, {
error: TypeError, error: TypeError,
message: "Assignment to constant variable" message: "Invalid assignment to const variable"
}); });
assert(constantValue === 1); assert(constantValue === 1);

View file

@ -137,12 +137,12 @@ JS::Value CanvasRenderingContext2DWrapper::draw_image(JS::Interpreter& interpret
if (!impl) if (!impl)
return {}; return {};
if (interpreter.argument_count() < 3) if (interpreter.argument_count() < 3)
return interpreter.throw_exception<JS::TypeError>("drawImage() needs three arguments"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::DrawImageArgumentCount);
auto* image_argument = interpreter.argument(0).to_object(interpreter); auto* image_argument = interpreter.argument(0).to_object(interpreter);
if (!image_argument) if (!image_argument)
return {}; return {};
if (StringView(image_argument->class_name()) != "HTMLImageElementWrapper") if (StringView(image_argument->class_name()) != "HTMLImageElementWrapper")
return interpreter.throw_exception<JS::TypeError>(String::format("Image is not an HTMLImageElement, it's an %s", image_argument->class_name())); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::ImageIsAn, image_argument->class_name());
auto x = interpreter.argument(1).to_double(interpreter); auto x = interpreter.argument(1).to_double(interpreter);
if (interpreter.exception()) if (interpreter.exception())
@ -288,10 +288,10 @@ JS::Value CanvasRenderingContext2DWrapper::fill(JS::Interpreter& interpreter)
if (winding_name == "evenodd") { if (winding_name == "evenodd") {
winding = Gfx::Painter::WindingRule::EvenOdd; winding = Gfx::Painter::WindingRule::EvenOdd;
} else if (winding_name != "nonzero") { } else if (winding_name != "nonzero") {
return interpreter.throw_exception<JS::TypeError>("fill winding rule must be either 'nonzero' or 'evenodd'"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::FillBadWindingRule);
} }
} else { } else {
return interpreter.throw_exception<JS::TypeError>("fill called with non-string"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::FillNonString);
} }
} else { } else {
// FIXME: Path2D object // FIXME: Path2D object
@ -378,7 +378,7 @@ JS::Value CanvasRenderingContext2DWrapper::put_image_data(JS::Interpreter& inter
return {}; return {};
if (StringView(image_data_object->class_name()) != "ImageDataWrapper") { if (StringView(image_data_object->class_name()) != "ImageDataWrapper") {
return interpreter.throw_exception<JS::TypeError>("putImageData called with non-ImageData"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::PutImageDataBadCall);
} }
auto& image_data = static_cast<ImageDataWrapper*>(image_data_object)->impl(); auto& image_data = static_cast<ImageDataWrapper*>(image_data_object)->impl();

View file

@ -66,7 +66,7 @@ static Document* document_from(JS::Interpreter& interpreter)
if (!this_object) if (!this_object)
return {}; return {};
if (StringView("DocumentWrapper") != this_object->class_name()) { if (StringView("DocumentWrapper") != this_object->class_name()) {
interpreter.throw_exception<JS::TypeError>("That's not a DocumentWrapper, bro."); interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "DocumentWrapper");
return {}; return {};
} }
return &static_cast<DocumentWrapper*>(this_object)->node(); return &static_cast<DocumentWrapper*>(this_object)->node();
@ -78,7 +78,7 @@ JS::Value DocumentWrapper::get_element_by_id(JS::Interpreter& interpreter)
if (!document) if (!document)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("getElementById() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "getElementById");
auto id = interpreter.argument(0).to_string(interpreter); auto id = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -94,7 +94,7 @@ JS::Value DocumentWrapper::query_selector(JS::Interpreter& interpreter)
if (!document) if (!document)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("querySelector() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "querySelector");
auto selector = interpreter.argument(0).to_string(interpreter); auto selector = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};
@ -111,7 +111,7 @@ JS::Value DocumentWrapper::query_selector_all(JS::Interpreter& interpreter)
if (!document) if (!document)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("querySelectorAll() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "querySelectorAll");
auto selector = interpreter.argument(0).to_string(interpreter); auto selector = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

@ -79,7 +79,7 @@ JS::Value ElementWrapper::get_attribute(JS::Interpreter& interpreter)
return {}; return {};
if (interpreter.argument_count() < 1) if (interpreter.argument_count() < 1)
return interpreter.throw_exception<JS::TypeError>("getAttribute() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "getAttribute");
auto attribute_name = interpreter.argument(0).to_string(interpreter); auto attribute_name = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
@ -99,7 +99,7 @@ JS::Value ElementWrapper::set_attribute(JS::Interpreter& interpreter)
return {}; return {};
if (interpreter.argument_count() < 2) if (interpreter.argument_count() < 2)
return interpreter.throw_exception<JS::TypeError>("setAttribute() needs two arguments"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, "setAttribute", "two");
auto attribute_name = interpreter.argument(0).to_string(interpreter); auto attribute_name = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())

View file

@ -55,7 +55,7 @@ JS::Value EventTargetWrapper::add_event_listener(JS::Interpreter& interpreter)
if (!this_object) if (!this_object)
return {}; return {};
if (interpreter.argument_count() < 2) if (interpreter.argument_count() < 2)
return interpreter.throw_exception<JS::TypeError>("addEventListener() needs two arguments"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, "addEventListener", "two");
auto event_name = interpreter.argument(0).to_string(interpreter); auto event_name = interpreter.argument(0).to_string(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

@ -61,7 +61,7 @@ static ImageData* impl_from(JS::Interpreter& interpreter)
return nullptr; return nullptr;
} }
if (StringView("ImageDataWrapper") != this_object->class_name()) { if (StringView("ImageDataWrapper") != this_object->class_name()) {
interpreter.throw_exception<JS::TypeError>("That's not an ImageDataWrapper, bro."); interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAn, "ImageDataWrapper");
return nullptr; return nullptr;
} }
return &static_cast<ImageDataWrapper*>(this_object)->impl(); return &static_cast<ImageDataWrapper*>(this_object)->impl();

View file

@ -88,7 +88,7 @@ static Window* impl_from(JS::Interpreter& interpreter)
return nullptr; return nullptr;
} }
if (StringView("WindowObject") != this_object->class_name()) { if (StringView("WindowObject") != this_object->class_name()) {
interpreter.throw_exception<JS::TypeError>("That's not a WindowObject, bro."); interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "WindowObject");
return nullptr; return nullptr;
} }
return &static_cast<WindowObject*>(this_object)->impl(); return &static_cast<WindowObject*>(this_object)->impl();
@ -129,12 +129,12 @@ JS::Value WindowObject::set_interval(JS::Interpreter& interpreter)
if (!impl) if (!impl)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("setInterval() needs at least one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
auto* callback_object = interpreter.argument(0).to_object(interpreter); auto* callback_object = interpreter.argument(0).to_object(interpreter);
if (!callback_object) if (!callback_object)
return {}; return {};
if (!callback_object->is_function()) if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>("Not a function"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
i32 interval = 0; i32 interval = 0;
if (interpreter.argument_count() >= 2) { if (interpreter.argument_count() >= 2) {
@ -155,12 +155,12 @@ JS::Value WindowObject::set_timeout(JS::Interpreter& interpreter)
if (!impl) if (!impl)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("setTimeout() needs at least one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
auto* callback_object = interpreter.argument(0).to_object(interpreter); auto* callback_object = interpreter.argument(0).to_object(interpreter);
if (!callback_object) if (!callback_object)
return {}; return {};
if (!callback_object->is_function()) if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>("Not a function"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
i32 interval = 0; i32 interval = 0;
if (interpreter.argument_count() >= 2) { if (interpreter.argument_count() >= 2) {
@ -181,12 +181,12 @@ JS::Value WindowObject::request_animation_frame(JS::Interpreter& interpreter)
if (!impl) if (!impl)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("requestAnimationFrame() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
auto* callback_object = interpreter.argument(0).to_object(interpreter); auto* callback_object = interpreter.argument(0).to_object(interpreter);
if (!callback_object) if (!callback_object)
return {}; return {};
if (!callback_object->is_function()) if (!callback_object->is_function())
return interpreter.throw_exception<JS::TypeError>("Not a function"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
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)));
} }
@ -196,7 +196,7 @@ JS::Value WindowObject::cancel_animation_frame(JS::Interpreter& interpreter)
if (!impl) if (!impl)
return {}; return {};
if (!interpreter.argument_count()) if (!interpreter.argument_count())
return interpreter.throw_exception<JS::TypeError>("cancelAnimationFrame() needs one argument"); return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
auto id = interpreter.argument(0).to_i32(interpreter); auto id = interpreter.argument(0).to_i32(interpreter);
if (interpreter.exception()) if (interpreter.exception())
return {}; return {};

View file

@ -60,7 +60,7 @@ static XMLHttpRequest* impl_from(JS::Interpreter& interpreter)
if (!this_object) if (!this_object)
return nullptr; return nullptr;
if (StringView("XMLHttpRequestWrapper") != this_object->class_name()) { if (StringView("XMLHttpRequestWrapper") != this_object->class_name()) {
interpreter.throw_exception<JS::TypeError>("This is not an XMLHttpRequest object"); interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "XMLHttpRequest");
return nullptr; return nullptr;
} }
return &static_cast<XMLHttpRequestWrapper*>(this_object)->impl(); return &static_cast<XMLHttpRequestWrapper*>(this_object)->impl();