1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2003 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "value.h"
25#include <config-kjs.h>
26
27#include "error_object.h"
28#include "nodes.h"
29#include "operations.h"
30#include <stdio.h>
31#include <string.h>
32#include <wtf/MathExtras.h>
33
34namespace KJS {
35
36static const double D16 = 65536.0;
37static const double D32 = 4294967296.0;
38
39void *JSCell::operator new(size_t size)
40{
41 return Collector::allocate(size);
42}
43
44bool JSCell::getUInt32(uint32_t&) const
45{
46 return false;
47}
48
49bool JSCell::getTruncatedInt32(int32_t&) const
50{
51 return false;
52}
53
54bool JSCell::getTruncatedUInt32(uint32_t&) const
55{
56 return false;
57}
58
59// ECMA 9.4
60double JSValue::toInteger(ExecState *exec) const
61{
62 int32_t i;
63 if (getTruncatedInt32(i))
64 return i;
65 double d = toNumber(exec);
66 return isNaN(d) ? 0.0 : trunc(d);
67}
68
69double JSValue::toIntegerPreserveNaN(ExecState *exec) const
70{
71 int32_t i;
72 if (getTruncatedInt32(i))
73 return i;
74 return trunc(toNumber(exec));
75}
76
77int32_t JSValue::toInt32SlowCase(double d, bool& ok)
78{
79 ok = true;
80
81 if (d >= -D32 / 2 && d < D32 / 2)
82 return static_cast<int32_t>(d);
83
84 if (isNaN(d) || isInf(d)) {
85 ok = false;
86 return 0;
87 }
88
89 double d32 = fmod(trunc(d), D32);
90 if (d32 >= D32 / 2)
91 d32 -= D32;
92 else if (d32 < -D32 / 2)
93 d32 += D32;
94 return static_cast<int32_t>(d32);
95}
96
97int32_t JSValue::toInt32SlowCase(ExecState* exec, bool& ok) const
98{
99 return JSValue::toInt32SlowCase(toNumber(exec), ok);
100}
101
102uint32_t JSValue::toUInt32SlowCase(double d, bool& ok)
103{
104 ok = true;
105
106 if (d >= 0.0 && d < D32)
107 return static_cast<uint32_t>(d);
108
109 if (isNaN(d) || isInf(d)) {
110 ok = false;
111 return 0;
112 }
113
114 double d32 = fmod(trunc(d), D32);
115 if (d32 < 0)
116 d32 += D32;
117 return static_cast<uint32_t>(d32);
118}
119
120uint32_t JSValue::toUInt32SlowCase(ExecState* exec, bool& ok) const
121{
122 return JSValue::toUInt32SlowCase(toNumber(exec), ok);
123}
124
125uint16_t JSValue::toUInt16(ExecState *exec) const
126{
127 uint32_t i;
128 if (getUInt32(i))
129 return static_cast<uint16_t>(i);
130
131 return KJS::toUInt16(const_cast<JSValue*>(this)->toNumber(exec));
132}
133
134float JSValue::toFloat(ExecState* exec) const
135{
136 return static_cast<float>(toNumber(exec));
137}
138
139bool JSCell::getNumber(double &numericValue) const
140{
141 if (!isNumber())
142 return false;
143 numericValue = static_cast<const NumberImp *>(this)->value();
144 return true;
145}
146
147double JSCell::getNumber() const
148{
149 return isNumber() ? static_cast<const NumberImp *>(this)->value() : NaN;
150}
151
152bool JSCell::getString(UString &stringValue) const
153{
154 if (!isString())
155 return false;
156 stringValue = static_cast<const StringImp *>(this)->value();
157 return true;
158}
159
160UString JSCell::getString() const
161{
162 return isString() ? static_cast<const StringImp *>(this)->value() : UString();
163}
164
165JSObject *JSCell::getObject()
166{
167 return isObject() ? static_cast<JSObject *>(this) : 0;
168}
169
170const JSObject *JSCell::getObject() const
171{
172 return isObject() ? static_cast<const JSObject *>(this) : 0;
173}
174
175bool JSCell::implementsCall() const
176{
177 return false;
178}
179
180JSCell* jsString()
181{
182 return new StringImp();
183}
184
185JSCell* jsString(const char* s)
186{
187 return new StringImp(s, s ? strlen(s) : 0);
188}
189
190JSCell* jsString(const char* s, int len)
191{
192 return new StringImp(s, len);
193}
194
195JSCell* jsString(const UString& s)
196{
197 return s.isNull() ? new StringImp() : new StringImp(s);
198}
199
200JSCell* jsOwnedString(const UString& s)
201{
202 return s.isNull() ? new StringImp(UString::empty, StringImp::HasOtherOwner) : new StringImp(s, StringImp::HasOtherOwner);
203}
204
205JSCell* jsString(ExecState* exec, const JSValue* value)
206{
207 if (value->isString())
208 return jsString(static_cast<const StringImp*>(value)->value());
209 return jsString(value->toString(exec));
210}
211
212// This method includes a PIC branch to set up the NumberImp's vtable, so we quarantine
213// it in a separate function to keep the normal case speedy.
214JSValue *jsNumberCell(double d)
215{
216 return new NumberImp(d);
217}
218
219JSValue* JSValue::getByIndex(ExecState* exec, unsigned propertyName) const
220{
221 switch (type()) {
222 case StringType: {
223 UString s = static_cast<const StringImp*>(asCell())->value();
224 if (propertyName < static_cast<unsigned>(s.size())) {
225 return jsString(s.substr(propertyName, 1));
226 }
227 // fall through
228 }
229 default: {
230 JSObject* obj = toObject(exec);
231 PropertySlot slot;
232 if (obj->getPropertySlot(exec, propertyName, slot))
233 return slot.getValue(exec, obj, propertyName);
234
235 return jsUndefined();
236 }
237 }
238}
239
240} // namespace KJS
241