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 | |
34 | namespace KJS { |
35 | |
36 | static const double D16 = 65536.0; |
37 | static const double D32 = 4294967296.0; |
38 | |
39 | void *JSCell::operator new(size_t size) |
40 | { |
41 | return Collector::allocate(size); |
42 | } |
43 | |
44 | bool JSCell::getUInt32(uint32_t&) const |
45 | { |
46 | return false; |
47 | } |
48 | |
49 | bool JSCell::getTruncatedInt32(int32_t&) const |
50 | { |
51 | return false; |
52 | } |
53 | |
54 | bool JSCell::getTruncatedUInt32(uint32_t&) const |
55 | { |
56 | return false; |
57 | } |
58 | |
59 | // ECMA 9.4 |
60 | double 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 | |
69 | double JSValue::toIntegerPreserveNaN(ExecState *exec) const |
70 | { |
71 | int32_t i; |
72 | if (getTruncatedInt32(i)) |
73 | return i; |
74 | return trunc(toNumber(exec)); |
75 | } |
76 | |
77 | int32_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 | |
97 | int32_t JSValue::toInt32SlowCase(ExecState* exec, bool& ok) const |
98 | { |
99 | return JSValue::toInt32SlowCase(toNumber(exec), ok); |
100 | } |
101 | |
102 | uint32_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 | |
120 | uint32_t JSValue::toUInt32SlowCase(ExecState* exec, bool& ok) const |
121 | { |
122 | return JSValue::toUInt32SlowCase(toNumber(exec), ok); |
123 | } |
124 | |
125 | uint16_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 | |
134 | float JSValue::toFloat(ExecState* exec) const |
135 | { |
136 | return static_cast<float>(toNumber(exec)); |
137 | } |
138 | |
139 | bool 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 | |
147 | double JSCell::getNumber() const |
148 | { |
149 | return isNumber() ? static_cast<const NumberImp *>(this)->value() : NaN; |
150 | } |
151 | |
152 | bool 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 | |
160 | UString JSCell::getString() const |
161 | { |
162 | return isString() ? static_cast<const StringImp *>(this)->value() : UString(); |
163 | } |
164 | |
165 | JSObject *JSCell::getObject() |
166 | { |
167 | return isObject() ? static_cast<JSObject *>(this) : 0; |
168 | } |
169 | |
170 | const JSObject *JSCell::getObject() const |
171 | { |
172 | return isObject() ? static_cast<const JSObject *>(this) : 0; |
173 | } |
174 | |
175 | bool JSCell::implementsCall() const |
176 | { |
177 | return false; |
178 | } |
179 | |
180 | JSCell* jsString() |
181 | { |
182 | return new StringImp(); |
183 | } |
184 | |
185 | JSCell* jsString(const char* s) |
186 | { |
187 | return new StringImp(s, s ? strlen(s) : 0); |
188 | } |
189 | |
190 | JSCell* jsString(const char* s, int len) |
191 | { |
192 | return new StringImp(s, len); |
193 | } |
194 | |
195 | JSCell* jsString(const UString& s) |
196 | { |
197 | return s.isNull() ? new StringImp() : new StringImp(s); |
198 | } |
199 | |
200 | JSCell* jsOwnedString(const UString& s) |
201 | { |
202 | return s.isNull() ? new StringImp(UString::empty, StringImp::HasOtherOwner) : new StringImp(s, StringImp::HasOtherOwner); |
203 | } |
204 | |
205 | JSCell* 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. |
214 | JSValue *jsNumberCell(double d) |
215 | { |
216 | return new NumberImp(d); |
217 | } |
218 | |
219 | JSValue* 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 | |