Browse Source

LibJS: Consolidate error messages into ErrorTypes.h

Now, exceptions can be thrown with
interpreter.throw_exception<T>(ErrorType:TYPE, "format", "args",
"here").
Matthew Olsson 5 years ago
parent
commit
78155a6668
63 changed files with 439 additions and 223 deletions
  1. 11 11
      Libraries/LibJS/AST.cpp
  2. 1 0
      Libraries/LibJS/CMakeLists.txt
  3. 1 1
      Libraries/LibJS/Interpreter.cpp
  4. 7 0
      Libraries/LibJS/Interpreter.h
  5. 2 2
      Libraries/LibJS/Runtime/Array.cpp
  6. 1 1
      Libraries/LibJS/Runtime/ArrayConstructor.cpp
  7. 6 6
      Libraries/LibJS/Runtime/ArrayPrototype.cpp
  8. 2 2
      Libraries/LibJS/Runtime/BigIntConstructor.cpp
  9. 1 1
      Libraries/LibJS/Runtime/BigIntPrototype.cpp
  10. 2 2
      Libraries/LibJS/Runtime/BooleanPrototype.cpp
  11. 1 1
      Libraries/LibJS/Runtime/DatePrototype.cpp
  12. 4 4
      Libraries/LibJS/Runtime/ErrorPrototype.cpp
  13. 36 0
      Libraries/LibJS/Runtime/ErrorTypes.cpp
  14. 172 0
      Libraries/LibJS/Runtime/ErrorTypes.h
  15. 5 5
      Libraries/LibJS/Runtime/FunctionPrototype.cpp
  16. 9 9
      Libraries/LibJS/Runtime/Object.cpp
  17. 11 11
      Libraries/LibJS/Runtime/ObjectConstructor.cpp
  18. 4 4
      Libraries/LibJS/Runtime/ProxyConstructor.cpp
  19. 42 42
      Libraries/LibJS/Runtime/ProxyObject.cpp
  20. 6 6
      Libraries/LibJS/Runtime/Reference.cpp
  21. 6 6
      Libraries/LibJS/Runtime/ReflectObject.cpp
  22. 2 2
      Libraries/LibJS/Runtime/ScriptFunction.cpp
  23. 1 1
      Libraries/LibJS/Runtime/StringConstructor.cpp
  24. 3 3
      Libraries/LibJS/Runtime/StringPrototype.cpp
  25. 2 2
      Libraries/LibJS/Runtime/SymbolConstructor.cpp
  26. 1 1
      Libraries/LibJS/Runtime/SymbolPrototype.cpp
  27. 1 1
      Libraries/LibJS/Runtime/Uint8ClampedArray.cpp
  28. 22 22
      Libraries/LibJS/Runtime/Value.cpp
  29. 2 2
      Libraries/LibJS/Tests/BigInt.js
  30. 1 1
      Libraries/LibJS/Tests/Boolean.prototype.toString.js
  31. 1 1
      Libraries/LibJS/Tests/Boolean.prototype.valueOf.js
  32. 2 2
      Libraries/LibJS/Tests/Object.defineProperty.js
  33. 2 2
      Libraries/LibJS/Tests/Object.entries.js
  34. 2 2
      Libraries/LibJS/Tests/Object.keys.js
  35. 1 1
      Libraries/LibJS/Tests/Object.preventExtensions.js
  36. 7 7
      Libraries/LibJS/Tests/Object.setPrototypeOf.js
  37. 2 2
      Libraries/LibJS/Tests/Object.values.js
  38. 1 1
      Libraries/LibJS/Tests/Proxy.handler-defineProperty.js
  39. 1 1
      Libraries/LibJS/Tests/Proxy.handler-deleteProperty.js
  40. 1 1
      Libraries/LibJS/Tests/Proxy.handler-has.js
  41. 1 1
      Libraries/LibJS/Tests/Proxy.handler-preventExtensions.js
  42. 1 1
      Libraries/LibJS/Tests/Proxy.handler-setPrototypeOf.js
  43. 2 2
      Libraries/LibJS/Tests/Proxy.js
  44. 1 1
      Libraries/LibJS/Tests/Symbol.for.js
  45. 1 1
      Libraries/LibJS/Tests/Symbol.js
  46. 2 2
      Libraries/LibJS/Tests/Symbol.prototype.toString.js
  47. 1 1
      Libraries/LibJS/Tests/Symbol.prototype.valueOf.js
  48. 1 1
      Libraries/LibJS/Tests/bigint-basic.js
  49. 12 12
      Libraries/LibJS/Tests/bigint-number-mix-errors.js
  50. 3 3
      Libraries/LibJS/Tests/for-head-errors.js
  51. 1 1
      Libraries/LibJS/Tests/in-operator-basic.js
  52. 1 1
      Libraries/LibJS/Tests/strict-mode-errors.js
  53. 2 2
      Libraries/LibJS/Tests/tagged-template-literals.js
  54. 1 1
      Libraries/LibJS/Tests/template-literals.js
  55. 1 1
      Libraries/LibJS/Tests/update-expressions-basic.js
  56. 1 1
      Libraries/LibJS/Tests/variable-declaration.js
  57. 5 5
      Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp
  58. 4 4
      Libraries/LibWeb/Bindings/DocumentWrapper.cpp
  59. 2 2
      Libraries/LibWeb/Bindings/ElementWrapper.cpp
  60. 1 1
      Libraries/LibWeb/Bindings/EventTargetWrapper.cpp
  61. 1 1
      Libraries/LibWeb/Bindings/ImageDataWrapper.cpp
  62. 8 8
      Libraries/LibWeb/Bindings/WindowObject.cpp
  63. 1 1
      Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp

