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 #include "src/objects/option-utils.h"
6
7 #include "src/numbers/conversions.h"
8 #include "src/objects/objects-inl.h"
9
10 namespace v8 {
11 namespace internal {
12
13 // ecma402/#sec-getoptionsobject
GetOptionsObject(Isolate * isolate,Handle<Object> options,const char * method_name)14 MaybeHandle<JSReceiver> GetOptionsObject(Isolate* isolate,
15 Handle<Object> options,
16 const char* method_name) {
17 // 1. If options is undefined, then
18 if (options->IsUndefined(isolate)) {
19 // a. Return ! ObjectCreate(null).
20 return isolate->factory()->NewJSObjectWithNullProto();
21 }
22 // 2. If Type(options) is Object, then
23 if (options->IsJSReceiver()) {
24 // a. Return options.
25 return Handle<JSReceiver>::cast(options);
26 }
27 // 3. Throw a TypeError exception.
28 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidArgument),
29 JSReceiver);
30 }
31
32 // ecma402/#sec-coerceoptionstoobject
CoerceOptionsToObject(Isolate * isolate,Handle<Object> options,const char * method_name)33 MaybeHandle<JSReceiver> CoerceOptionsToObject(Isolate* isolate,
34 Handle<Object> options,
35 const char* method_name) {
36 // 1. If options is undefined, then
37 if (options->IsUndefined(isolate)) {
38 // a. Return ! ObjectCreate(null).
39 return isolate->factory()->NewJSObjectWithNullProto();
40 }
41 // 2. Return ? ToObject(options).
42 ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
43 Object::ToObject(isolate, options, method_name),
44 JSReceiver);
45 return Handle<JSReceiver>::cast(options);
46 }
47
GetStringOption(Isolate * isolate,Handle<JSReceiver> options,const char * property,std::vector<const char * > values,const char * method_name,std::unique_ptr<char[]> * result)48 Maybe<bool> GetStringOption(Isolate* isolate, Handle<JSReceiver> options,
49 const char* property,
50 std::vector<const char*> values,
51 const char* method_name,
52 std::unique_ptr<char[]>* result) {
53 Handle<String> property_str =
54 isolate->factory()->NewStringFromAsciiChecked(property);
55
56 // 1. Let value be ? Get(options, property).
57 Handle<Object> value;
58 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
59 isolate, value,
60 Object::GetPropertyOrElement(isolate, options, property_str),
61 Nothing<bool>());
62
63 if (value->IsUndefined(isolate)) {
64 return Just(false);
65 }
66
67 // 2. c. Let value be ? ToString(value).
68 Handle<String> value_str;
69 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
70 isolate, value_str, Object::ToString(isolate, value), Nothing<bool>());
71 std::unique_ptr<char[]> value_cstr = value_str->ToCString();
72
73 // 2. d. if values is not undefined, then
74 if (values.size() > 0) {
75 // 2. d. i. If values does not contain an element equal to value,
76 // throw a RangeError exception.
77 for (size_t i = 0; i < values.size(); i++) {
78 if (strcmp(values.at(i), value_cstr.get()) == 0) {
79 // 2. e. return value
80 *result = std::move(value_cstr);
81 return Just(true);
82 }
83 }
84
85 Handle<String> method_str =
86 isolate->factory()->NewStringFromAsciiChecked(method_name);
87 THROW_NEW_ERROR_RETURN_VALUE(
88 isolate,
89 NewRangeError(MessageTemplate::kValueOutOfRange, value, method_str,
90 property_str),
91 Nothing<bool>());
92 }
93
94 // 2. e. return value
95 *result = std::move(value_cstr);
96 return Just(true);
97 }
98
GetBoolOption(Isolate * isolate,Handle<JSReceiver> options,const char * property,const char * method_name,bool * result)99 V8_WARN_UNUSED_RESULT Maybe<bool> GetBoolOption(Isolate* isolate,
100 Handle<JSReceiver> options,
101 const char* property,
102 const char* method_name,
103 bool* result) {
104 Handle<String> property_str =
105 isolate->factory()->NewStringFromAsciiChecked(property);
106
107 // 1. Let value be ? Get(options, property).
108 Handle<Object> value;
109 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
110 isolate, value,
111 Object::GetPropertyOrElement(isolate, options, property_str),
112 Nothing<bool>());
113
114 // 2. If value is not undefined, then
115 if (!value->IsUndefined(isolate)) {
116 // 2. b. i. Let value be ToBoolean(value).
117 *result = value->BooleanValue(isolate);
118
119 // 2. e. return value
120 return Just(true);
121 }
122
123 return Just(false);
124 }
125
126 // ecma402/#sec-defaultnumberoption
DefaultNumberOption(Isolate * isolate,Handle<Object> value,int min,int max,int fallback,Handle<String> property)127 Maybe<int> DefaultNumberOption(Isolate* isolate, Handle<Object> value, int min,
128 int max, int fallback, Handle<String> property) {
129 // 2. Else, return fallback.
130 if (value->IsUndefined()) return Just(fallback);
131
132 // 1. If value is not undefined, then
133 // a. Let value be ? ToNumber(value).
134 Handle<Object> value_num;
135 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
136 isolate, value_num, Object::ToNumber(isolate, value), Nothing<int>());
137 DCHECK(value_num->IsNumber());
138
139 // b. If value is NaN or less than minimum or greater than maximum, throw a
140 // RangeError exception.
141 if (value_num->IsNaN() || value_num->Number() < min ||
142 value_num->Number() > max) {
143 THROW_NEW_ERROR_RETURN_VALUE(
144 isolate,
145 NewRangeError(MessageTemplate::kPropertyValueOutOfRange, property),
146 Nothing<int>());
147 }
148
149 // The max and min arguments are integers and the above check makes
150 // sure that we are within the integer range making this double to
151 // int conversion safe.
152 //
153 // c. Return floor(value).
154 return Just(FastD2I(floor(value_num->Number())));
155 }
156
157 // ecma402/#sec-getnumberoption
GetNumberOption(Isolate * isolate,Handle<JSReceiver> options,Handle<String> property,int min,int max,int fallback)158 Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
159 Handle<String> property, int min, int max,
160 int fallback) {
161 // 1. Let value be ? Get(options, property).
162 Handle<Object> value;
163 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
164 isolate, value, JSReceiver::GetProperty(isolate, options, property),
165 Nothing<int>());
166
167 // Return ? DefaultNumberOption(value, minimum, maximum, fallback).
168 return DefaultNumberOption(isolate, value, min, max, fallback, property);
169 }
170
171 } // namespace internal
172 } // namespace v8
173