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