Property setters should not be called for bound arguments list entries.
[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         // c. Let bf be BoundFunctionCreate(F, «this value»).
141         boundFormat = JSBoundFunction::create(vm, state, globalObject, targetObject, dtf, nullptr, 1, ASCIILiteral("format"));
142         RETURN_IF_EXCEPTION(scope, encodedJSValue());
143         // d. Set dtf.[[boundFormat]] to bf.
144         dtf->setBoundFormat(vm, boundFormat);
145     }
146     // 4. Return dtf.[[boundFormat]].
147     return JSValue::encode(boundFormat);
148 }
149
150 EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState* state)
151 {
152     VM& vm = state->vm();
153     auto scope = DECLARE_THROW_SCOPE(vm);
154
155     // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
156     IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
157
158     // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns.
159     // https://bugs.webkit.org/show_bug.cgi?id=153679
160     if (!dateTimeFormat) {
161         JSValue value = state->thisValue().get(state, vm.propertyNames->builtinNames().intlSubstituteValuePrivateName());
162         RETURN_IF_EXCEPTION(scope, encodedJSValue());
163         dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(value);
164     }
165
166     if (!dateTimeFormat)
167         return JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat")));
168
169     scope.release();
170     return JSValue::encode(dateTimeFormat->resolvedOptions(*state));
171 }
172
173 } // namespace JSC
174
175 #endif // ENABLE(INTL)