operations.cpp
00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 */ 00022 00023 #ifdef HAVE_CONFIG_H 00024 #include "config.h" 00025 #endif 00026 #ifndef HAVE_FLOAT_H /* just for !Windows */ 00027 #define HAVE_FLOAT_H 0 00028 #define HAVE_FUNC__FINITE 0 00029 #endif 00030 00031 #include <stdio.h> 00032 #include <assert.h> 00033 #include <math.h> 00034 #include <stdlib.h> 00035 00036 // For declaration of isinf on Sun C++ 00037 #ifdef __SUNPRO_CC 00038 #include <sunmath.h> 00039 #endif 00040 00041 #ifndef HAVE_FUNC_ISINF 00042 #ifdef HAVE_IEEEFP_H 00043 #include <ieeefp.h> 00044 #endif 00045 #endif /* HAVE_FUNC_ISINF */ 00046 00047 #if HAVE_FLOAT_H 00048 #include <float.h> 00049 #endif 00050 00051 #include "operations.h" 00052 #include "object.h" 00053 00054 using namespace KJS; 00055 00056 bool KJS::isNaN(double d) 00057 { 00058 #ifdef HAVE_FUNC_ISNAN 00059 return isnan(d); 00060 #elif defined HAVE_FLOAT_H 00061 return _isnan(d) != 0; 00062 #else 00063 return !(d == d); 00064 #endif 00065 } 00066 00067 bool KJS::isInf(double d) 00068 { 00069 #if defined(HAVE_FUNC_ISINF) 00070 return isinf(d); 00071 #elif HAVE_FUNC_FINITE 00072 return finite(d) == 0 && d == d; 00073 #elif HAVE_FUNC__FINITE 00074 return _finite(d) == 0 && d == d; 00075 #else 00076 return false; 00077 #endif 00078 } 00079 00080 bool KJS::isPosInf(double d) 00081 { 00082 #if defined(HAVE_FUNC_ISINF) 00083 return (isinf(d) == 1); 00084 #elif HAVE_FUNC_FINITE 00085 return finite(d) == 0 && d == d; // ### can we distinguish between + and - ? 00086 #elif HAVE_FUNC__FINITE 00087 return _finite(d) == 0 && d == d; // ### 00088 #else 00089 return false; 00090 #endif 00091 } 00092 00093 bool KJS::isNegInf(double d) 00094 { 00095 #if defined(HAVE_FUNC_ISINF) 00096 return (isinf(d) == -1); 00097 #elif HAVE_FUNC_FINITE 00098 return finite(d) == 0 && d == d; // ### 00099 #elif HAVE_FUNC__FINITE 00100 return _finite(d) == 0 && d == d; // ### 00101 #else 00102 return false; 00103 #endif 00104 } 00105 00106 // ECMA 11.9.3 00107 bool KJS::equal(ExecState *exec, const Value& v1, const Value& v2) 00108 { 00109 Type t1 = v1.type(); 00110 Type t2 = v2.type(); 00111 00112 if (t1 == t2) { 00113 if (t1 == UndefinedType || t1 == NullType) 00114 return true; 00115 if (t1 == NumberType) 00116 { 00117 double d1 = v1.toNumber(exec); 00118 double d2 = v2.toNumber(exec); 00119 if ( isNaN( d1 ) || isNaN( d2 ) ) 00120 return false; 00121 return ( d1 == d2 ); /* TODO: +0, -0 ? */ 00122 } 00123 if (t1 == StringType) 00124 return (v1.toString(exec) == v2.toString(exec)); 00125 if (t1 == BooleanType) 00126 return (v1.toBoolean(exec) == v2.toBoolean(exec)); 00127 00128 // types are Object 00129 return (v1.imp() == v2.imp()); 00130 } 00131 00132 // different types 00133 if ((t1 == NullType && t2 == UndefinedType) || (t1 == UndefinedType && t2 == NullType)) 00134 return true; 00135 if (t1 == NumberType && t2 == StringType) { 00136 Number n2 = v2.toNumber(exec); 00137 return equal(exec,v1, n2); 00138 } 00139 if ((t1 == StringType && t2 == NumberType) || t1 == BooleanType) { 00140 Number n1 = v1.toNumber(exec); 00141 return equal(exec,n1, v2); 00142 } 00143 if (t2 == BooleanType) { 00144 Number n2 = v2.toNumber(exec); 00145 return equal(exec,v1, n2); 00146 } 00147 if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) { 00148 Value p2 = v2.toPrimitive(exec); 00149 return equal(exec,v1, p2); 00150 } 00151 if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) { 00152 Value p1 = v1.toPrimitive(exec); 00153 return equal(exec,p1, v2); 00154 } 00155 00156 return false; 00157 } 00158 00159 bool KJS::strictEqual(ExecState *exec, const Value &v1, const Value &v2) 00160 { 00161 Type t1 = v1.type(); 00162 Type t2 = v2.type(); 00163 00164 if (t1 != t2) 00165 return false; 00166 if (t1 == UndefinedType || t1 == NullType) 00167 return true; 00168 if (t1 == NumberType) { 00169 double n1 = v1.toNumber(exec); 00170 double n2 = v2.toNumber(exec); 00171 if (isNaN(n1) || isNaN(n2)) 00172 return false; 00173 if (n1 == n2) 00174 return true; 00175 /* TODO: +0 and -0 */ 00176 return false; 00177 } else if (t1 == StringType) { 00178 return v1.toString(exec) == v2.toString(exec); 00179 } else if (t2 == BooleanType) { 00180 return v1.toBoolean(exec) == v2.toBoolean(exec); 00181 } 00182 if (v1.imp() == v2.imp()) 00183 return true; 00184 /* TODO: joined objects */ 00185 00186 return false; 00187 } 00188 00189 int KJS::relation(ExecState *exec, const Value& v1, const Value& v2) 00190 { 00191 Value p1 = v1.toPrimitive(exec,NumberType); 00192 Value p2 = v2.toPrimitive(exec,NumberType); 00193 00194 if (p1.type() == StringType && p2.type() == StringType) 00195 return p1.toString(exec) < p2.toString(exec) ? 1 : 0; 00196 00197 double n1 = p1.toNumber(exec); 00198 double n2 = p2.toNumber(exec); 00199 if ( isNaN( n1 ) || isNaN( n2 ) ) 00200 return -1; // means undefined 00201 if (n1 == n2) 00202 return 0; 00203 /* TODO: +0, -0 */ 00204 if ( isPosInf( n1 ) ) 00205 return 0; 00206 if ( isPosInf( n2 ) ) 00207 return 1; 00208 if ( isNegInf( n2 ) ) 00209 return 0; 00210 if ( isNegInf( n1 ) ) 00211 return 1; 00212 return (n1 < n2) ? 1 : 0; 00213 } 00214 00215 int KJS::maxInt(int d1, int d2) 00216 { 00217 return (d1 > d2) ? d1 : d2; 00218 } 00219 00220 int KJS::minInt(int d1, int d2) 00221 { 00222 return (d1 < d2) ? d1 : d2; 00223 } 00224 00225 // ECMA 11.6 00226 Value KJS::add(ExecState *exec, const Value &v1, const Value &v2, char oper) 00227 { 00228 // exception for the Date exception in defaultValue() 00229 Type preferred = oper == '+' ? UnspecifiedType : NumberType; 00230 Value p1 = v1.toPrimitive(exec, preferred); 00231 Value p2 = v2.toPrimitive(exec, preferred); 00232 00233 if ((p1.type() == StringType || p2.type() == StringType) && oper == '+') { 00234 UString s1 = p1.toString(exec); 00235 UString s2 = p2.toString(exec); 00236 00237 return String(s1 + s2); 00238 } 00239 00240 double n1 = p1.toNumber(exec); 00241 double n2 = p2.toNumber(exec); 00242 00243 if (oper == '+') 00244 return Number(n1 + n2); 00245 else 00246 return Number(n1 - n2); 00247 } 00248 00249 // ECMA 11.5 00250 Value KJS::mult(ExecState *exec, const Value &v1, const Value &v2, char oper) 00251 { 00252 double n1 = v1.toNumber(exec); 00253 double n2 = v2.toNumber(exec); 00254 00255 double result; 00256 00257 if (oper == '*') 00258 result = n1 * n2; 00259 else if (oper == '/') 00260 result = n1 / n2; 00261 else 00262 result = fmod(n1, n2); 00263 00264 return Number(result); 00265 }