IntlNumberFormatPrototype.cpp
1 /* 2 * Copyright (C) 2015 Andy VanWagoner (andy@vanwagoner.family) 3 * Copyright (C) 2016-2019 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 "IntlNumberFormatPrototype.h" 29 30 #include "BuiltinNames.h" 31 #include "IntlNumberFormatInlines.h" 32 #include "JSBoundFunction.h" 33 #include "JSCInlines.h" 34 35 namespace JSC { 36 37 static JSC_DECLARE_HOST_FUNCTION(IntlNumberFormatPrototypeGetterFormat); 38 static JSC_DECLARE_HOST_FUNCTION(IntlNumberFormatPrototypeFuncFormatToParts); 39 static JSC_DECLARE_HOST_FUNCTION(IntlNumberFormatPrototypeFuncResolvedOptions); 40 static JSC_DECLARE_HOST_FUNCTION(IntlNumberFormatFuncFormat); 41 42 } 43 44 #include "IntlNumberFormatPrototype.lut.h" 45 46 namespace JSC { 47 48 const ClassInfo IntlNumberFormatPrototype::s_info = { "Intl.NumberFormat", &Base::s_info, &numberFormatPrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlNumberFormatPrototype) }; 49 50 /* Source for IntlNumberFormatPrototype.lut.h 51 @begin numberFormatPrototypeTable 52 format IntlNumberFormatPrototypeGetterFormat DontEnum|Accessor 53 formatToParts IntlNumberFormatPrototypeFuncFormatToParts DontEnum|Function 1 54 resolvedOptions IntlNumberFormatPrototypeFuncResolvedOptions DontEnum|Function 0 55 @end 56 */ 57 58 IntlNumberFormatPrototype* IntlNumberFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure) 59 { 60 IntlNumberFormatPrototype* object = new (NotNull, allocateCell<IntlNumberFormatPrototype>(vm.heap)) IntlNumberFormatPrototype(vm, structure); 61 object->finishCreation(vm); 62 return object; 63 } 64 65 Structure* IntlNumberFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 66 { 67 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); 68 } 69 70 IntlNumberFormatPrototype::IntlNumberFormatPrototype(VM& vm, Structure* structure) 71 : Base(vm, structure) 72 { 73 } 74 75 void IntlNumberFormatPrototype::finishCreation(VM& vm) 76 { 77 Base::finishCreation(vm); 78 ASSERT(inherits(vm, info())); 79 JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); 80 } 81 82 // https://tc39.es/ecma402/#sec-number-format-functions 83 JSC_DEFINE_HOST_FUNCTION(IntlNumberFormatFuncFormat, (JSGlobalObject* globalObject, CallFrame* callFrame)) 84 { 85 VM& vm = globalObject->vm(); 86 auto scope = DECLARE_THROW_SCOPE(vm); 87 auto* numberFormat = jsCast<IntlNumberFormat*>(callFrame->thisValue()); 88 89 JSValue bigIntOrNumber = callFrame->argument(0).toNumeric(globalObject); 90 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 91 92 scope.release(); 93 if (bigIntOrNumber.isNumber()) { 94 double value = bigIntOrNumber.asNumber(); 95 return JSValue::encode(numberFormat->format(globalObject, value)); 96 } 97 98 #if USE(BIGINT32) 99 if (bigIntOrNumber.isBigInt32()) { 100 JSBigInt* value = JSBigInt::createFrom(globalObject, bigIntOrNumber.bigInt32AsInt32()); 101 RETURN_IF_EXCEPTION(scope, { }); 102 RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->format(globalObject, value))); 103 } 104 #endif 105 106 ASSERT(bigIntOrNumber.isHeapBigInt()); 107 JSBigInt* value = bigIntOrNumber.asHeapBigInt(); 108 return JSValue::encode(numberFormat->format(globalObject, value)); 109 } 110 111 JSC_DEFINE_HOST_FUNCTION(IntlNumberFormatPrototypeGetterFormat, (JSGlobalObject* globalObject, CallFrame* callFrame)) 112 { 113 VM& vm = globalObject->vm(); 114 auto scope = DECLARE_THROW_SCOPE(vm); 115 116 // 11.3.3 Intl.NumberFormat.prototype.format (ECMA-402 2.0) 117 // 1. Let nf be this NumberFormat object. 118 auto* nf = IntlNumberFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue()); 119 RETURN_IF_EXCEPTION(scope, { }); 120 if (UNLIKELY(!nf)) 121 return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat"_s)); 122 123 JSBoundFunction* boundFormat = nf->boundFormat(); 124 // 2. If nf.[[boundFormat]] is undefined, 125 if (!boundFormat) { 126 JSGlobalObject* globalObject = nf->globalObject(vm); 127 // a. Let F be a new built-in function object as defined in 11.3.4. 128 // b. The value of F’s length property is 1. 129 auto* targetObject = JSFunction::create(vm, globalObject, 1, "format"_s, IntlNumberFormatFuncFormat, NoIntrinsic); 130 // c. Let bf be BoundFunctionCreate(F, «this value»). 131 boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, nf, nullptr, 1, nullptr); 132 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 133 // d. Set nf.[[boundFormat]] to bf. 134 nf->setBoundFormat(vm, boundFormat); 135 } 136 // 3. Return nf.[[boundFormat]]. 137 return JSValue::encode(boundFormat); 138 } 139 140 JSC_DEFINE_HOST_FUNCTION(IntlNumberFormatPrototypeFuncFormatToParts, (JSGlobalObject* globalObject, CallFrame* callFrame)) 141 { 142 VM& vm = globalObject->vm(); 143 auto scope = DECLARE_THROW_SCOPE(vm); 144 145 // Intl.NumberFormat.prototype.formatToParts (ECMA-402) 146 // https://tc39.github.io/ecma402/#sec-intl.numberformat.prototype.formattoparts 147 148 // Do not use unwrapForOldFunctions. 149 auto* numberFormat = jsDynamicCast<IntlNumberFormat*>(vm, callFrame->thisValue()); 150 if (UNLIKELY(!numberFormat)) 151 return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.formatToParts called on value that's not an object initialized as a NumberFormat"_s)); 152 153 double value = callFrame->argument(0).toNumber(globalObject); 154 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 155 156 RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatToParts(globalObject, value))); 157 } 158 159 JSC_DEFINE_HOST_FUNCTION(IntlNumberFormatPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame)) 160 { 161 VM& vm = globalObject->vm(); 162 auto scope = DECLARE_THROW_SCOPE(vm); 163 164 // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0) 165 166 auto* numberFormat = IntlNumberFormat::unwrapForOldFunctions(globalObject, callFrame->thisValue()); 167 RETURN_IF_EXCEPTION(scope, { }); 168 if (UNLIKELY(!numberFormat)) 169 return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat"_s)); 170 171 RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->resolvedOptions(globalObject))); 172 } 173 174 } // namespace JSC