File indexing completed on 2024-05-12 15:43:36

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
0005  *  Copyright (C) 2003 Apple Computer, Inc.
0006  *
0007  *  This library is free software; you can redistribute it and/or
0008  *  modify it under the terms of the GNU Library General Public
0009  *  License as published by the Free Software Foundation; either
0010  *  version 2 of the License, or (at your option) any later version.
0011  *
0012  *  This library is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  *  Library General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU Library General Public License
0018  *  along with this library; see the file COPYING.LIB.  If not, write to
0019  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  *  Boston, MA 02110-1301, USA.
0021  *
0022  */
0023 
0024 #include "value.h"
0025 
0026 #include "error_object.h"
0027 #include "nodes.h"
0028 #include "operations.h"
0029 #include <stdio.h>
0030 #include <string.h>
0031 #include <wtf/MathExtras.h>
0032 
0033 namespace KJS
0034 {
0035 
0036 static const double D16 = 65536.0;
0037 static const double D32 = 4294967296.0;
0038 
0039 void *JSCell::operator new(size_t size)
0040 {
0041     return Collector::allocate(size);
0042 }
0043 
0044 bool JSCell::getUInt32(uint32_t &) const
0045 {
0046     return false;
0047 }
0048 
0049 bool JSCell::getTruncatedInt32(int32_t &) const
0050 {
0051     return false;
0052 }
0053 
0054 bool JSCell::getTruncatedUInt32(uint32_t &) const
0055 {
0056     return false;
0057 }
0058 
0059 // ECMA 9.4
0060 double JSValue::toInteger(ExecState *exec) const
0061 {
0062     return toInteger(this, exec);
0063 }
0064 
0065 double JSValue::toInteger(const JSValue *value, ExecState *exec)
0066 {
0067     int32_t i;
0068     if (getTruncatedInt32(value, i)) {
0069         return i;
0070     }
0071     double d = toNumber(value, exec);
0072     return isNaN(d) ? 0.0 : trunc(d);
0073 }
0074 
0075 double JSValue::toIntegerPreserveNaN(ExecState *exec) const
0076 {
0077     return toIntegerPreserveNaN(this, exec);
0078 }
0079 
0080 double JSValue::toIntegerPreserveNaN(const JSValue *value, ExecState *exec)
0081 {
0082     int32_t i;
0083     if (getTruncatedInt32(value, i)) {
0084         return i;
0085     }
0086     return trunc(toNumber(value, exec));
0087 }
0088 
0089 int32_t JSValue::toInt32SlowCase(double d, bool &ok)
0090 {
0091     ok = true;
0092 
0093     if (d >= -D32 / 2 && d < D32 / 2) {
0094         return static_cast<int32_t>(d);
0095     }
0096 
0097     if (isNaN(d) || isInf(d)) {
0098         ok = false;
0099         return 0;
0100     }
0101 
0102     double d32 = fmod(trunc(d), D32);
0103     if (d32 >= D32 / 2) {
0104         d32 -= D32;
0105     } else if (d32 < -D32 / 2) {
0106         d32 += D32;
0107     }
0108     return static_cast<int32_t>(d32);
0109 }
0110 
0111 int32_t JSValue::toInt32SlowCase(const JSValue *value, ExecState *exec, bool &ok)
0112 {
0113     return JSValue::toInt32SlowCase(toNumber(value, exec), ok);
0114 }
0115 
0116 uint32_t JSValue::toUInt32SlowCase(double d, bool &ok)
0117 {
0118     ok = true;
0119 
0120     if (d >= 0.0 && d < D32) {
0121         return static_cast<uint32_t>(d);
0122     }
0123 
0124     if (isNaN(d) || isInf(d)) {
0125         ok = false;
0126         return 0;
0127     }
0128 
0129     double d32 = fmod(trunc(d), D32);
0130     if (d32 < 0) {
0131         d32 += D32;
0132     }
0133     return static_cast<uint32_t>(d32);
0134 }
0135 
0136 uint32_t JSValue::toUInt32SlowCase(const JSValue *value, ExecState *exec, bool &ok)
0137 {
0138     return JSValue::toUInt32SlowCase(toNumber(value, exec), ok);
0139 }
0140 
0141 uint16_t JSValue::toUInt16(ExecState *exec) const
0142 {
0143     return toUInt16(this, exec);
0144 }
0145 
0146 uint16_t JSValue::toUInt16(const JSValue *value, ExecState *exec)
0147 {
0148     uint32_t i;
0149     if (getUInt32(value, i)) {
0150         return static_cast<uint16_t>(i);
0151     }
0152 
0153     return KJS::toUInt16(const_cast<JSValue *>(value)->toNumber(value, exec));
0154 }
0155 
0156 float JSValue::toFloat(ExecState *exec) const
0157 {
0158     return toFloat(this, exec);
0159 }
0160 
0161 float JSValue::toFloat(const JSValue *value, ExecState *exec)
0162 {
0163     return static_cast<float>(toNumber(value, exec));
0164 }
0165 
0166 bool JSCell::getNumber(double &numericValue) const
0167 {
0168     if (!isNumber()) {
0169         return false;
0170     }
0171     numericValue = static_cast<const NumberImp *>(this)->value();
0172     return true;
0173 }
0174 
0175 double JSCell::getNumber() const
0176 {
0177     return isNumber() ? static_cast<const NumberImp *>(this)->value() : NaN;
0178 }
0179 
0180 bool JSCell::getString(UString &stringValue) const
0181 {
0182     if (!isString()) {
0183         return false;
0184     }
0185     stringValue = static_cast<const StringImp *>(this)->value();
0186     return true;
0187 }
0188 
0189 UString JSCell::getString() const
0190 {
0191     return isString() ? static_cast<const StringImp *>(this)->value() : UString();
0192 }
0193 
0194 JSObject *JSCell::getObject()
0195 {
0196     return isObject() ? static_cast<JSObject *>(this) : nullptr;
0197 }
0198 
0199 const JSObject *JSCell::getObject() const
0200 {
0201     return isObject() ? static_cast<const JSObject *>(this) : nullptr;
0202 }
0203 
0204 bool JSCell::implementsCall() const
0205 {
0206     return false;
0207 }
0208 
0209 JSCell *jsString()
0210 {
0211     return new StringImp();
0212 }
0213 
0214 JSCell *jsString(const char *s)
0215 {
0216     return new StringImp(s, s ? strlen(s) : 0);
0217 }
0218 
0219 JSCell *jsString(const char *s, int len)
0220 {
0221     return new StringImp(s, len);
0222 }
0223 
0224 JSCell *jsString(const UString &s)
0225 {
0226     return s.isNull() ? new StringImp() : new StringImp(s);
0227 }
0228 
0229 JSCell *jsOwnedString(const UString &s)
0230 {
0231     return s.isNull() ? new StringImp(UString::empty, StringImp::HasOtherOwner) : new StringImp(s, StringImp::HasOtherOwner);
0232 }
0233 
0234 JSCell *jsString(ExecState *exec, const JSValue *value)
0235 {
0236     if (JSValue::isString(value)) {
0237         return jsString(static_cast<const StringImp *>(value)->value());
0238     }
0239     return jsString(JSValue::toString(value, exec));
0240 }
0241 
0242 // This method includes a PIC branch to set up the NumberImp's vtable, so we quarantine
0243 // it in a separate function to keep the normal case speedy.
0244 JSValue *jsNumberCell(double d)
0245 {
0246     return new NumberImp(d);
0247 }
0248 
0249 JSValue *JSValue::getByIndex(ExecState *exec, unsigned propertyName) const
0250 {
0251     return getByIndex(this, exec, propertyName);
0252 }
0253 
0254 JSValue *JSValue::getByIndex(const JSValue *value, ExecState *exec, unsigned propertyName)
0255 {
0256     switch (type(value)) {
0257     case StringType: {
0258         UString s = static_cast<const StringImp *>(value->asCell())->value();
0259         if (propertyName < static_cast<unsigned>(s.size())) {
0260             return jsString(s.substr(propertyName, 1));
0261         }
0262         // fall through
0263     }
0264     default: {
0265         JSObject *obj = toObject(value, exec);
0266         PropertySlot slot;
0267         if (obj->getPropertySlot(exec, propertyName, slot)) {
0268             return slot.getValue(exec, obj, propertyName);
0269         }
0270 
0271         return jsUndefined();
0272     }
0273     }
0274 }
0275 
0276 } // namespace KJS