blob: a6a1f14102976d56cabc467ea6dc6e07065a5ae8 [file]
// 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/object-conversions-inl.h"
#include "src/objects/objects-inl.h"
namespace v8 {
namespace internal {
// https://tc39.es/ecma402/#sec-getoptionsobject
MaybeDirectHandle<JSReceiver> GetOptionsObject(Isolate* isolate,
DirectHandle<Object> options,
const char* method_name) {
// 1. If options is undefined, then
if (IsUndefined(*options)) {
// a. Return ! ObjectCreate(null).
return isolate->factory()->NewJSObjectWithNullProto();
}
// 2. If Type(options) is Object, then
if (IsJSReceiver(*options)) {
// a. Return options.
return Cast<JSReceiver>(options);
}
// 3. Throw a TypeError exception.
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidArgument));
}
// https://tc39.es/ecma402/#sec-coerceoptionstoobject
MaybeDirectHandle<JSReceiver> CoerceOptionsToObject(
Isolate* isolate, DirectHandle<Object> options, const char* method_name) {
// 1. If options is undefined, then
if (IsUndefined(*options)) {
// a. Return ! ObjectCreate(null).
return isolate->factory()->NewJSObjectWithNullProto();
}
// 2. Return ? ToObject(options).
ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
Object::ToObject(isolate, options, method_name));
return Cast<JSReceiver>(options);
}
Maybe<bool> GetStringOption(Isolate* isolate, DirectHandle<JSReceiver> options,
DirectHandle<String> property,
const char* method_name,
DirectHandle<String>* result) {
// 1. Let value be ? Get(options, property).
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, Object::GetPropertyOrElement(isolate, options, property));
if (IsUndefined(*value)) {
return Just(false);
}
// 2. c. Let value be ? ToString(value).
DirectHandle<String> value_str;
ASSIGN_RETURN_ON_EXCEPTION(isolate, value_str,
Object::ToString(isolate, value));
// 2. d. if values is not undefined, then
// Skip: this overload is only for when values is undefined
// 2. e. return value
*result = value_str;
return Just(true);
}
V8_WARN_UNUSED_RESULT Maybe<bool> GetBoolOption(
Isolate* isolate, DirectHandle<JSReceiver> options,
DirectHandle<String> property, const char* method_name, bool* result) {
// 1. Let value be ? Get(options, property).
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, Object::GetPropertyOrElement(isolate, options, property));
// 2. If value is not undefined, then
if (!IsUndefined(*value)) {
// 2. b. i. Let value be ToBoolean(value).
*result = Object::BooleanValue(*value, isolate);
// 2. e. return value
return Just(true);
}
return Just(false);
}
// https://tc39.es/ecma402/#sec-defaultnumberoption
Maybe<int> DefaultNumberOption(Isolate* isolate, DirectHandle<Object> value,
int min, int max, int fallback,
DirectHandle<String> property) {
// 2. Else, return fallback.
if (IsUndefined(*value)) return Just(fallback);
// 1. If value is not undefined, then
// a. Let value be ? ToNumber(value).
DirectHandle<Number> value_num;
ASSIGN_RETURN_ON_EXCEPTION(isolate, value_num,
Object::ToNumber(isolate, value));
DCHECK(IsNumber(*value_num));
// b. If value is NaN or less than minimum or greater than maximum, throw a
// RangeError exception.
if (IsNaN(*value_num) || Object::NumberValue(*value_num) < min ||
Object::NumberValue(*value_num) > max) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange, property));
}
// 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(Object::NumberValue(*value_num))));
}
// https://tc39.es/ecma402/#sec-getnumberoption
Maybe<int> GetNumberOption(Isolate* isolate, DirectHandle<JSReceiver> options,
DirectHandle<String> property, int min, int max,
int fallback) {
// 1. Let value be ? Get(options, property).
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, JSReceiver::GetProperty(isolate, options, property));
// Return ? DefaultNumberOption(value, minimum, maximum, fallback).
return DefaultNumberOption(isolate, value, min, max, fallback, property);
}
// https://tc39.es/ecma262/#sec-getoption while type is "number"
Maybe<double> GetNumberOptionAsDouble(Isolate* isolate,
DirectHandle<JSReceiver> options,
DirectHandle<String> property,
double default_value) {
// 1. Let value be ? Get(options, property).
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, JSReceiver::GetProperty(isolate, options, property));
// 2. If value is undefined, then
if (IsUndefined(*value)) {
// b. Return default.
return Just(default_value);
}
// 4. Else if type is "number", then
// a. Set value to ? ToNumber(value).
DirectHandle<Number> value_num;
ASSIGN_RETURN_ON_EXCEPTION(isolate, value_num,
Object::ToNumber(isolate, value));
// b. If value is NaN, throw a RangeError exception.
if (IsNaN(*value_num)) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange, property));
}
// 7. Return value.
return Just(Object::NumberValue(*value_num));
}
} // namespace internal
} // namespace v8