mirror of
				https://github.com/LadybirdBrowser/ladybird.git
				synced 2025-10-31 21:30:58 +00:00 
			
		
		
		
	LibJS: Consolidate error messages into ErrorTypes.h
Now, exceptions can be thrown with interpreter.throw_exception<T>(ErrorType:TYPE, "format", "args", "here").
This commit is contained in:
		
							parent
							
								
									9940a7f6de
								
							
						
					
					
						commit
						78155a6668
					
				
				
				Notes:
				
					sideshowbarker
				
				2024-07-19 05:43:14 +09:00 
				
			
			Author: https://github.com/mattco98
Commit: 78155a6668
Pull-request: https://github.com/SerenityOS/serenity/pull/2538
Issue: https://github.com/SerenityOS/serenity/issues/1842
			
					 63 changed files with 439 additions and 223 deletions
				
			
		|  | @ -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(); | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; } | ||||||
|  |  | ||||||
|  | @ -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()); | ||||||
|  |  | ||||||
|  | @ -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()); | ||||||
|  |  | ||||||
|  | @ -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()); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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
									
								
								Libraries/LibJS/Runtime/ErrorTypes.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Libraries/LibJS/Runtime/ErrorTypes.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  |  *    list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||||
|  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||||
|  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||||
|  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <LibJS/Runtime/ErrorTypes.h> | ||||||
|  | 
 | ||||||
|  | namespace JS { | ||||||
|  | 
 | ||||||
|  | #define __ENUMERATE_JS_ERROR(name, message) \ | ||||||
|  | const ErrorType ErrorType::name = ErrorType(message); | ||||||
|  |     JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR) | ||||||
|  | #undef __ENUMERATE_JS_ERROR | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										172
									
								
								Libraries/LibJS/Runtime/ErrorTypes.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Libraries/LibJS/Runtime/ErrorTypes.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,172 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, this | ||||||
