| // 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. |
| |
| #ifndef V8_OBJECTS_OPTION_UTILS_H_ |
| #define V8_OBJECTS_OPTION_UTILS_H_ |
| |
| #include "src/common/globals.h" |
| #include "src/execution/isolate.h" |
| #include "src/objects/js-objects.h" |
| #include "src/objects/string.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // https://tc39.es/ecma262/#sec-getoptionsobject |
| V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSReceiver> GetOptionsObject( |
| Isolate* isolate, DirectHandle<Object> options, const char* method_name); |
| |
| // https://tc39.es/ecma402/#sec-coerceoptionstoobject |
| V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSReceiver> CoerceOptionsToObject( |
| Isolate* isolate, DirectHandle<Object> options, const char* method_name); |
| |
| // ECMA402 9.2.10. GetOption( options, property, type, values, fallback) |
| // https://tc39.es/ecma402/#sec-getoption and |
| // https://tc39.es/proposal-temporal/#sec-getoption |
| // |
| // This is specialized for the case when type is string, and when |
| // no list of values is passed. If you wish to pass a list of values, |
| // use the other overload. |
| // |
| // Returns true if options object has the property and stores the |
| // result in value. Returns false if the value is not found. The |
| // caller is required to use fallback value appropriately in this |
| // case. |
| // |
| // method_name is a string denoting the method the call from; used when |
| // printing the error message. |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<bool> GetStringOption( |
| Isolate* isolate, DirectHandle<JSReceiver> options, |
| DirectHandle<String> property, const char* method_name, |
| DirectHandle<String>* result); |
| |
| // ECMA402 9.2.10. GetOption( options, property, type, values, fallback) |
| // https://tc39.es/ecma402/#sec-getoption and |
| // https://tc39.es/proposal-temporal/#sec-getoption |
| // |
| // This is specialized for the case when type is string, and when you are |
| // passing in a list of values to match against. If you just wish to get the |
| // string, use the overload above. This function expects a list of |
| // `enum_values`, which it will return on matching the corresponding |
| // (index-wise) str_values entry, which is useful when trying to match against |
| // an options list. If you do not need a particular enum but still wish to match |
| // against a list of values, just pass in str_values twice. |
| // |
| // The enum in the enum_values is the corresponding value to the strings |
| // in the str_values. If the option does not contains name, |
| // default_value will be return. If default_value is not set, fallback |
| // is treated as REQUIRED and this will error when a value cannot be matched. |
| template <typename T> |
| V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOption( |
| Isolate* isolate, DirectHandle<JSReceiver> options, |
| DirectHandle<String> property, const char* method_name, |
| const std::span<const std::string_view> str_values, |
| const std::span<const T> enum_values, std::optional<T> default_value) { |
| DCHECK_EQ(str_values.size(), enum_values.size()); |
| // 1. Let value be ? Get(options, property). |
| // 2. c. Let value be ? ToString(value). |
| |
| DirectHandle<String> found_string; |
| Maybe<bool> found = |
| GetStringOption(isolate, options, property, method_name, &found_string); |
| MAYBE_RETURN(found, Nothing<T>()); |
| // 2. d. if values is not undefined, then |
| |
| if (found.FromJust()) { |
| for (size_t i = 0; i < str_values.size(); i++) { |
| if (found_string->IsEqualTo(str_values[i], isolate)) { |
| return Just(enum_values[i]); |
| } |
| } |
| } else if (default_value.has_value()) { |
| // 2. If value is undefined, then |
| // a. If default is required, throw a RangeError exception. |
| // (done in branch below) |
| // b. Return default. |
| return Just(default_value.value()); |
| } |
| |
| // For the error |
| if (found_string.is_null()) { |
| found_string = isolate->factory()->undefined_string(); |
| } |
| |
| // 2. d. i. If values does not contain an element equal to value, |
| // throw a RangeError exception. |
| DirectHandle<String> method_str = |
| isolate->factory()->NewStringFromAsciiChecked(method_name); |
| THROW_NEW_ERROR_RETURN_VALUE( |
| isolate, |
| NewRangeError(MessageTemplate::kValueOutOfRange, found_string, method_str, |
| property), |
| Nothing<T>()); |
| } |
| |
| // A helper template to get string from option into a enum. |
| // The enum in the enum_values is the corresponding value to the strings |
| // in the str_values. If the option does not contains name, |
| // default_value will be return. |
| template <typename T> |
| V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOrBooleanOption( |
| Isolate* isolate, DirectHandle<JSReceiver> options, const char* property, |
| const char* method, const std::span<const std::string_view> str_values, |
| const std::span<const T> enum_values, T true_value, T false_value, |
| T fallback_value) { |
| DCHECK_EQ(str_values.size(), enum_values.size()); |
| Factory* factory = isolate->factory(); |
| DirectHandle<String> property_str = |
| factory->NewStringFromAsciiChecked(property); |
| |
| // 1. Let value be ? Get(options, property). |
| DirectHandle<Object> value; |
| ASSIGN_RETURN_ON_EXCEPTION( |
| isolate, value, |
| Object::GetPropertyOrElement(isolate, options, property_str)); |
| // 2. If value is undefined, then return fallback. |
| if (IsUndefined(*value)) { |
| return Just(fallback_value); |
| } |
| // 3. If value is true, then return trueValue. |
| if (IsTrue(*value)) { |
| return Just(true_value); |
| } |
| // 4. Let valueBoolean be ToBoolean(value). |
| bool valueBoolean = Object::BooleanValue(*value, isolate); |
| // 5. If valueBoolean is false, then return valueBoolean. |
| if (!valueBoolean) { |
| return Just(false_value); |
| } |
| |
| DirectHandle<String> value_str; |
| // 6. Let value be ? ToString(value). |
| ASSIGN_RETURN_ON_EXCEPTION(isolate, value_str, |
| Object::ToString(isolate, value)); |
| // 7. If value is *"true"* or *"false"*, return _fallback_. |
| if (String::Equals(isolate, value_str, factory->true_string()) || |
| String::Equals(isolate, value_str, factory->false_string())) { |
| return Just(fallback_value); |
| } |
| // 8. If values does not contain an element equal to _value_, throw a |
| // *RangeError* exception. |
| // 9. Return value. |
| for (size_t i = 0; i < str_values.size(); i++) { |
| if (value_str->IsEqualTo(str_values[i], isolate)) { |
| return Just(enum_values[i]); |
| } |
| } |
| |
| THROW_NEW_ERROR( |
| isolate, |
| NewRangeError(MessageTemplate::kValueOutOfRange, value, |
| factory->NewStringFromAsciiChecked(method), property_str)); |
| } |
| |
| // ECMA402 9.2.10. GetOption( options, property, type, values, fallback) |
| // https://tc39.es/ecma402/#sec-getoption |
| // |
| // This is specialized for the case when type is boolean. |
| // |
| // Returns true if options object has the property and stores the |
| // result in value. Returns false if the value is not found. The |
| // caller is required to use fallback value appropriately in this |
| // case. |
| // |
| // method_name is a string denoting the method it called from; used when |
| // printing the error message. |
| |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<bool> GetBoolOption( |
| Isolate* isolate, DirectHandle<JSReceiver> options, |
| DirectHandle<String> property, const char* method_name, bool* result); |
| |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<int> GetNumberOption( |
| Isolate* isolate, DirectHandle<JSReceiver> options, |
| DirectHandle<String> property, int min, int max, int fallback); |
| |
| // https://tc39.es/ecma262/#sec-getoption while type is "number" |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<double> GetNumberOptionAsDouble( |
| Isolate* isolate, DirectHandle<JSReceiver> options, |
| DirectHandle<String> property, double default_value); |
| |
| // https://tc39.es/ecma402/#sec-defaultnumberoption |
| V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<int> DefaultNumberOption( |
| Isolate* isolate, DirectHandle<Object> value, int min, int max, |
| int fallback, DirectHandle<String> property); |
| |
| } // namespace internal |
| } // namespace v8 |
| #endif // V8_OBJECTS_OPTION_UTILS_H_ |