1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecma-comparison.h" 17#include "ecma-conversion.h" 18#include "ecma-globals.h" 19#include "ecma-try-catch-macro.h" 20#include "jrt.h" 21 22/** \addtogroup ecma ECMA 23 * @{ 24 * 25 * \addtogroup ecmacomparison ECMA comparison 26 * @{ 27 */ 28 29/** 30 * ECMA abstract equality comparison routine. 31 * 32 * See also: ECMA-262 v5, 11.9.3 33 * 34 * Note: 35 * This function might raise an exception, so the 36 * returned value must be freed with ecma_free_value. 37 * 38 * @return true - if values are equal, 39 * false - otherwise 40 * error - in case of any problems 41 */ 42ecma_value_t 43ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ 44 ecma_value_t y) /**< second operand */ 45{ 46 if (x == y) 47 { 48 return ECMA_VALUE_TRUE; 49 } 50 51 if (ecma_are_values_integer_numbers (x, y)) 52 { 53 /* Note: the (x == y) comparison captures the true case. */ 54 return ECMA_VALUE_FALSE; 55 } 56 57 if (ecma_is_value_number (x)) 58 { 59 if (ecma_is_value_number (y)) 60 { 61 /* 1.c */ 62 ecma_number_t x_num = ecma_get_number_from_value (x); 63 ecma_number_t y_num = ecma_get_number_from_value (y); 64 65 bool is_x_equal_to_y = (x_num == y_num); 66 67#ifndef JERRY_NDEBUG 68 bool is_x_equal_to_y_check; 69 70 if (ecma_number_is_nan (x_num) 71 || ecma_number_is_nan (y_num)) 72 { 73 is_x_equal_to_y_check = false; 74 } 75 else if (x_num == y_num 76 || (ecma_number_is_zero (x_num) 77 && ecma_number_is_zero (y_num))) 78 { 79 is_x_equal_to_y_check = true; 80 } 81 else 82 { 83 is_x_equal_to_y_check = false; 84 } 85 86 JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); 87#endif /* !JERRY_NDEBUG */ 88 89 return ecma_make_boolean_value (is_x_equal_to_y); 90 } 91 92 /* Swap values. */ 93 ecma_value_t tmp = x; 94 x = y; 95 y = tmp; 96 } 97 98 if (ecma_is_value_string (x)) 99 { 100 if (ecma_is_value_string (y)) 101 { 102 /* 1., d. */ 103 ecma_string_t *x_str_p = ecma_get_string_from_value (x); 104 ecma_string_t *y_str_p = ecma_get_string_from_value (y); 105 106 bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); 107 108 return ecma_make_boolean_value (is_equal); 109 } 110 111 if (ecma_is_value_number (y)) 112 { 113 /* 4. */ 114 ecma_value_t x_num_value = ecma_op_to_number (x); 115 116 if (ECMA_IS_VALUE_ERROR (x_num_value)) 117 { 118 return x_num_value; 119 } 120 121 ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); 122 123 ecma_free_value (x_num_value); 124 return compare_result; 125 } 126 127 /* Swap values. */ 128 ecma_value_t tmp = x; 129 x = y; 130 y = tmp; 131 } 132 133#if ENABLED (JERRY_ES2015) 134 if (ecma_is_value_symbol (x)) 135 { 136 return ECMA_VALUE_FALSE; 137 } 138#endif /* ENABLED (JERRY_ES2015) */ 139 140 if (ecma_is_value_boolean (y)) 141 { 142 if (ecma_is_value_boolean (x)) 143 { 144 /* 1., e. */ 145 /* Note: the (x == y) comparison captures the true case. */ 146 return ECMA_VALUE_FALSE; 147 } 148 149 /* 7. */ 150 return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); 151 } 152 153 if (ecma_is_value_object (x)) 154 { 155 if (ecma_is_value_string (y) 156#if ENABLED (JERRY_ES2015) 157 || ecma_is_value_symbol (y) 158#endif /* ENABLED (JERRY_ES2015) */ 159 || ecma_is_value_number (y)) 160 { 161 /* 9. */ 162 ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); 163 164 if (ECMA_IS_VALUE_ERROR (x_prim_value)) 165 { 166 return x_prim_value; 167 } 168 169 ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); 170 171 ecma_free_value (x_prim_value); 172 return compare_result; 173 } 174 175 /* 1., f. */ 176 /* Note: the (x == y) comparison captures the true case. */ 177 return ECMA_VALUE_FALSE; 178 } 179 180 if (ecma_is_value_boolean (x)) 181 { 182 /* 6. */ 183 return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); 184 } 185 186 if (ecma_is_value_undefined (x) 187 || ecma_is_value_null (x)) 188 { 189 /* 1. a., b. */ 190 /* 2., 3. */ 191 bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); 192 193 return ecma_make_boolean_value (is_equal); 194 } 195 196 return ECMA_VALUE_FALSE; 197} /* ecma_op_abstract_equality_compare */ 198 199/** 200 * ECMA strict equality comparison routine. 201 * 202 * See also: ECMA-262 v5, 11.9.6 203 * 204 * @return true - if values are strict equal, 205 * false - otherwise 206 */ 207bool 208ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ 209 ecma_value_t y) /**< second operand */ 210{ 211 if (ecma_is_value_direct (x) 212 || ecma_is_value_direct (y) 213#if ENABLED (JERRY_ES2015) 214 || ecma_is_value_symbol (x) 215 || ecma_is_value_symbol (y) 216#endif /* ENABLED (JERRY_ES2015) */ 217 || ecma_is_value_object (x) 218 || ecma_is_value_object (y)) 219 { 220 JERRY_ASSERT (!ecma_is_value_direct (x) 221 || ecma_is_value_undefined (x) 222 || ecma_is_value_null (x) 223 || ecma_is_value_boolean (x) 224 || ecma_is_value_integer_number (x)); 225 226 JERRY_ASSERT (!ecma_is_value_direct (y) 227 || ecma_is_value_undefined (y) 228 || ecma_is_value_null (y) 229 || ecma_is_value_boolean (y) 230 || ecma_is_value_integer_number (y)); 231 232 if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) 233 && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) 234 { 235 return (x == y); 236 } 237 238 /* The +0 === -0 case handled below. */ 239 } 240 241 JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); 242 JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); 243 244 if (ecma_is_value_string (x)) 245 { 246 if (!ecma_is_value_string (y)) 247 { 248 return false; 249 } 250 251 ecma_string_t *x_str_p = ecma_get_string_from_value (x); 252 ecma_string_t *y_str_p = ecma_get_string_from_value (y); 253 254 return ecma_compare_ecma_strings (x_str_p, y_str_p); 255 } 256 257 if (!ecma_is_value_number (y)) 258 { 259 return false; 260 } 261 262 ecma_number_t x_num = ecma_get_number_from_value (x); 263 ecma_number_t y_num = ecma_get_number_from_value (y); 264 265 bool is_x_equal_to_y = (x_num == y_num); 266 267#ifndef JERRY_NDEBUG 268 bool is_x_equal_to_y_check; 269 270 if (ecma_number_is_nan (x_num) 271 || ecma_number_is_nan (y_num)) 272 { 273 is_x_equal_to_y_check = false; 274 } 275 else if (x_num == y_num 276 || (ecma_number_is_zero (x_num) 277 && ecma_number_is_zero (y_num))) 278 { 279 is_x_equal_to_y_check = true; 280 } 281 else 282 { 283 is_x_equal_to_y_check = false; 284 } 285 286 JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); 287#endif /* !JERRY_NDEBUG */ 288 289 return is_x_equal_to_y; 290} /* ecma_op_strict_equality_compare */ 291 292/** 293 * ECMA abstract relational comparison routine. 294 * 295 * See also: ECMA-262 v5, 11.8.5 296 * 297 * @return ecma value 298 * Returned value must be freed with ecma_free_value 299 */ 300ecma_value_t 301ecma_op_abstract_relational_compare (ecma_value_t x, /**< first operand */ 302 ecma_value_t y, /**< second operand */ 303 bool left_first) /**< 'LeftFirst' flag */ 304{ 305 ecma_value_t ret_value = ECMA_VALUE_EMPTY; 306 307 /* 1., 2. */ 308 ecma_value_t prim_first_converted_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NUMBER); 309 if (ECMA_IS_VALUE_ERROR (prim_first_converted_value)) 310 { 311 return prim_first_converted_value; 312 } 313 314 ecma_value_t prim_second_converted_value = ecma_op_to_primitive (y, ECMA_PREFERRED_TYPE_NUMBER); 315 if (ECMA_IS_VALUE_ERROR (prim_second_converted_value)) 316 { 317 ecma_free_value (prim_first_converted_value); 318 return prim_second_converted_value; 319 } 320 321 const ecma_value_t px = left_first ? prim_first_converted_value : prim_second_converted_value; 322 const ecma_value_t py = left_first ? prim_second_converted_value : prim_first_converted_value; 323 324 const bool is_px_string = ecma_is_value_string (px); 325 const bool is_py_string = ecma_is_value_string (py); 326 327 if (!(is_px_string && is_py_string)) 328 { 329 /* 3. */ 330 331 /* a. */ 332 ECMA_OP_TO_NUMBER_TRY_CATCH (nx, px, ret_value); 333 ECMA_OP_TO_NUMBER_TRY_CATCH (ny, py, ret_value); 334 335 /* b. */ 336 if (ecma_number_is_nan (nx) 337 || ecma_number_is_nan (ny)) 338 { 339 /* c., d. */ 340 ret_value = ECMA_VALUE_UNDEFINED; 341 } 342 else 343 { 344 bool is_x_less_than_y = (nx < ny); 345 346#ifndef JERRY_NDEBUG 347 bool is_x_less_than_y_check; 348 349 if (nx == ny 350 || (ecma_number_is_zero (nx) 351 && ecma_number_is_zero (ny))) 352 { 353 /* e., f., g. */ 354 is_x_less_than_y_check = false; 355 } 356 else if (ecma_number_is_infinity (nx) 357 && !ecma_number_is_negative (nx)) 358 { 359 /* h. */ 360 is_x_less_than_y_check = false; 361 } 362 else if (ecma_number_is_infinity (ny) 363 && !ecma_number_is_negative (ny)) 364 { 365 /* i. */ 366 is_x_less_than_y_check = true; 367 } 368 else if (ecma_number_is_infinity (ny) 369 && ecma_number_is_negative (ny)) 370 { 371 /* j. */ 372 is_x_less_than_y_check = false; 373 } 374 else if (ecma_number_is_infinity (nx) 375 && ecma_number_is_negative (nx)) 376 { 377 /* k. */ 378 is_x_less_than_y_check = true; 379 } 380 else 381 { 382 /* l. */ 383 JERRY_ASSERT (!ecma_number_is_nan (nx) 384 && !ecma_number_is_infinity (nx)); 385 JERRY_ASSERT (!ecma_number_is_nan (ny) 386 && !ecma_number_is_infinity (ny)); 387 JERRY_ASSERT (!(ecma_number_is_zero (nx) 388 && ecma_number_is_zero (ny))); 389 390 if (nx < ny) 391 { 392 is_x_less_than_y_check = true; 393 } 394 else 395 { 396 is_x_less_than_y_check = false; 397 } 398 } 399 400 JERRY_ASSERT (is_x_less_than_y_check == is_x_less_than_y); 401#endif /* !JERRY_NDEBUG */ 402 403 ret_value = ecma_make_boolean_value (is_x_less_than_y); 404 } 405 406 ECMA_OP_TO_NUMBER_FINALIZE (ny); 407 ECMA_OP_TO_NUMBER_FINALIZE (nx); 408 } 409 else 410 { /* 4. */ 411 JERRY_ASSERT (is_px_string && is_py_string); 412 413 ecma_string_t *str_x_p = ecma_get_string_from_value (px); 414 ecma_string_t *str_y_p = ecma_get_string_from_value (py); 415 416 bool is_px_less = ecma_compare_ecma_strings_relational (str_x_p, str_y_p); 417 418 ret_value = ecma_make_boolean_value (is_px_less); 419 } 420 421 ecma_free_value (prim_second_converted_value); 422 ecma_free_value (prim_first_converted_value); 423 424 return ret_value; 425} /* ecma_op_abstract_relational_compare */ 426 427/** 428 * @} 429 * @} 430 */ 431