|  |  *    list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||||
|  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||||
|  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||||
|  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #define JS_ENUMERATE_ERROR_TYPES(M)                                                                    \ | ||||||
|  |     M(ArrayInvalidLength, "Invalid array length")                                                      \ | ||||||
|  |     M(ArrayMaxSize, "Maximum array size exceeded")                                                     \ | ||||||
|  |     M(ArrayPrototypeOneArg, "Array.prototype.%s() requires at least one argument")                     \ | ||||||
|  |     M(AccessorBadField, "Accessor descriptor's '%s' field must be a function or undefined")            \ | ||||||
|  |     M(AccessorValueOrWritable, "Accessor property descriptor cannot specify a value or writable key")  \ | ||||||
|  |     M(BigIntBadOperator, "Cannot use %s operator with BigInt")                                         \ | ||||||
|  |     M(BigIntBadOperatorOtherType, "Cannot use %s operator with BigInt and other type")                 \ | ||||||
|  |     M(BigIntIntArgument, "BigInt argument must be an integer")                                         \ | ||||||
|  |     M(BigIntInvalidValue, "Invalid value for BigInt: %s")                                              \ | ||||||
|  |     M(Convert, "Cannot convert %s to %s")                                                              \ | ||||||
|  |     M(ConvertUndefinedToObject, "Cannot convert undefined to object")                                  \ | ||||||
|  |     M(DescChangeNonConfigurable, "Cannot change attributes of non-configurable property '%s'")         \ | ||||||
|  |     M(ForOfNotIterable, "for..of right-hand side must be iterable")                                    \ | ||||||
|  |     M(FunctionArgsNotObject, "Argument array must be an object")                                       \ | ||||||
|  |     M(InOperatorWithObject, "'in' operator must be used on an object")                                 \ | ||||||
|  |     M(InstanceOfOperatorBadPrototype, "Prototype property of %s is not an object")                     \ | ||||||
|  |     M(InvalidAssignToConst, "Invalid assignment to const variable")                                    \ | ||||||
|  |     M(InvalidLeftHandAssignment, "Invalid left-hand side in assignment")                               \ | ||||||
|  |     M(IsNotA, "%s is not a %s")                                                                        \ | ||||||
|  |     M(IsNotAEvaluatedFrom, "%s is not a %s (evaluated from '%s')")                                     \ | ||||||
|  |     M(NotA, "Not a %s object")                                                                         \ | ||||||
|  |     M(NotACtor, "%s is not a constructor")                                                             \ | ||||||
|  |     M(NotAFunction, "%s is not a function")                                                            \ | ||||||
|  |     M(NotAFunctionNoParam, "Not a function")                                                           \ | ||||||
|  |     M(NotAn, "Not an %s object")                                                                       \ | ||||||
|  |     M(NotAnObject, "%s is not an object")                                                              \ | ||||||
|  |     M(NotASymbol, "%s is not a symbol")                                                                \ | ||||||
|  |     M(NotIterable, "%s is not iterable")                                                               \ | ||||||
|  |     M(NonExtensibleDefine, "Cannot define property %s on non-extensible object")                       \ | ||||||
|  |     M(ObjectDefinePropertyReturnedFalse, "Object's [[DefineProperty]] method returned false")          \ | ||||||
|  |     M(ObjectSetPrototypeOfReturnedFalse, "Object's [[SetPrototypeOf]] method returned false")          \ | ||||||
|  |     M(ObjectSetPrototypeOfTwoArgs, "Object.setPrototypeOf requires at least two arguments")            \ | ||||||
|  |     M(ObjectPreventExtensionsReturnedFalse, "Object's [[PreventExtensions]] method returned false")    \ | ||||||
|  |     M(ObjectPrototypeWrongType, "Prototype must be an object or null")                                 \ | ||||||
|  |     M(ProxyCallWithNew, "Proxy must be called with the 'new' operator")                                \ | ||||||
|  |     M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s")       \ | ||||||
|  |     M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates "             \ | ||||||
|  |         "invariant: a property cannot be defined as non-configurable if it already exists on the "     \ | ||||||
|  |         "target object as a configurable property")                                                    \ | ||||||
|  |     M(ProxyDefinePropIncompatibleDescriptor, "Proxy handler's defineProperty trap violates "           \ | ||||||
|  |         "invariant: the new descriptor is not compatible with the existing descriptor of the "         \ | ||||||
|  |         "property on the target")                                                                      \ | ||||||
|  |     M(ProxyDefinePropNonConfigurableNonExisting, "Proxy handler's defineProperty trap "                \ | ||||||
|  |         "violates invariant: a property cannot be defined as non-configurable if it does not "         \ | ||||||
|  |         "already exist on the target object")                                                          \ | ||||||
|  |     M(ProxyDefinePropNonExtensible, "Proxy handler's defineProperty trap violates invariant: "         \ | ||||||
|  |         "a property cannot be reported as being defined if the property does not exist on "            \ | ||||||
|  |         "the target and the target is non-extensible")                                                 \ | ||||||
|  |     M(ProxyDeleteNonConfigurable, "Proxy handler's deleteProperty trap violates invariant: "           \ | ||||||
|  |         "cannot report a non-configurable own property of the target as deleted")                      \ | ||||||
|  |     M(ProxyGetImmutableDataProperty, "Proxy handler's get trap violates invariant: the "               \ | ||||||
|  |         "returned value must match the value on the target if the property exists on the "             \ | ||||||
|  |         "target as a non-writable, non-configurable own data property")                                \ | ||||||
|  |     M(ProxyGetNonConfigurableAccessor, "Proxy handler's get trap violates invariant: the "             \ | ||||||
|  |         "returned value must be undefined if the property exists on the target as a "                  \ | ||||||
|  |         "non-configurable accessor property with an undefined get attribute")                          \ | ||||||
|  |     M(ProxyGetOwnDescriptorExistingConfigurable, "Proxy handler's getOwnPropertyDescriptor "           \ | ||||||
|  |         "trap violates invariant: a property cannot be defined as non-configurable if it "             \ | ||||||
|  |         "already exists on the target object as a configurable property")                              \ | ||||||
|  |     M(ProxyGetOwnDescriptorInvalidDescriptor, "Proxy handler's getOwnPropertyDescriptor trap "         \ | ||||||
|  |         "violates invariant: invalid property descriptor for existing property on the target")         \ | ||||||
|  |     M(ProxyGetOwnDescriptorInvalidNonConfig, "Proxy handler's getOwnPropertyDescriptor trap "          \ | ||||||
|  |         "violates invariant: cannot report target's property as non-configurable if the "              \ | ||||||
|  |         "property does not exist, or if it is configurable")                                           \ | ||||||
|  |     M(ProxyGetOwnDescriptorNonConfigurable, "Proxy handler's getOwnPropertyDescriptor trap "           \ | ||||||
|  |         "violates invariant: cannot return undefined for a property on the target which is "           \ | ||||||
|  |         "a non-configurable property")                                                                 \ | ||||||
|  |     M(ProxyGetOwnDescriptorReturn, "Proxy handler's getOwnPropertyDescriptor trap violates "           \ | ||||||
|  |         "invariant: must return an object or undefined")                                               \ | ||||||
|  |     M(ProxyGetOwnDescriptorUndefReturn, "Proxy handler's getOwnPropertyDescriptor trap "               \ | ||||||
|  |         "violates invariant: cannot report a property as being undefined if it exists as an "          \ | ||||||
|  |         "own property of the target and the target is non-extensible")                                 \ | ||||||
|  |     M(ProxyGetPrototypeOfNonExtensible, "Proxy handler's getPrototypeOf trap violates "                \ | ||||||
|  |         "invariant: cannot return a different prototype object for a non-extensible target")           \ | ||||||
|  |     M(ProxyGetPrototypeOfReturn, "Proxy handler's getPrototypeOf trap violates invariant: "            \ | ||||||
|  |         "must return an object or null")                                                               \ | ||||||
|  |     M(ProxyHasExistingNonConfigurable, "Proxy handler's has trap violates invariant: a "               \ | ||||||
|  |         "property cannot be reported as non-existent if it exists on the target as a "                 \ | ||||||
|  |         "non-configurable property")                                                                   \ | ||||||
|  |     M(ProxyHasExistingNonExtensible, "Proxy handler's has trap violates invariant: a property "        \ | ||||||
|  |         "cannot be reported as non-existent if it exists on the target and the target is "             \ | ||||||
|  |         "non-extensible")                                                                              \ | ||||||
|  |     M(ProxyInvalidTrap, "Proxy handler's %s trap wasn't undefined, null, or callable")                 \ | ||||||
|  |     M(ProxyIsExtensibleReturn, "Proxy handler's isExtensible trap violates invariant: "                \ | ||||||
|  |         "return value must match the target's extensibility")                                          \ | ||||||
|  |     M(ProxyPreventExtensionsReturn, "Proxy handler's preventExtensions trap violates "                 \ | ||||||
|  |         "invariant: cannot return true if the target object is extensible")                            \ | ||||||
|  |     M(ProxyRevoked, "An operation was performed on a revoked Proxy object")                            \ | ||||||
|  |     M(ProxySetImmutableDataProperty, "Proxy handler's set trap violates invariant: cannot "            \ | ||||||
|  |         "return true for a property on the target which is a non-configurable, non-writable "          \ | ||||||
|  |         "own data property")                                                                           \ | ||||||
|  |     M(ProxySetNonConfigurableAccessor, "Proxy handler's set trap violates invariant: cannot "          \ | ||||||
|  |         "return true for a property on the target which is a non-configurable own accessor "           \ | ||||||
|  |         "property with an undefined set attribute")                                                    \ | ||||||
|  |     M(ProxySetPrototypeOfNonExtensible, "Proxy handler's setPrototypeOf trap violates "                \ | ||||||
|  |         "invariant: the argument must match the prototype of the target if the "                       \ | ||||||
|  |         "target is non-extensible")                                                                    \ | ||||||
|  |     M(ProxyTwoArguments, "Proxy constructor requires at least two arguments")                          \ | ||||||
|  |     M(ReduceNoInitial, "Reduce of empty array with no initial value")                                  \ | ||||||
|  |     M(ReferencePrimitiveAssignment, "Cannot assign property %s to primitive value")                    \ | ||||||
|  |     M(ReferenceUnresolvable, "Unresolvable reference")                                                 \ | ||||||
|  |     M(ReflectArgumentMustBeAFunction, "First argument of Reflect.%s() must be a function")             \ | ||||||
|  |     M(ReflectArgumentMustBeAnObject, "First argument of Reflect.%s() must be an object")               \ | ||||||
|  |     M(ReflectBadArgumentsList, "Arguments list must be an object")                                     \ | ||||||
|  |     M(ReflectBadNewTarget, "Optional third argument of Reflect.construct() must be a constructor")     \ | ||||||
|  |     M(ReflectBadDescriptorArgument, "Descriptor argument is not an object")                            \ | ||||||
|  |     M(StringRawCannotConvert, "Cannot convert property 'raw' to object from %s")                       \ | ||||||
|  |     M(StringRepeatCountMustBe, "repeat count must be a %s number")                                     \ | ||||||
|  |     M(ToObjectNullOrUndef, "ToObject on null or undefined")                                            \ | ||||||
|  |     M(UnknownIdentifier, "'%s' is not defined")                                                        \ | ||||||
|  |     /* LibWeb bindings */                                                                              \ | ||||||
|  |     M(BadArgCountOne, "%s() needs one argument")                                                       \ | ||||||
|  |     M(BadArgCountAtLeastOne, "%s() needs at least one argument")                                       \ | ||||||
|  |     M(BadArgCountMany, "%s() needs %s arguments")                                                      \ | ||||||
|  |     M(DrawImageArgumentCount, "drawImage() needs three arguments")                                     \ | ||||||
|  |     M(FillBadWindingRule, "fill() winding rule must be either 'nonzero' or 'evenodd'")                 \ | ||||||
|  |     M(FillNonString, "fill() called with non-string")                                                  \ | ||||||
|  |     M(ImageIsAn, "Image is not an HTMLImageElement, it's an %s")                                       \ | ||||||
|  |     M(PutImageDataBadCall, "putImageData() called with non-ImageData")                                 \ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace JS { | ||||||
|  | 
 | ||||||
|  | class ErrorType { | ||||||
|  | public: | ||||||
|  | #define __ENUMERATE_JS_ERROR(name, message) \ | ||||||
|  |     static const ErrorType name; | ||||||
|  |     JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR) | ||||||
|  | #undef __ENUMERATE_JS_ERROR | ||||||
|  | 
 | ||||||
|  |     const char* message() const { return m_message; }; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     explicit ErrorType(const char* message) | ||||||
|  |         : m_message(message) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const char* m_message; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @ -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 = ""; | ||||||
|  |  | ||||||
|  | @ -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)); | ||||||
|  |  | ||||||
|  | @ -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()) | ||||||
|  |  | ||||||
|  | @ -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()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ void Reference::put(Interpreter& interpreter, Value value) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!base().is_object() && interpreter.in_strict_mode()) { |     if (!base().is_object() && interpreter.in_strict_mode()) { | ||||||
|         interpreter.throw_exception<TypeError>(String::format("Can't assign property %s to primitive value", m_name.to_string().characters())); |         interpreter.throw_exception<TypeError>(ErrorType::ReferencePrimitiveAssignment, m_name.to_string().characters()); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -66,11 +66,11 @@ void Reference::throw_reference_error(Interpreter& interpreter) | ||||||
| { | { | ||||||
|     auto property_name = m_name.to_string(); |     auto property_name = m_name.to_string(); | ||||||
|     String message; |     String message; | ||||||
|     if (property_name.is_empty()) |     if (property_name.is_empty()) { | ||||||
|         message = "Unresolvable reference"; |         interpreter.throw_exception<ReferenceError>(ErrorType::ReferenceUnresolvable); | ||||||
|     else |     } else { | ||||||
|         message = String::format("'%s' not known", property_name.characters()); |         interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, property_name.characters()); | ||||||
|     interpreter.throw_exception<ReferenceError>(message); |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Value Reference::get(Interpreter& interpreter) | Value Reference::get(Interpreter& interpreter) | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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()) | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|  |  | ||||||
|  | @ -33,8 +33,8 @@ try { | ||||||
|         }, { |         }, { | ||||||
|             error: TypeError, |             error: TypeError, | ||||||
|             message: typeof value === "symbol" |             message: typeof value === "symbol" | ||||||
|                 ? "Can't convert symbol to BigInt" |                 ? "Cannot convert symbol to BigInt" | ||||||
|                 : `Can't convert ${value} to BigInt` |                 : `Cannot convert ${value} to BigInt` | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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 }); | ||||||
|  |  | ||||||
|  | @ -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 }); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -10,12 +10,12 @@ try { | ||||||
|         message: "Object.setPrototypeOf requires at least two arguments", |         message: "Object.setPrototypeOf requires at least two arguments", | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| //     assertThrowsError(() => {
 |     assertThrowsError(() => { | ||||||
| //         Object.setPrototypeOf({}, "foo");
 |         Object.setPrototypeOf({}, "foo"); | ||||||
| //     }, {
 |     }, { | ||||||
| //         error: TypeError,
 |         error: TypeError, | ||||||
| //         message: "Prototype must be null or object"
 |         message: "Prototype must be an object or null" | ||||||
| //     });
 |     }); | ||||||
| 
 | 
 | ||||||
|     o = {}; |     o = {}; | ||||||
|     p = {}; |     p = {}; | ||||||
|  | @ -26,7 +26,7 @@ try { | ||||||
|         Object.setPrototypeOf(o, {}); |         Object.setPrototypeOf(o, {}); | ||||||
|     }, { |     }, { | ||||||
|         error: TypeError, |         error: TypeError, | ||||||
|         message: "Object's setPrototypeOf method returned false" |         message: "Object's [[SetPrototypeOf]] method returned false" | ||||||
|     }); |     }); | ||||||
|     assert(Object.setPrototypeOf(o, p) === o); |     assert(Object.setPrototypeOf(o, p) === o); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 }); | ||||||
|  |  | ||||||
|  | @ -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 = {}; | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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 = {}; | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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(() => { | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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(() => { | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|  |  | ||||||
|  | @ -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()) | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  |  | ||||||
|  | @ -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 {}; | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Olsson
						Matthew Olsson