81420776a236582e9f34efdffd6a3023464fc0d9
[WebKit-https.git] / Source / JavaScriptCore / runtime / IntlDateTimeFormatPrototype.cpp
1 /*
2  * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
3  * Copyright (C) 2016 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "IntlDateTimeFormatPrototype.h"
29
30 #if ENABLE(INTL)
31
32 #include "BuiltinNames.h"
33 #include "DateConstructor.h"
34 #include "Error.h"
35 #include "IntlDateTimeFormat.h"
36 #include "IntlObject.h"
37 #include "JSBoundFunction.h"
38 #include "JSCInlines.h"
39 #include "JSObjectInlines.h"
40
41 namespace JSC {
42
43 static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState*);
44 static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState*);
45
46 }
47
48 #include "IntlDateTimeFormatPrototype.lut.h"
49
50 namespace JSC {
51
52 const ClassInfo IntlDateTimeFormatPrototype::s_info = { "Object", &IntlDateTimeFormat::s_info, &dateTimeFormatPrototypeTable, CREATE_METHOD_TABLE(IntlDateTimeFormatPrototype) };
53
54 /* Source for IntlDateTimeFormatPrototype.lut.h
55 @begin dateTimeFormatPrototypeTable
56   format           IntlDateTimeFormatPrototypeGetterFormat         DontEnum|Accessor
57   resolvedOptions  IntlDateTimeFormatPrototypeFuncResolvedOptions  DontEnum|Function 0
58 @end
59 */
60
61 IntlDateTimeFormatPrototype* IntlDateTimeFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
62 {
63     IntlDateTimeFormatPrototype* object = new (NotNull, allocateCell<IntlDateTimeFormatPrototype>(vm.heap)) IntlDateTimeFormatPrototype(vm, structure);
64     object->finishCreation(vm, structure);
65     return object;
66 }
67
68 Structure* IntlDateTimeFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
69 {
70     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
71 }
72
73 IntlDateTimeFormatPrototype::IntlDateTimeFormatPrototype(VM& vm, Structure* structure)
74     : IntlDateTimeFormat(vm, structure)
75 {
76 }
77
78 void IntlDateTimeFormatPrototype::finishCreation(VM& vm, Structure*)
79 {
80     Base::finishCreation(vm);
81 }
82
83 static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatFuncFormatDateTime(ExecState* state)
84 {
85     VM& vm = state->vm();
86     auto scope = DECLARE_THROW_SCOPE(vm);
87     // 12.3.4 DateTime Format Functions (ECMA-402 2.0)
88     // 1. Let dtf be the this value.
89     // 2. Assert: Type(dtf) is Object and dtf has an [[initializedDateTimeFormat]] internal slot whose value is true.
90     IntlDateTimeFormat* format = jsCast<IntlDateTimeFormat*>(state->thisValue());
91
92     JSValue date = state->argument(0);
93     double value;
94
95     // 3. If date is not provided or is undefined, then
96     if (date.isUndefined()) {
97         // a. Let x be %Date_now%().
98         value = JSValue::decode(dateNow(state)).toNumber(state);
99     } else {
100         // 4. Else
101         // a. Let x be ToNumber(date).
102         value = date.toNumber(state);
103         // b. ReturnIfAbrupt(x).
104         RETURN_IF_EXCEPTION(scope, encodedJSValue());
105     }
106
107     // 5. Return FormatDateTime(dtf, x).
108     scope.release();
109     return JSValue::encode(format->format(*state, value));
110 }
111
112 EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState* state)
113 {
114     VM& vm = state->vm();
115     auto scope = DECLARE_THROW_SCOPE(vm);
116
117     // 12.3.3 Intl.DateTimeFormat.prototype.format (ECMA-402 2.0)
118     // 1. Let dtf be this DateTimeFormat object.
119     IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
120
121     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
122     // https://bugs.webkit.org/show_bug.cgi?id=153679
123     if (!dtf) {
124         JSValue value = state->thisValue().get(state, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
125         RETURN_IF_EXCEPTION(scope, encodedJSValue());
126         dtf = jsDynamicCast<IntlDateTimeFormat*>(value);
127     }
128
129     // 2. ReturnIfAbrupt(dtf).
130     if (!dtf)
131         return JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat")));
132
133     JSBoundFunction* boundFormat = dtf->boundFormat();
134     // 3. If the [[boundFormat]] internal slot of this DateTimeFormat object is undefined,
135     if (!boundFormat) {
136         JSGlobalObject* globalObject = dtf->globalObject();
137         // a. Let F be a new built-in function object as defined in 12.3.4.
138         // b. The value of F’s length property is 1. (Note: F’s length property was 0 in ECMA-402 1.0)
139         JSFunction* targetObject = JSFunction::create(vm, globalObject, 1, ASCIILiteral("format"), IntlDateTimeFormatFuncFormatDateTime, NoIntrinsic);
140         JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
141         if (!boundArgs)
142             return JSValue::encode(throwOutOfMemoryError(state, scope));
143
144         // c. Let bf be BoundFunctionCreate(F, «this value»).
145         boundFormat = JSBoundFunction::create(vm, state, globalObject, targetObject, dtf, boundArgs, 1, ASCIILiteral("format"));
146         RETURN_IF_EXCEPTION(scope, encodedJSValue());
147         // d. Set dtf.[[boundFormat]] to bf.
148         dtf->setBoundFormat(vm, boundFormat);
149     }
150     // 4. Return dtf.[[boundFormat]].
151     return JSValue::encode(boundFormat);
152 }
153
154 EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState* state)
155 {
156     VM& vm = state->vm();
157     auto scope = DECLARE_THROW_SCOPE(vm);
158
159     // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
160     IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
161
162     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
163     // https://bugs.webkit.org/show_bug.cgi?id=153679
164     if (!dateTimeFormat) {
165         JSValue value = state->thisValue().get(state, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
166         RETURN_IF_EXCEPTION(scope, encodedJSValue());
167         dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(value);
168     }
169
170     if (!dateTimeFormat)
171         return JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat")));
172
173     scope.release();
174     return JSValue::encode(dateTimeFormat->resolvedOptions(*state));
175 }
176
177 } // namespace JSC
178
179 #endif // ENABLE(INTL)