// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/objects/option-utils.h" #include "src/numbers/conversions.h" #include "src/objects/objects-inl.h" namespace v8 { namespace internal { // ecma402/#sec-getoptionsobject MaybeHandle GetOptionsObject(Isolate* isolate, Handle options, const char* method_name) { // 1. If options is undefined, then if (options->IsUndefined(isolate)) { // a. Return ! ObjectCreate(null). return isolate->factory()->NewJSObjectWithNullProto(); } // 2. If Type(options) is Object, then if (options->IsJSReceiver()) { // a. Return options. return Handle::cast(options); } // 3. Throw a TypeError exception. THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidArgument), JSReceiver); } // ecma402/#sec-coerceoptionstoobject MaybeHandle CoerceOptionsToObject(Isolate* isolate, Handle options, const char* method_name) { // 1. If options is undefined, then if (options->IsUndefined(isolate)) { // a. Return ! ObjectCreate(null). return isolate->factory()->NewJSObjectWithNullProto(); } // 2. Return ? ToObject(options). ASSIGN_RETURN_ON_EXCEPTION(isolate, options, Object::ToObject(isolate, options, method_name), JSReceiver); return Handle::cast(options); } Maybe GetStringOption(Isolate* isolate, Handle options, const char* property, std::vector values, const char* method_name, std::unique_ptr* result) { Handle property_str = isolate->factory()->NewStringFromAsciiChecked(property); // 1. Let value be ? Get(options, property). Handle value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value, Object::GetPropertyOrElement(isolate, options, property_str), Nothing()); if (value->IsUndefined(isolate)) { return Just(false); } // 2. c. Let value be ? ToString(value). Handle value_str; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value_str, Object::ToString(isolate, value), Nothing()); std::unique_ptr value_cstr = value_str->ToCString(); // 2. d. if values is not undefined, then if (values.size() > 0) { // 2. d. i. If values does not contain an element equal to value, // throw a RangeError exception. for (size_t i = 0; i < values.size(); i++) { if (strcmp(values.at(i), value_cstr.get()) == 0) { // 2. e. return value *result = std::move(value_cstr); return Just(true); } } Handle method_str = isolate->factory()->NewStringFromAsciiChecked(method_name); THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kValueOutOfRange, value, method_str, property_str), Nothing()); } // 2. e. return value *result = std::move(value_cstr); return Just(true); } V8_WARN_UNUSED_RESULT Maybe GetBoolOption(Isolate* isolate, Handle options, const char* property, const char* method_name, bool* result) { Handle property_str = isolate->factory()->NewStringFromAsciiChecked(property); // 1. Let value be ? Get(options, property). Handle value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value, Object::GetPropertyOrElement(isolate, options, property_str), Nothing()); // 2. If value is not undefined, then if (!value->IsUndefined(isolate)) { // 2. b. i. Let value be ToBoolean(value). *result = value->BooleanValue(isolate); // 2. e. return value return Just(true); } return Just(false); } // ecma402/#sec-defaultnumberoption Maybe DefaultNumberOption(Isolate* isolate, Handle value, int min, int max, int fallback, Handle property) { // 2. Else, return fallback. if (value->IsUndefined()) return Just(fallback); // 1. If value is not undefined, then // a. Let value be ? ToNumber(value). Handle value_num; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value_num, Object::ToNumber(isolate, value), Nothing()); DCHECK(value_num->IsNumber()); // b. If value is NaN or less than minimum or greater than maximum, throw a // RangeError exception. if (value_num->IsNaN() || value_num->Number() < min || value_num->Number() > max) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kPropertyValueOutOfRange, property), Nothing()); } // The max and min arguments are integers and the above check makes // sure that we are within the integer range making this double to // int conversion safe. // // c. Return floor(value). return Just(FastD2I(floor(value_num->Number()))); } // ecma402/#sec-getnumberoption Maybe GetNumberOption(Isolate* isolate, Handle options, Handle property, int min, int max, int fallback) { // 1. Let value be ? Get(options, property). Handle value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, value, JSReceiver::GetProperty(isolate, options, property), Nothing()); // Return ? DefaultNumberOption(value, minimum, maximum, fallback). return DefaultNumberOption(isolate, value, min, max, fallback, property); } } // namespace internal } // namespace v8