+ 11 - 11
Libraries/LibJS/AST.cpp

@@ -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();

+ 1 - 0
Libraries/LibJS/CMakeLists.txt

@@ -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

+ 1 - 1
Libraries/LibJS/Interpreter.cpp

@@ -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;
                 }
                 }
 
 

+ 7 - 0
Libraries/LibJS/Interpreter.h

@@ -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; }

+ 2 - 2
Libraries/LibJS/Runtime/Array.cpp

@@ -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());

+ 1 - 1
Libraries/LibJS/Runtime/ArrayConstructor.cpp

@@ -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());

+ 6 - 6
Libraries/LibJS/Runtime/ArrayPrototype.cpp

@@ -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());
 
 

+ 2 - 2
Libraries/LibJS/Runtime/BigIntConstructor.cpp

@@ -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 {};
 }
 }
 
 

+ 1 - 1
Libraries/LibJS/Runtime/BigIntPrototype.cpp

@@ -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);

+ 2 - 2
Libraries/LibJS/Runtime/BooleanPrototype.cpp

@@ -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 {};
     }
     }
 
 

+ 1 - 1
Libraries/LibJS/Runtime/DatePrototype.cpp

@@ -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);

+ 4 - 4
Libraries/LibJS/Runtime/ErrorPrototype.cpp

@@ -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";

+ 36 - 0
Libraries/LibJS/Runtime/ErrorTypes.cpp

@@ -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
+
+}

+ 172 - 0
Libraries/LibJS/Runtime/ErrorTypes.h

@@ -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;
+};
+
+}
+

+ 5 - 5
Libraries/LibJS/Runtime/FunctionPrototype.cpp

@@ -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 = "";

+ 9 - 9
Libraries/LibJS/Runtime/Object.cpp

@@ -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));

+ 11 - 11
Libraries/LibJS/Runtime/ObjectConstructor.cpp

@@ -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())

+ 4 - 4
Libraries/LibJS/Runtime/ProxyConstructor.cpp

@@ -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());
 }
 }

+ 42 - 42
Libraries/LibJS/Runtime/ProxyObject.cpp

@@ -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);
 }
 }
 
 

+ 6 - 6
Libraries/LibJS/Runtime/Reference.cpp

@@ -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())
-        message = "Unresolvable reference";
-    else
-        message = String::format("'%s' not known", property_name.characters());
-    interpreter.throw_exception<ReferenceError>(message);
+    if (property_name.is_empty()) {
+        interpreter.throw_exception<ReferenceError>(ErrorType::ReferenceUnresolvable);
+    } else {
+        interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, property_name.characters());
+    }
 }
 }
 
 
 Value Reference::get(Interpreter& interpreter)
 Value Reference::get(Interpreter& interpreter)

+ 6 - 6
Libraries/LibJS/Runtime/ReflectObject.cpp

@@ -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;

+ 2 - 2
Libraries/LibJS/Runtime/ScriptFunction.cpp

@@ -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);
 }
 }
 
 

+ 1 - 1
Libraries/LibJS/Runtime/StringConstructor.cpp

@@ -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())

