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 #endif 00029 00030 #include <stdio.h> 00031 #include <assert.h> 00032 #include <math.h> 00033 #include <stdlib.h> 00034 00035 // For declaration of isinf on Sun C++ 00036 #ifdef __SUNPRO_CC 00037 #include <sunmath.h> 00038 #endif 00039 00040 #ifdef HAVE_IEEEFP_H 00041 #include <ieeefp.h> 00042 #endif 00043 00044 #if HAVE_FLOAT_H 00045 #include <float.h> 00046 #endif 00047 00048 #include "operations.h" 00049 #include "object.h" 00050 00051 using namespace KJS; 00052 00053 bool KJS::isNaN(double d) 00054 { 00055 return isnan(d); 00056 } 00057 00058 bool KJS::isInf(double d) 00059 { 00060 return isinf(d); 00061 } 00062 00063 bool KJS::isPosInf(double d) 00064 { 00065 return ( isinf(d) && d > 0 ); 00066 } 00067 00068 bool KJS::isNegInf(double d) 00069 { 00070 return ( isinf(d) && d < 0 ); 00071 } 00072 00073 // ECMA 11.9.3 00074 bool KJS::equal(ExecState *exec, const Value& v1, const Value& v2) 00075 { 00076 Type t1 = v1.type(); 00077 Type t2 = v2.type(); 00078 00079 if (t1 == t2) { 00080 if (t1 == UndefinedType || t1 == NullType) 00081 return true; 00082 if (t1 == NumberType) 00083 { 00084 double d1 = v1.toNumber(exec); 00085 double d2 = v2.toNumber(exec); 00086 if ( isNaN( d1 ) || isNaN( d2 ) ) 00087 return false; 00088 return ( d1 == d2 ); /* TODO: +0, -0 ? */ 00089 } 00090 if (t1 == StringType) 00091 return (v1.toString(exec) == v2.toString(exec)); 00092 if (t1 == BooleanType) 00093 return (v1.toBoolean(exec) == v2.toBoolean(exec)); 00094 00095 // types are Object 00096 return (v1.imp() == v2.imp()); 00097 } 00098 00099 // different types 00100 if ((t1 == NullType && t2 == UndefinedType) || (t1 == UndefinedType && t2 == NullType)) 00101 return true; 00102 if (t1 == NumberType && t2 == StringType) { 00103 Number n2 = v2.toNumber(exec); 00104 return equal(exec,v1, n2); 00105 } 00106 if ((t1 == StringType && t2 == NumberType) || t1 == BooleanType) { 00107 Number n1 = v1.toNumber(exec); 00108 return equal(exec,n1, v2); 00109 } 00110 if (t2 == BooleanType) { 00111 Number n2 = v2.toNumber(exec); 00112 return equal(exec,v1, n2); 00113 } 00114 if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) { 00115 Value p2 = v2.toPrimitive(exec); 00116 return equal(exec,v1, p2); 00117 } 00118 if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) { 00119 Value p1 = v1.toPrimitive(exec); 00120 return equal(exec,p1, v2); 00121 } 00122 00123 return false; 00124 } 00125 00126 bool KJS::strictEqual(ExecState *exec, const Value &v1, const Value &v2) 00127 { 00128 Type t1 = v1.type(); 00129 Type t2 = v2.type(); 00130 00131 if (t1 != t2) 00132 return false; 00133 if (t1 == UndefinedType || t1 == NullType) 00134 return true; 00135 if (t1 == NumberType) { 00136 double n1 = v1.toNumber(exec); 00137 double n2 = v2.toNumber(exec); 00138 if (isNaN(n1) || isNaN(n2)) 00139 return false; 00140 if (n1 == n2) 00141 return true; 00142 /* TODO: +0 and -0 */ 00143 return false; 00144 } else if (t1 == StringType) { 00145 return v1.toString(exec) == v2.toString(exec); 00146 } else if (t2 == BooleanType) { 00147 return v1.toBoolean(exec) == v2.toBoolean(exec); 00148 } 00149 if (v1.imp() == v2.imp()) 00150 return true; 00151 /* TODO: joined objects */ 00152 00153 return false; 00154 } 00155 00156 int KJS::relation(ExecState *exec, const Value& v1, const Value& v2) 00157 { 00158 Value p1 = v1.toPrimitive(exec,NumberType); 00159 Value p2 = v2.toPrimitive(exec,NumberType); 00160 00161 if (p1.type() == StringType && p2.type() == StringType) 00162 return p1.toString(exec) < p2.toString(exec) ? 1 : 0; 00163 00164 double n1 = p1.toNumber(exec); 00165 double n2 = p2.toNumber(exec); 00166 if ( isNaN( n1 ) || isNaN( n2 ) ) 00167 return -1; // means undefined 00168 if (n1 == n2) 00169 return 0; 00170 /* TODO: +0, -0 */ 00171 if ( isPosInf( n1 ) ) 00172 return 0; 00173 if ( isPosInf( n2 ) ) 00174 return 1; 00175 if ( isNegInf( n2 ) ) 00176 return 0; 00177 if ( isNegInf( n1 ) ) 00178 return 1; 00179 return (n1 < n2) ? 1 : 0; 00180 } 00181 00182 int KJS::maxInt(int d1, int d2) 00183 { 00184 return (d1 > d2) ? d1 : d2; 00185 } 00186 00187 int KJS::minInt(int d1, int d2) 00188 { 00189 return (d1 < d2) ? d1 : d2; 00190 } 00191 00192 // ECMA 11.6 00193 Value KJS::add(ExecState *exec, const Value &v1, const Value &v2, char oper) 00194 { 00195 // exception for the Date exception in defaultValue() 00196 Type preferred = oper == '+' ? UnspecifiedType : NumberType; 00197 Value p1 = v1.toPrimitive(exec, preferred); 00198 Value p2 = v2.toPrimitive(exec, preferred); 00199 00200 if ((p1.type() == StringType || p2.type() == StringType) && oper == '+') { 00201 UString s1 = p1.toString(exec); 00202 UString s2 = p2.toString(exec); 00203 00204 return String(s1 + s2); 00205 } 00206 00207 double n1 = p1.toNumber(exec); 00208 double n2 = p2.toNumber(exec); 00209 00210 if (oper == '+') 00211 return Number(n1 + n2); 00212 else 00213 return Number(n1 - n2); 00214 } 00215 00216 // ECMA 11.5 00217 Value KJS::mult(ExecState *exec, const Value &v1, const Value &v2, char oper) 00218 { 00219 double n1 = v1.toNumber(exec); 00220 double n2 = v2.toNumber(exec); 00221 00222 double result; 00223 00224 if (oper == '*') 00225 result = n1 * n2; 00226 else if (oper == '/') 00227 result = n1 / n2; 00228 else 00229 result = fmod(n1, n2); 00230 00231 return Number(result); 00232 }