• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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