File indexing completed on 2024-05-12 15:43:31

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
0004  *
0005  *  This library is free software; you can redistribute it and/or
0006  *  modify it under the terms of the GNU Library General Public
0007  *  License as published by the Free Software Foundation; either
0008  *  version 2 of the License, or (at your option) any later version.
0009  *
0010  *  This library is distributed in the hope that it will be useful,
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  *  Library General Public License for more details.
0014  *
0015  *  You should have received a copy of the GNU Library General Public License
0016  *  along with this library; see the file COPYING.LIB.  If not, write to
0017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  *  Boston, MA 02110-1301, USA.
0019  *
0020  */
0021 
0022 #include "operations.h"
0023 
0024 #include "object.h"
0025 #include "internal.h"
0026 
0027 namespace KJS
0028 {
0029 // ECMA 11.9.3
0030 bool equal(ExecState *exec, JSValue *v1, JSValue *v2)
0031 {
0032     JSType t1 = JSValue::type(v1);
0033     JSType t2 = JSValue::type(v2);
0034 
0035     if (t1 != t2) {
0036         if (t1 == UndefinedType) {
0037             t1 = NullType;
0038         }
0039         if (t2 == UndefinedType) {
0040             t2 = NullType;
0041         }
0042 
0043         if (t1 == BooleanType) {
0044             t1 = NumberType;
0045         }
0046         if (t2 == BooleanType) {
0047             t2 = NumberType;
0048         }
0049 
0050         if (t1 == NumberType && t2 == StringType) {
0051             // use toNumber
0052         } else if (t1 == StringType && t2 == NumberType) {
0053             t1 = NumberType;
0054         }
0055         // use toNumber
0056         else {
0057             if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) {
0058                 return equal(exec, v1, JSValue::toPrimitive(v2, exec));
0059             }
0060             if (t1 == NullType && t2 == ObjectType) {
0061                 return static_cast<JSObject *>(v2)->masqueradeAsUndefined();
0062             }
0063             if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) {
0064                 return equal(exec, JSValue::toPrimitive(v1, exec), v2);
0065             }
0066             if (t1 == ObjectType && t2 == NullType) {
0067                 return static_cast<JSObject *>(v1)->masqueradeAsUndefined();
0068             }
0069             if (t1 != t2) {
0070                 return false;
0071             }
0072         }
0073     }
0074 
0075     if (t1 == UndefinedType || t1 == NullType) {
0076         return true;
0077     }
0078 
0079     if (t1 == NumberType) {
0080         double d1 = JSValue::toNumber(v1, exec);
0081         double d2 = JSValue::toNumber(v2, exec);
0082         return d1 == d2;
0083     }
0084 
0085     if (t1 == StringType) {
0086         return JSValue::toString(v1, exec) == JSValue::toString(v2, exec);
0087     }
0088 
0089     if (t1 == BooleanType) {
0090         return JSValue::toBoolean(v1, exec) == JSValue::toBoolean(v2,  exec);
0091     }
0092 
0093     // types are Object
0094     return v1 == v2;
0095 }
0096 
0097 bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2)
0098 {
0099     JSType t1 = JSValue::type(v1);
0100     JSType t2 = JSValue::type(v2);
0101 
0102     if (t1 != t2) {
0103         return false;
0104     }
0105     if (t1 == UndefinedType || t1 == NullType) {
0106         return true;
0107     }
0108     if (t1 == NumberType) {
0109         double n1 = JSValue::toNumber(v1, exec);
0110         double n2 = JSValue::toNumber(v2, exec);
0111         if (n1 == n2) {
0112             return true;
0113         }
0114         return false;
0115     } else if (t1 == StringType) {
0116         return JSValue::toString(v1, exec) == JSValue::toString(v2, exec);
0117     } else if (t2 == BooleanType) {
0118         return JSValue::toBoolean(v1, exec) == JSValue::toBoolean(v2,  exec);
0119     }
0120 
0121     if (v1 == v2) {
0122         return true;
0123     }
0124     /* TODO: joined objects */
0125 
0126     return false;
0127 }
0128 
0129 int relation(ExecState *exec, JSValue *v1, JSValue *v2, bool leftFirst)
0130 {
0131     double n1;
0132     double n2;
0133     JSValue *p1;
0134     JSValue *p2;
0135 
0136     bool wasNotString1;
0137     bool wasNotString2;
0138 
0139     if (leftFirst) {
0140         wasNotString1 = JSValue::getPrimitiveNumber(v1, exec, n1, p1);
0141         if (exec->hadException()) {
0142             return -1;
0143         }
0144         wasNotString2 = JSValue::getPrimitiveNumber(v2, exec, n2, p2);
0145     } else {
0146         wasNotString1 = JSValue::getPrimitiveNumber(v2, exec, n2, p2);
0147         if (exec->hadException()) {
0148             return -1;
0149         }
0150         wasNotString2 = JSValue::getPrimitiveNumber(v1, exec, n1, p1);
0151     }
0152 
0153     if (wasNotString1 || wasNotString2) {
0154         if (n1 < n2) {
0155             return 1;
0156         }
0157         if (n1 >= n2) {
0158             return 0;
0159         }
0160         return -1; // must be NaN, so undefined
0161     }
0162 
0163     assert(JSValue::isString(p1) && JSValue::isString(p2));
0164     return static_cast<const StringImp *>(p1)->value() < static_cast<const StringImp *>(p2)->value() ? 1 : 0;
0165 }
0166 
0167 //EMCA 9.12
0168 bool sameValue(ExecState *exec, JSValue *v1, JSValue *v2)
0169 {
0170     using namespace std;
0171     JSType t1 = JSValue::type(v1);
0172     JSType t2 = JSValue::type(v2);
0173 
0174     if (t1 != t2) {
0175         return false;
0176     }
0177     if (t1 == UndefinedType || t1 == NullType) {
0178         return true;
0179     }
0180     if (t1 == NumberType) {
0181         double n1 = JSValue::toNumber(v1, exec);
0182         double n2 = JSValue::toNumber(v2, exec);
0183         if (isNaN(n1) && isNaN(n2)) {
0184             return true;
0185         }
0186         if (signbit(n1) != signbit(n2)) {
0187             return false;
0188         }
0189         if (n1 == n2) {
0190             return true;
0191         }
0192         return false;
0193     } else if (t1 == StringType) {
0194         return JSValue::toString(v1, exec) == JSValue::toString(v2, exec);
0195     } else if (t2 == BooleanType) {
0196         return JSValue::toBoolean(v1, exec) == JSValue::toBoolean(v2,  exec);
0197     }
0198 
0199     if (v1 == v2) {
0200         return true;
0201     }
0202     /* TODO: joined objects */
0203 
0204     return false;
0205 }
0206 
0207 int relation(ExecState *exec, JSValue *v1, double n2)
0208 {
0209     double n1;
0210     JSValue *p1;
0211 
0212     JSValue::getPrimitiveNumber(v1, exec, n1, p1);
0213     if (exec->hadException()) {
0214         return -1;
0215     }
0216 
0217     if (n1 < n2) {
0218         return 1;
0219     }
0220     if (n1 >= n2) {
0221         return 0;
0222     }
0223     return -1; // must be NaN, so undefined
0224 }
0225 
0226 int maxInt(int d1, int d2)
0227 {
0228     return (d1 > d2) ? d1 : d2;
0229 }
0230 
0231 int minInt(int d1, int d2)
0232 {
0233     return (d1 < d2) ? d1 : d2;
0234 }
0235 
0236 double exponentiation(double base, double exponent)
0237 {
0238     if (isNaN(exponent))
0239     return NaN;
0240     if (abs(base) == 1 && isInf(exponent))
0241     return NaN;
0242     return pow(base, exponent);
0243 }
0244 
0245 }