• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
42 ecma_value_t
ecma_op_abstract_equality_compare(ecma_value_t x,ecma_value_t y)43 ecma_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  */
207 bool
ecma_op_strict_equality_compare(ecma_value_t x,ecma_value_t y)208 ecma_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  */
300 ecma_value_t
ecma_op_abstract_relational_compare(ecma_value_t x,ecma_value_t y,bool left_first)301 ecma_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