1 | // -*- c-basic-offset: 2 -*- |
2 | /* |
3 | * This file is part of the KDE libraries |
4 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | * |
21 | */ |
22 | |
23 | #include "operations.h" |
24 | #include <config-kjs.h> |
25 | |
26 | #include "object.h" |
27 | #include "internal.h" |
28 | #include <math.h> |
29 | #include <stdio.h> |
30 | #include <wtf/MathExtras.h> |
31 | |
32 | #if HAVE(IEEEFP_H) |
33 | #if HAVE(FUNC_ISINF) || HAVE(FUNC_FINITE) |
34 | #include <ieeefp.h> |
35 | #endif |
36 | #endif |
37 | |
38 | #if HAVE(FLOAT_H) |
39 | #include <float.h> |
40 | #endif |
41 | |
42 | namespace KJS { |
43 | |
44 | #if !PLATFORM(DARWIN) |
45 | |
46 | // FIXME: Should probably be inlined on non-Darwin platforms too, and controlled exclusively |
47 | // by HAVE macros rather than PLATFORM. |
48 | |
49 | // FIXME: Merge with isnan in MathExtras.h and remove this one entirely. |
50 | bool isNaN(double d) |
51 | { |
52 | #if HAVE(FUNC_ISNAN) |
53 | return isnan(d) != 0; |
54 | #elif HAVE(FLOAT_H) |
55 | return _isnan(d) != 0; |
56 | #else |
57 | return !(d == d); |
58 | #endif |
59 | } |
60 | |
61 | // FIXME: Merge with isinf in MathExtras.h and remove this one entirely. |
62 | bool isInf(double d) |
63 | { |
64 | // FIXME: should be HAVE(_FPCLASS) |
65 | #if PLATFORM(WIN_OS) |
66 | int fpClass = _fpclass(d); |
67 | return _FPCLASS_PINF == fpClass || _FPCLASS_NINF == fpClass; |
68 | #elif HAVE(FUNC_ISINF) && !PLATFORM(SOLARIS_OS) |
69 | return isinf(d); |
70 | #elif HAVE(FUNC_FINITE) |
71 | return finite(d) == 0 && d == d; |
72 | #elif HAVE(FUNC__FINITE) |
73 | return _finite(d) == 0 && d == d; |
74 | #else |
75 | return false; |
76 | #endif |
77 | } |
78 | |
79 | bool isPosInf(double d) |
80 | { |
81 | // FIXME: should be HAVE(_FPCLASS) |
82 | #if PLATFORM(WIN_OS) |
83 | return _FPCLASS_PINF == _fpclass(d); |
84 | #elif HAVE(FUNC_ISINF) && !PLATFORM(SOLARIS_OS) |
85 | return (isinf(d) == 1); |
86 | #elif HAVE(FUNC_FINITE) |
87 | return !finite(d) && d == d; // ### can we distinguish between + and - ? |
88 | #elif HAVE(FUNC__FINITE) |
89 | return !_finite(d) && d == d; // ### |
90 | #else |
91 | return false; |
92 | #endif |
93 | } |
94 | |
95 | bool isNegInf(double d) |
96 | { |
97 | // FIXME: should be HAVE(_FPCLASS) |
98 | #if PLATFORM(WIN_OS) |
99 | return _FPCLASS_NINF == _fpclass(d); |
100 | #elif HAVE(FUNC_ISINF) && !PLATFORM(SOLARIS_OS) |
101 | return (isinf(d) == -1); |
102 | #elif HAVE(FUNC_FINITE) |
103 | return finite(d) == 0 && d == d; // ### |
104 | #elif HAVE(FUNC__FINITE) |
105 | return _finite(d) == 0 && d == d; // ### |
106 | #else |
107 | return false; |
108 | #endif |
109 | } |
110 | |
111 | #endif |
112 | |
113 | // ECMA 11.9.3 |
114 | bool equal(ExecState *exec, JSValue *v1, JSValue *v2) |
115 | { |
116 | JSType t1 = v1->type(); |
117 | JSType t2 = v2->type(); |
118 | |
119 | if (t1 != t2) { |
120 | if (t1 == UndefinedType) |
121 | t1 = NullType; |
122 | if (t2 == UndefinedType) |
123 | t2 = NullType; |
124 | |
125 | if (t1 == BooleanType) |
126 | t1 = NumberType; |
127 | if (t2 == BooleanType) |
128 | t2 = NumberType; |
129 | |
130 | if (t1 == NumberType && t2 == StringType) { |
131 | // use toNumber |
132 | } else if (t1 == StringType && t2 == NumberType) |
133 | t1 = NumberType; |
134 | // use toNumber |
135 | else { |
136 | if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) |
137 | return equal(exec, v1, v2->toPrimitive(exec)); |
138 | if (t1 == NullType && t2 == ObjectType) |
139 | return static_cast<JSObject *>(v2)->masqueradeAsUndefined(); |
140 | if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) |
141 | return equal(exec, v1->toPrimitive(exec), v2); |
142 | if (t1 == ObjectType && t2 == NullType) |
143 | return static_cast<JSObject *>(v1)->masqueradeAsUndefined(); |
144 | if (t1 != t2) |
145 | return false; |
146 | } |
147 | } |
148 | |
149 | if (t1 == UndefinedType || t1 == NullType) |
150 | return true; |
151 | |
152 | if (t1 == NumberType) { |
153 | double d1 = v1->toNumber(exec); |
154 | double d2 = v2->toNumber(exec); |
155 | return d1 == d2; |
156 | } |
157 | |
158 | if (t1 == StringType) |
159 | return v1->toString(exec) == v2->toString(exec); |
160 | |
161 | if (t1 == BooleanType) |
162 | return v1->toBoolean(exec) == v2->toBoolean(exec); |
163 | |
164 | // types are Object |
165 | return v1 == v2; |
166 | } |
167 | |
168 | bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2) |
169 | { |
170 | JSType t1 = v1->type(); |
171 | JSType t2 = v2->type(); |
172 | |
173 | if (t1 != t2) |
174 | return false; |
175 | if (t1 == UndefinedType || t1 == NullType) |
176 | return true; |
177 | if (t1 == NumberType) { |
178 | double n1 = v1->toNumber(exec); |
179 | double n2 = v2->toNumber(exec); |
180 | if (n1 == n2) |
181 | return true; |
182 | return false; |
183 | } else if (t1 == StringType) |
184 | return v1->toString(exec) == v2->toString(exec); |
185 | else if (t2 == BooleanType) |
186 | return v1->toBoolean(exec) == v2->toBoolean(exec); |
187 | |
188 | if (v1 == v2) |
189 | return true; |
190 | /* TODO: joined objects */ |
191 | |
192 | return false; |
193 | } |
194 | |
195 | int relation(ExecState *exec, JSValue *v1, JSValue *v2, bool leftFirst) |
196 | { |
197 | double n1; |
198 | double n2; |
199 | JSValue* p1; |
200 | JSValue* p2; |
201 | |
202 | bool wasNotString1; |
203 | bool wasNotString2; |
204 | |
205 | if (leftFirst) { |
206 | wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1); |
207 | if (exec->hadException()) |
208 | return -1; |
209 | wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2); |
210 | } else { |
211 | wasNotString1 = v2->getPrimitiveNumber(exec, n2, p2); |
212 | if (exec->hadException()) |
213 | return -1; |
214 | wasNotString2 = v1->getPrimitiveNumber(exec, n1, p1); |
215 | } |
216 | |
217 | if (wasNotString1 || wasNotString2) { |
218 | if (n1 < n2) |
219 | return 1; |
220 | if (n1 >= n2) |
221 | return 0; |
222 | return -1; // must be NaN, so undefined |
223 | } |
224 | |
225 | assert(p1->isString() && p2->isString()); |
226 | return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value() ? 1 : 0; |
227 | } |
228 | |
229 | //EMCA 9.12 |
230 | bool sameValue(ExecState *exec, JSValue *v1, JSValue *v2) |
231 | { |
232 | JSType t1 = v1->type(); |
233 | JSType t2 = v2->type(); |
234 | |
235 | if (t1 != t2) |
236 | return false; |
237 | if (t1 == UndefinedType || t1 == NullType) |
238 | return true; |
239 | if (t1 == NumberType) { |
240 | double n1 = v1->toNumber(exec); |
241 | double n2 = v2->toNumber(exec); |
242 | if (isNaN(n1) && isNaN(n2)) |
243 | return true; |
244 | if (signbit(n1) != signbit(n2)) |
245 | return false; |
246 | if (n1 == n2) |
247 | return true; |
248 | return false; |
249 | } else if (t1 == StringType) |
250 | return v1->toString(exec) == v2->toString(exec); |
251 | else if (t2 == BooleanType) |
252 | return v1->toBoolean(exec) == v2->toBoolean(exec); |
253 | |
254 | if (v1 == v2) |
255 | return true; |
256 | /* TODO: joined objects */ |
257 | |
258 | return false; |
259 | } |
260 | |
261 | int relation(ExecState *exec, JSValue *v1, double n2) |
262 | { |
263 | double n1; |
264 | JSValue* p1; |
265 | |
266 | v1->getPrimitiveNumber(exec, n1, p1); |
267 | if (exec->hadException()) |
268 | return -1; |
269 | |
270 | if (n1 < n2) |
271 | return 1; |
272 | if (n1 >= n2) |
273 | return 0; |
274 | return -1; // must be NaN, so undefined |
275 | } |
276 | |
277 | int maxInt(int d1, int d2) |
278 | { |
279 | return (d1 > d2) ? d1 : d2; |
280 | } |
281 | |
282 | int minInt(int d1, int d2) |
283 | { |
284 | return (d1 < d2) ? d1 : d2; |
285 | } |
286 | |
287 | } |
288 | |