1 /*
2  * Copyright (c) 2022 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_list_format.h"
17 
18 #include "ecmascript/intl/locale_helper.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_list_format.h"
21 
22 namespace panda::ecmascript::builtins {
ListFormatConstructor(EcmaRuntimeCallInfo *argv)23 JSTaggedValue BuiltinsListFormat::ListFormatConstructor(EcmaRuntimeCallInfo *argv)
24 {
25     JSThread *thread = argv->GetThread();
26     BUILTINS_API_TRACE(thread, ListFormat, Constructor);
27     [[maybe_unused]] EcmaHandleScope scope(thread);
28     EcmaVM *ecmaVm = thread->GetEcmaVM();
29     ObjectFactory *factory = ecmaVm->GetFactory();
30 
31     // 1. If NewTarget is undefined, throw a TypeError exception.
32     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33     if (newTarget->IsUndefined()) {
34         THROW_TYPE_ERROR_AND_RETURN(thread, "newTarget is undefined", JSTaggedValue::Exception());
35     }
36 
37     // 2. Let listFormat be ? OrdinaryCreateFromConstructor
38     // (NewTarget, "%ListFormat.prototype%", « [[InitializedListFormat]], [[Locale]],
39     // [[Type]], [[Style]], [[Templates]] »).
40 
41     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
42     JSHandle<JSObject> newObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
43     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
44     JSHandle<JSListFormat> listFormat = JSHandle<JSListFormat>::Cast(newObject);
45 
46     // 3. Perform ? InitializeListFormat(listFormat, locales, options).
47     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
48     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
49     listFormat = JSListFormat::InitializeListFormat(thread, listFormat, locales, options);
50     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
51     return listFormat.GetTaggedValue();
52 }
53 
54 // 13.3.2 Intl.ListFormat.supportedLocalesOf ( locales [ , options ] )
SupportedLocalesOf(EcmaRuntimeCallInfo *argv)55 JSTaggedValue BuiltinsListFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *argv)
56 {
57     JSThread *thread = argv->GetThread();
58     BUILTINS_API_TRACE(thread, ListFormat, SupportedLocalesOf);
59     [[maybe_unused]] EcmaHandleScope scope(thread);
60 
61     // 1. Let availableLocales be %ListFormat%.[[AvailableLocales]].
62     JSHandle<TaggedArray> availableLocales = JSListFormat::GetAvailableLocales(thread);
63 
64     // 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
65     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
66     JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales);
67     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
68 
69     // 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).
70     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
71     JSHandle<JSArray> result = JSLocale::SupportedLocales(thread, availableLocales, requestedLocales, options);
72     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
73     return result.GetTaggedValue();
74 }
75 
76 // 13.4.3 Intl.ListFormat.prototype.format( list )
Format(EcmaRuntimeCallInfo *argv)77 JSTaggedValue BuiltinsListFormat::Format(EcmaRuntimeCallInfo *argv)
78 {
79     JSThread *thread = argv->GetThread();
80     BUILTINS_API_TRACE(thread, ListFormat, Format);
81     [[maybe_unused]] EcmaHandleScope scope(thread);
82 
83     // 1. Let lf be the this value.
84     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
85 
86     // 2. Perform ? RequireInternalSlot(lf, [[InitializedListFormat]]).
87     if (!thisValue->IsJSListFormat()) {
88         THROW_TYPE_ERROR_AND_RETURN(thread, "this is not JSListFormat", JSTaggedValue::Exception());
89     }
90 
91     // 3. Let stringList be ? StringListFromIterable(list).
92     JSHandle<JSTaggedValue> list = GetCallArg(argv, 0);
93     JSHandle<JSTaggedValue> listArray = JSListFormat::StringListFromIterable(thread, list);
94     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
95 
96     // 4. Return FormatList(lf, stringList).
97     JSHandle<JSListFormat> listFormat = JSHandle<JSListFormat>::Cast(thisValue);
98     JSHandle<JSArray> array = JSHandle<JSArray>::Cast(listArray);
99     JSHandle<EcmaString> result = JSListFormat::FormatList(thread, listFormat, array);
100     return result.GetTaggedValue();
101 }
102 
103 // 13.4.4 Intl.ListFormat.prototype.formatToParts ( list )
FormatToParts(EcmaRuntimeCallInfo *argv)104 JSTaggedValue BuiltinsListFormat::FormatToParts(EcmaRuntimeCallInfo *argv)
105 {
106     JSThread *thread = argv->GetThread();
107     BUILTINS_API_TRACE(thread, ListFormat, FormatToParts);
108     [[maybe_unused]] EcmaHandleScope scope(thread);
109 
110     // 1. Let lf be the this value.
111     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
112 
113     // 2. Perform ? RequireInternalSlot(lf, [[InitializedListFormat]]).
114     if (!thisValue->IsJSListFormat()) {
115         THROW_TYPE_ERROR_AND_RETURN(thread, "this is not JSListFormat", JSTaggedValue::Exception());
116     }
117 
118     // 3. Let stringList be ? StringListFromIterable(list).
119     JSHandle<JSTaggedValue> list = GetCallArg(argv, 0);
120     JSHandle<JSTaggedValue> listArray = JSListFormat::StringListFromIterable(thread, list);
121     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
122 
123     // 4 Return FormatListToParts(lf, stringList).
124     JSHandle<JSListFormat> listFormat = JSHandle<JSListFormat>::Cast(thisValue);
125     JSHandle<JSArray> array = JSHandle<JSArray>::Cast(listArray);
126 
127     JSHandle<JSArray> result = JSListFormat::FormatListToParts(thread, listFormat, array);
128     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
129     return result.GetTaggedValue();
130 }
131 
132 // 13.4.5 Intl.ListFormat.prototype.resolvedOptions()
ResolvedOptions(EcmaRuntimeCallInfo *argv)133 JSTaggedValue BuiltinsListFormat::ResolvedOptions(EcmaRuntimeCallInfo *argv)
134 {
135     JSThread *thread = argv->GetThread();
136     BUILTINS_API_TRACE(thread, ListFormat, ResolvedOptions);
137     [[maybe_unused]] EcmaHandleScope scope(thread);
138 
139     // 1. Let lf be the this value.
140     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
141 
142     // 2. Perform ? RequireInternalSlot(lf, [[InitializedListFormat]]).
143     if (!thisValue->IsJSListFormat()) {
144         THROW_TYPE_ERROR_AND_RETURN(thread, "this is not JSListFormat", JSTaggedValue::Exception());
145     }
146 
147     // 3 .Let options be ! OrdinaryObjectCreate(%Object.prototype%).
148     auto ecmaVm = thread->GetEcmaVM();
149     JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
150     ObjectFactory *factory = ecmaVm->GetFactory();
151     JSHandle<JSFunction> ctor(env->GetObjectFunction());
152     JSHandle<JSObject> options(factory->NewJSObjectByConstructor(ctor));
153 
154     // 4. For each row of Table 9, except the header row, in table order, do
155     //  Let p be the Property value of the current row.
156     //  Let v be the value of lf's internal slot whose name is the Internal Slot value of the current row.
157     //  Assert: v is not undefined.
158     //  Perform ! CreateDataPropertyOrThrow(options, p, v).
159     JSHandle<JSListFormat> listFormat = JSHandle<JSListFormat>::Cast(thisValue);
160     JSListFormat::ResolvedOptions(thread, listFormat, options);
161     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
162 
163     // 5. Return options.
164     return options.GetTaggedValue();
165 }
166 }  // namespace panda::ecmascript::builtins