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