1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/builtins/builtins_relative_time_format.h" 17 18namespace panda::ecmascript::builtins { 19JSTaggedValue BuiltinsRelativeTimeFormat::RelativeTimeFormatConstructor(EcmaRuntimeCallInfo *argv) 20{ 21 JSThread *thread = argv->GetThread(); 22 BUILTINS_API_TRACE(thread, RelativeTimeFormat, Constructor); 23 [[maybe_unused]] EcmaHandleScope scope(thread); 24 EcmaVM *ecmaVm = thread->GetEcmaVM(); 25 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 26 ObjectFactory *factory = ecmaVm->GetFactory(); 27 28 // 1. If NewTarget is undefined, throw a TypeError exception. 29 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 30 if (newTarget->IsUndefined()) { 31 THROW_TYPE_ERROR_AND_RETURN(thread, "newTarget is undefined", JSTaggedValue::Exception()); 32 } 33 34 // 2. Let relativeTimeFormat be ? OrdinaryCreateFromConstructor 35 // (NewTarget, "%RelativeTimeFormatPrototype%", « [[InitializedRelativeTimeFormat]], 36 // [[Locale]], [[DataLocale]], [[Style]], [[Numeric]], [[NumberFormat]], [[NumberingSystem]], [[PluralRules]] »). 37 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 38 JSHandle<JSObject> newObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 39 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 40 JSHandle<JSRelativeTimeFormat> relativeTimeFormat = JSHandle<JSRelativeTimeFormat>::Cast(newObject); 41 42 // 3. Perform ? InitializeRelativeTimeFormat(relativeTimeFormat, locales, options). 43 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 44 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 45 JSRelativeTimeFormat::InitializeRelativeTimeFormat(thread, relativeTimeFormat, locales, options); 46 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 47 48 // 4. Intl.RelativeTimeFormat.prototype[ @@toStringTag ] 49 // This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }. 50 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 51 bool isInstanceOf = JSObject::InstanceOf(thread, thisValue, env->GetRelativeTimeFormatFunction()); 52 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 53 if (newTarget->IsUndefined() && thisValue->IsJSObject() && isInstanceOf) { 54 PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(relativeTimeFormat), false, false, true); 55 JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol()); 56 JSTaggedValue::DefinePropertyOrThrow(thread, thisValue, key, descriptor); 57 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 58 return thisValue.GetTaggedValue(); 59 } 60 61 return relativeTimeFormat.GetTaggedValue(); 62} 63 64JSTaggedValue BuiltinsRelativeTimeFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *argv) 65{ 66 JSThread *thread = argv->GetThread(); 67 BUILTINS_API_TRACE(thread, RelativeTimeFormat, SupportedLocalesOf); 68 [[maybe_unused]] EcmaHandleScope scope(thread); 69 70 // 1. Let availableLocales be %RelativeTimeFormat%.[[AvailableLocales]]. 71 std::vector<std::string> availableStringLocales = 72 intl::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr); 73 JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales); 74 75 // 2. Let requestedLocales be ? CanonicalizeLocaleList(locales). 76 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 77 JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 78 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 79 80 // 3. Return ? SupportedLocales(availableLocales, requestedLocales, options). 81 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 82 JSHandle<JSArray> result = JSLocale::SupportedLocales(thread, availableLocales, requestedLocales, options); 83 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 84 return result.GetTaggedValue(); 85} 86 87JSTaggedValue BuiltinsRelativeTimeFormat::Format(EcmaRuntimeCallInfo *argv) 88{ 89 JSThread *thread = argv->GetThread(); 90 BUILTINS_API_TRACE(thread, RelativeTimeFormat, Format); 91 [[maybe_unused]] EcmaHandleScope scope(thread); 92 93 // 1. Let relativeTimeFormat be the this value. 94 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 95 96 // 2. Perform ? RequireInternalSlot(relativeTimeFormat, [[InitializedRelativeTimeFormat]]). 97 if (!thisValue->IsJSRelativeTimeFormat()) { 98 THROW_TYPE_ERROR_AND_RETURN(thread, "this is not rtf object", JSTaggedValue::Exception()); 99 } 100 101 // 3. Let value be ? ToNumber(value). 102 double x = 0.0; 103 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 104 JSTaggedNumber temp = JSTaggedValue::ToNumber(thread, value); 105 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 106 x = temp.GetNumber(); 107 108 // 4. Let unit be ? ToString(unit). 109 JSHandle<JSTaggedValue> unitValue = GetCallArg(argv, 1); 110 JSHandle<EcmaString> unit = JSTaggedValue::ToString(thread, unitValue); 111 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 112 113 // 5. Return ? FormatRelativeTime(relativeTimeFormat, value, unit). 114 JSHandle<JSRelativeTimeFormat> relativeTimeFormat = JSHandle<JSRelativeTimeFormat>::Cast(thisValue); 115 JSHandle<EcmaString> result = JSRelativeTimeFormat::Format(thread, x, unit, relativeTimeFormat); 116 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 117 return result.GetTaggedValue(); 118} 119 120JSTaggedValue BuiltinsRelativeTimeFormat::FormatToParts(EcmaRuntimeCallInfo *argv) 121{ 122 JSThread *thread = argv->GetThread(); 123 BUILTINS_API_TRACE(thread, RelativeTimeFormat, FormatToParts); 124 [[maybe_unused]] EcmaHandleScope scope(thread); 125 126 // 1. Let relativeTimeFormat be the this value. 127 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 128 129 // 2. Perform ? RequireInternalSlot(relativeTimeFormat, [[InitializedRelativeTimeFormat]]). 130 if (!thisValue->IsJSRelativeTimeFormat()) { 131 THROW_TYPE_ERROR_AND_RETURN(thread, "this is not rtf object", JSTaggedValue::Exception()); 132 } 133 134 // 3. Let value be ? ToNumber(value). 135 double x = 0.0; 136 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 137 JSTaggedNumber temp = JSTaggedValue::ToNumber(thread, value); 138 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 139 x = temp.GetNumber(); 140 141 // 4. Let unit be ? ToString(unit). 142 JSHandle<JSTaggedValue> unitValue = GetCallArg(argv, 1); 143 JSHandle<EcmaString> unit = JSTaggedValue::ToString(thread, unitValue); 144 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 145 146 // 5. Return ? FormatRelativeTime(relativeTimeFormat, value, unit). 147 JSHandle<JSRelativeTimeFormat> relativeTimeFormat = JSHandle<JSRelativeTimeFormat>::Cast(thisValue); 148 JSHandle<JSArray> result = JSRelativeTimeFormat::FormatToParts(thread, x, unit, relativeTimeFormat); 149 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 150 return result.GetTaggedValue(); 151} 152 153JSTaggedValue BuiltinsRelativeTimeFormat::ResolvedOptions(EcmaRuntimeCallInfo *argv) 154{ 155 JSThread *thread = argv->GetThread(); 156 BUILTINS_API_TRACE(thread, RelativeTimeFormat, ResolvedOptions); 157 [[maybe_unused]] EcmaHandleScope scope(thread); 158 159 // 1. Let relativeTimeFormat be the this value. 160 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 161 162 // 2. Perform ? RequireInternalSlot(relativeTimeFormat, [[InitializedRelativeTimeFormat]]). 163 if (!thisValue->IsJSRelativeTimeFormat()) { 164 THROW_TYPE_ERROR_AND_RETURN(thread, "this is not rtf object", JSTaggedValue::Exception()); 165 } 166 167 // 3. Let options be ! ObjectCreate(%ObjectPrototype%). 168 auto ecmaVm = thread->GetEcmaVM(); 169 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 170 ObjectFactory *factory = ecmaVm->GetFactory(); 171 JSHandle<JSFunction> ctor(env->GetObjectFunction()); 172 JSHandle<JSObject> options(factory->NewJSObjectByConstructor(ctor)); 173 174 // 4. perform resolvedOptions 175 JSHandle<JSRelativeTimeFormat> relativeTimeFormat = JSHandle<JSRelativeTimeFormat>::Cast(thisValue); 176 JSRelativeTimeFormat::ResolvedOptions(thread, relativeTimeFormat, options); 177 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 178 // 5. Return options. 179 return options.GetTaggedValue(); 180} 181} // namespace panda::ecmascript::builtins