+ 3 - 3
Libraries/LibJS/Runtime/StringPrototype.cpp

@@ -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 {};

+ 2 - 2
Libraries/LibJS/Runtime/SymbolConstructor.cpp

@@ -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 {};
     }
     }
 
 

+ 1 - 1
Libraries/LibJS/Runtime/SymbolPrototype.cpp

@@ -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);

+ 1 - 1
Libraries/LibJS/Runtime/Uint8ClampedArray.cpp

@@ -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());
 }
 }
 
 

+ 22 - 22
Libraries/LibJS/Runtime/Value.cpp

@@ -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 {};

+ 2 - 2
Libraries/LibJS/Tests/BigInt.js

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

+ 1 - 1
Libraries/LibJS/Tests/Boolean.prototype.toString.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/Boolean.prototype.valueOf.js

@@ -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");

+ 2 - 2
Libraries/LibJS/Tests/Object.defineProperty.js

@@ -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");

+ 2 - 2
Libraries/LibJS/Tests/Object.entries.js

@@ -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 });

+ 2 - 2
Libraries/LibJS/Tests/Object.keys.js

@@ -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 });

+ 1 - 1
Libraries/LibJS/Tests/Object.preventExtensions.js

@@ -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);

+ 7 - 7
Libraries/LibJS/Tests/Object.setPrototypeOf.js

@@ -10,12 +10,12 @@ try {
         message: "Object.setPrototypeOf requires at least two arguments",
         message: "Object.setPrototypeOf requires at least two arguments",
     });
     });
 
 
-//     assertThrowsError(() => {
-//         Object.setPrototypeOf({}, "foo");
-//     }, {
-//         error: TypeError,
-//         message: "Prototype must be null or object"
-//     });
+    assertThrowsError(() => {
+        Object.setPrototypeOf({}, "foo");
+    }, {
+        error: TypeError,
+        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);
 
 

+ 2 - 2
Libraries/LibJS/Tests/Object.values.js

@@ -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 });

+ 1 - 1
Libraries/LibJS/Tests/Proxy.handler-defineProperty.js

@@ -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 = {};

+ 1 - 1
Libraries/LibJS/Tests/Proxy.handler-deleteProperty.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/Proxy.handler-has.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/Proxy.handler-preventExtensions.js

@@ -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 = {};

+ 1 - 1
Libraries/LibJS/Tests/Proxy.handler-setPrototypeOf.js

@@ -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);
 
 

+ 2 - 2
Libraries/LibJS/Tests/Proxy.js

@@ -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(() => {

+ 1 - 1
Libraries/LibJS/Tests/Symbol.for.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/Symbol.js

@@ -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");

+ 2 - 2
Libraries/LibJS/Tests/Symbol.prototype.toString.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/Symbol.prototype.valueOf.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/bigint-basic.js

@@ -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);

+ 12 - 12
Libraries/LibJS/Tests/bigint-number-mix-errors.js

@@ -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"
         });
         });
     });
     });
 
 

+ 3 - 3
Libraries/LibJS/Tests/for-head-errors.js

@@ -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);
 
 

+ 1 - 1
Libraries/LibJS/Tests/in-operator-basic.js

@@ -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"
         });
         });
     });
     });
 
 

+ 1 - 1
Libraries/LibJS/Tests/strict-mode-errors.js

@@ -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"
         });
         });
     });
     });
 
 

+ 2 - 2
Libraries/LibJS/Tests/tagged-template-literals.js

@@ -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(() => {

+ 1 - 1
Libraries/LibJS/Tests/template-literals.js

@@ -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");

+ 1 - 1
Libraries/LibJS/Tests/update-expressions-basic.js

@@ -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;

+ 1 - 1
Libraries/LibJS/Tests/variable-declaration.js

@@ -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);
 
 

+ 5 - 5
Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp

@@ -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();

+ 4 - 4
Libraries/LibWeb/Bindings/DocumentWrapper.cpp

@@ -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 {};

+ 2 - 2
Libraries/LibWeb/Bindings/ElementWrapper.cpp

@@ -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())

+ 1 - 1
Libraries/LibWeb/Bindings/EventTargetWrapper.cpp

@@ -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 {};

+ 1 - 1
Libraries/LibWeb/Bindings/ImageDataWrapper.cpp

@@ -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();

+ 8 - 8
Libraries/LibWeb/Bindings/WindowObject.cpp

@@ -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 {};

+ 1 - 1
Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp

@@ -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();