1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_OPTION_UTILS_H_
6#define V8_OBJECTS_OPTION_UTILS_H_
7
8#include "src/execution/isolate.h"
9#include "src/objects/objects.h"
10
11namespace v8 {
12namespace internal {
13
14// ecma402/#sec-getoptionsobject and temporal/#sec-getoptionsobject
15V8_WARN_UNUSED_RESULT MaybeHandle<JSReceiver> GetOptionsObject(
16    Isolate* isolate, Handle<Object> options, const char* method_name);
17
18// ecma402/#sec-coerceoptionstoobject
19V8_WARN_UNUSED_RESULT MaybeHandle<JSReceiver> CoerceOptionsToObject(
20    Isolate* isolate, Handle<Object> options, const char* method_name);
21
22// ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
23// ecma402/#sec-getoption and temporal/#sec-getoption
24//
25// This is specialized for the case when type is string.
26//
27// Instead of passing undefined for the values argument as the spec
28// defines, pass in an empty vector.
29//
30// Returns true if options object has the property and stores the
31// result in value. Returns false if the value is not found. The
32// caller is required to use fallback value appropriately in this
33// case.
34//
35// method_name is a string denoting the method the call from; used when
36// printing the error message.
37V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<bool> GetStringOption(
38    Isolate* isolate, Handle<JSReceiver> options, const char* property,
39    std::vector<const char*> values, const char* method_name,
40    std::unique_ptr<char[]>* result);
41
42// A helper template to get string from option into a enum.
43// The enum in the enum_values is the corresponding value to the strings
44// in the str_values. If the option does not contains name,
45// default_value will be return.
46template <typename T>
47V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOption(
48    Isolate* isolate, Handle<JSReceiver> options, const char* name,
49    const char* method_name, const std::vector<const char*>& str_values,
50    const std::vector<T>& enum_values, T default_value) {
51  DCHECK_EQ(str_values.size(), enum_values.size());
52  std::unique_ptr<char[]> cstr;
53  Maybe<bool> found =
54      GetStringOption(isolate, options, name, str_values, method_name, &cstr);
55  MAYBE_RETURN(found, Nothing<T>());
56  if (found.FromJust()) {
57    DCHECK_NOT_NULL(cstr.get());
58    for (size_t i = 0; i < str_values.size(); i++) {
59      if (strcmp(cstr.get(), str_values[i]) == 0) {
60        return Just(enum_values[i]);
61      }
62    }
63    UNREACHABLE();
64  }
65  return Just(default_value);
66}
67
68// A helper template to get string from option into a enum.
69// The enum in the enum_values is the corresponding value to the strings
70// in the str_values. If the option does not contains name,
71// default_value will be return.
72template <typename T>
73V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOrBooleanOption(
74    Isolate* isolate, Handle<JSReceiver> options, const char* property,
75    const char* method, const std::vector<const char*>& str_values,
76    const std::vector<T>& enum_values, T true_value, T false_value,
77    T fallback_value) {
78  DCHECK_EQ(str_values.size(), enum_values.size());
79  Handle<String> property_str =
80      isolate->factory()->NewStringFromAsciiChecked(property);
81
82  // 1. Let value be ? Get(options, property).
83  Handle<Object> value;
84  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
85      isolate, value,
86      Object::GetPropertyOrElement(isolate, options, property_str),
87      Nothing<T>());
88  // 2. If value is undefined, then return fallback.
89  if (value->IsUndefined(isolate)) {
90    return Just(fallback_value);
91  }
92  // 3. If value is true, then return trueValue.
93  if (value->IsTrue(isolate)) {
94    return Just(true_value);
95  }
96  // 4. Let valueBoolean be ToBoolean(value).
97  bool valueBoolean = value->BooleanValue(isolate);
98  // 5. If valueBoolean is false, then return valueBoolean.
99  if (!valueBoolean) {
100    return Just(false_value);
101  }
102
103  Handle<String> value_str;
104  // 6. Let value be ? ToString(value).
105  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
106      isolate, value_str, Object::ToString(isolate, value), Nothing<T>());
107  // 7. If values does not contain an element equal to value, throw a
108  // RangeError exception.
109  // 8. Return value.
110  value_str = String::Flatten(isolate, value_str);
111  {
112    DisallowGarbageCollection no_gc;
113    const String::FlatContent& flat = value_str->GetFlatContent(no_gc);
114    int32_t length = value_str->length();
115    for (size_t i = 0; i < str_values.size(); i++) {
116      if (static_cast<int32_t>(strlen(str_values.at(i))) == length) {
117        if (flat.IsOneByte()) {
118          if (CompareCharsEqual(str_values.at(i),
119                                flat.ToOneByteVector().begin(), length)) {
120            return Just(enum_values[i]);
121          }
122        } else {
123          if (CompareCharsEqual(str_values.at(i), flat.ToUC16Vector().begin(),
124                                length)) {
125            return Just(enum_values[i]);
126          }
127        }
128      }
129    }
130  }  // end of no_gc
131  THROW_NEW_ERROR_RETURN_VALUE(
132      isolate,
133      NewRangeError(MessageTemplate::kValueOutOfRange, value,
134                    isolate->factory()->NewStringFromAsciiChecked(method),
135                    property_str),
136      Nothing<T>());
137}
138
139// ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
140// ecma402/#sec-getoption
141//
142// This is specialized for the case when type is boolean.
143//
144// Returns true if options object has the property and stores the
145// result in value. Returns false if the value is not found. The
146// caller is required to use fallback value appropriately in this
147// case.
148//
149// method_name is a string denoting the method it called from; used when
150// printing the error message.
151V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<bool> GetBoolOption(
152    Isolate* isolate, Handle<JSReceiver> options, const char* property,
153    const char* method_name, bool* result);
154
155V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<int> GetNumberOption(
156    Isolate* isolate, Handle<JSReceiver> options, Handle<String> property,
157    int min, int max, int fallback);
158
159// ecma402/#sec-defaultnumberoption
160V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Maybe<int> DefaultNumberOption(
161    Isolate* isolate, Handle<Object> value, int min, int max, int fallback,
162    Handle<String> property);
163
164}  // namespace internal
165}  // namespace v8
166#endif  // V8_OBJECTS_OPTION_UTILS_H_
167