2006-03-30 Eric Seidel <eseidel@apple.com>
[WebKit-https.git] / JavaScriptCore / kjs / operations.cpp
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
24 #include "JSType.h"
25 #include "config.h"
26 #include "operations.h"
27
28 #include <assert.h>
29 #include <math.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #if HAVE(FUNC_ISINF) && HAVE(IEEEFP_H)
34 #include <ieeefp.h>
35 #endif
36
37 #if HAVE(FLOAT_H)
38 #include <float.h>
39 #endif
40
41 #include "object.h"
42
43 namespace KJS {
44     
45 #if !PLATFORM(DARWIN)
46 // FIXME: should probably be inlined on other platforms too, and controlled exclusively
47 // by HAVE macros
48     
49     
50 bool isNaN(double d)
51 {
52 #if HAVE(FUNC_ISNAN)
53     return isnan(d);
54 #elif HAVE(FLOAT_H)
55     return _isnan(d) != 0;
56 #else
57     return !(d == d);
58 #endif
59 }
60
61 bool isInf(double d)
62 {
63     // FIXME: should be HAVE(_FPCLASS)
64 #if PLATFORM(WIN_OS)
65     int fpClass = _fpclass(d);
66     return _FPCLASS_PINF == fpClass || _FPCLASS_NINF == fpClass;
67 #elif HAVE(FUNC_ISINF)
68     return isinf(d);
69 #elif HAVE(FUNC_FINITE)
70     return finite(d) == 0 && d == d;
71 #elif HAVE(FUNC__FINITE)
72     return _finite(d) == 0 && d == d;
73 #else
74     return false;
75 #endif
76 }
77
78 bool isPosInf(double d)
79 {
80     // FIXME: should be HAVE(_FPCLASS)
81 #if PLATFORM(WIN_OS)
82     return _FPCLASS_PINF == _fpclass(d);
83 #elif HAVE(FUNC_ISINF)
84     return (isinf(d) == 1);
85 #elif HAVE(FUNC_FINITE)
86     return !finite(d) && d == d; // ### can we distinguish between + and - ?
87 #elif HAVE(FUNC__FINITE)
88     return !_finite(d) && d == d; // ###
89 #else
90     return false;
91 #endif
92 }
93
94 bool isNegInf(double d)
95 {
96     // FIXME: should be HAVE(_FPCLASS)
97 #if PLATFORM(WIN_OS)
98     return _FPCLASS_NINF == _fpclass(d);
99 #elif HAVE(FUNC_ISINF)
100     return (isinf(d) == -1);
101 #elif HAVE(FUNC_FINITE)
102     return finite(d) == 0 && d == d; // ###
103 #elif HAVE(FUNC__FINITE)
104     return _finite(d) == 0 && d == d; // ###
105 #else
106     return false;
107 #endif
108 }
109
110 #endif
111
112 // ECMA 11.9.3
113 bool equal(ExecState *exec, JSValue *v1, JSValue *v2)
114 {
115     JSType t1 = v1->type();
116     JSType t2 = v2->type();
117     
118     if (t1 != t2) {
119         if (t1 == UndefinedType)
120             t1 = NullType;
121         if (t2 == UndefinedType)
122             t2 = NullType;
123         
124         if (t1 == BooleanType)
125             t1 = NumberType;
126         if (t2 == BooleanType)
127             t2 = NumberType;
128         
129         if (t1 == NumberType && t2 == StringType) {
130             // use toNumber
131         } else if (t1 == StringType && t2 == NumberType) {
132             t1 = NumberType;
133             // use toNumber
134         } else {
135             if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType)
136                 return equal(exec, v1, v2->toPrimitive(exec));
137             if (t1 == NullType && t2 == ObjectType)
138                 return static_cast<JSObject *>(v2)->masqueradeAsUndefined();
139             if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType))
140                 return equal(exec, v1->toPrimitive(exec), v2);
141             if (t1 == ObjectType && t2 == NullType)
142                 return static_cast<JSObject *>(v1)->masqueradeAsUndefined();
143             if (t1 != t2)
144                 return false;
145         }
146     }
147     
148     if (t1 == UndefinedType || t1 == NullType)
149         return true;
150     
151     if (t1 == NumberType) {
152         double d1 = v1->toNumber(exec);
153         double d2 = v2->toNumber(exec);
154         return d1 == d2;
155     }
156     
157     if (t1 == StringType)
158         return v1->toString(exec) == v2->toString(exec);
159     
160     if (t1 == BooleanType)
161         return v1->toBoolean(exec) == v2->toBoolean(exec);
162     
163     // types are Object
164     return v1 == v2;
165 }
166
167 bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2)
168 {
169     JSType t1 = v1->type();
170     JSType t2 = v2->type();
171     
172     if (t1 != t2)
173         return false;
174     if (t1 == UndefinedType || t1 == NullType)
175         return true;
176     if (t1 == NumberType) {
177         double n1 = v1->toNumber(exec);
178         double n2 = v2->toNumber(exec);
179         if (n1 == n2)
180             return true;
181         return false;
182     } else if (t1 == StringType)
183         return v1->toString(exec) == v2->toString(exec);
184     else if (t2 == BooleanType)
185         return v1->toBoolean(exec) == v2->toBoolean(exec);
186     
187     if (v1 == v2)
188         return true;
189     /* TODO: joined objects */
190     
191     return false;
192 }
193
194 int relation(ExecState *exec, JSValue *v1, JSValue *v2)
195 {
196     JSValue *p1 = v1->toPrimitive(exec,NumberType);
197     JSValue *p2 = v2->toPrimitive(exec,NumberType);
198     
199     if (p1->isString() && p2->isString())
200         return p1->toString(exec) < p2->toString(exec) ? 1 : 0;
201     
202     double n1 = p1->toNumber(exec);
203     double n2 = p2->toNumber(exec);
204     if (n1 < n2)
205         return 1;
206     if (n1 >= n2)
207         return 0;
208     return -1; // must be NaN, so undefined
209 }
210
211 int maxInt(int d1, int d2)
212 {
213     return (d1 > d2) ? d1 : d2;
214 }
215
216 int minInt(int d1, int d2)
217 {
218     return (d1 < d2) ? d1 : d2;
219 }
220
221 // ECMA 11.6
222 JSValue *add(ExecState *exec, JSValue *v1, JSValue *v2, char oper)
223 {
224     // exception for the Date exception in defaultValue()
225     JSType preferred = oper == '+' ? UnspecifiedType : NumberType;
226     JSValue *p1 = v1->toPrimitive(exec, preferred);
227     JSValue *p2 = v2->toPrimitive(exec, preferred);
228     
229     if ((p1->isString() || p2->isString()) && oper == '+')
230         return jsString(p1->toString(exec) + p2->toString(exec));
231     
232     if (oper == '+')
233         return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
234     else
235         return jsNumber(p1->toNumber(exec) - p2->toNumber(exec));
236 }
237
238 // ECMA 11.5
239 JSValue *mult(ExecState *exec, JSValue *v1, JSValue *v2, char oper)
240 {
241     double n1 = v1->toNumber(exec);
242     double n2 = v2->toNumber(exec);
243     
244     double result;
245     
246     if (oper == '*')
247         result = n1 * n2;
248     else if (oper == '/')
249         result = n1 / n2;
250     else
251         result = fmod(n1, n2);
252     
253     return jsNumber(result);
254 }
255
256 }