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
42namespace 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.
50bool 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.
62bool 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
79bool 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
95bool 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
114bool 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
168bool 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
195int 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
230bool 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
261int 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
277int maxInt(int d1, int d2)
278{
279 return (d1 > d2) ? d1 : d2;
280}
281
282int minInt(int d1, int d2)
283{
284 return (d1 < d2) ? d1 : d2;
285}
286
287}
288