Skip to content

Commit c17197d

Browse files
committed
Handle Unicode characters in parseFloat()
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
1 parent 7aacb8f commit c17197d

File tree

2 files changed

+194
-93
lines changed

2 files changed

+194
-93
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp

Lines changed: 175 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -424,147 +424,229 @@ ecma_builtin_global_object_parse_float (ecma_value_t this_arg __attr_unused___,
424424
ecma_string_t *number_str_p = ecma_get_string_from_value (string_var);
425425
lit_utf8_size_t str_size = ecma_string_get_size (number_str_p);
426426

427-
MEM_DEFINE_LOCAL_ARRAY (utf8_string_buff, str_size + 1, lit_utf8_byte_t);
428-
429-
ssize_t bytes_copied = ecma_string_to_utf8_string (number_str_p,
430-
utf8_string_buff,
431-
(ssize_t) str_size);
432-
JERRY_ASSERT (bytes_copied >= 0);
433-
utf8_string_buff[str_size] = LIT_BYTE_NULL;
434-
435-
/* 2. Find first non whitespace char. */
436-
lit_utf8_size_t start = 0;
437-
for (lit_utf8_size_t i = 0; i < str_size; i++)
427+
if (str_size > 0)
438428
{
439-
if (!lit_char_is_white_space (utf8_string_buff[i])
440-
&& !lit_char_is_line_terminator (utf8_string_buff[i]))
441-
{
442-
start = i;
443-
break;
444-
}
445-
}
429+
MEM_DEFINE_LOCAL_ARRAY (utf8_string_buff, str_size, lit_utf8_byte_t);
446430

447-
bool sign = false;
431+
ssize_t bytes_copied = ecma_string_to_utf8_string (number_str_p,
432+
utf8_string_buff,
433+
(ssize_t) str_size);
434+
JERRY_ASSERT (bytes_copied >= 0);
435+
lit_utf8_iterator_t iter = lit_utf8_iterator_create (utf8_string_buff, str_size);
448436

449-
/* Check if sign is present. */
450-
if (utf8_string_buff[start] == '-')
451-
{
452-
sign = true;
453-
start++;
454-
}
455-
else if (utf8_string_buff[start] == '+')
456-
{
457-
start++;
458-
}
437+
lit_utf8_iterator_seek_eos (&iter);
438+
439+
lit_utf8_iterator_pos_t start = lit_utf8_iterator_get_pos (&iter);
440+
lit_utf8_iterator_pos_t end = lit_utf8_iterator_get_pos (&iter);
459441

460-
ecma_number_t *ret_num_p = ecma_alloc_number ();
442+
lit_utf8_iterator_seek_bos (&iter);
461443

462-
/* Check if string is equal to "Infinity". */
463-
const lit_utf8_byte_t *infinity_utf8_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
464444

465-
for (lit_utf8_size_t i = 0; infinity_utf8_str_p[i] == utf8_string_buff[start + i]; i++)
466-
{
467-
if (infinity_utf8_str_p[i + 1] == 0)
445+
/* 2. Find first non whitespace char and set starting position. */
446+
while (!lit_utf8_iterator_is_eos (&iter))
468447
{
469-
*ret_num_p = ecma_number_make_infinity (sign);
470-
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
471-
break;
448+
ecma_char_t current_char = lit_utf8_iterator_read_next (&iter);
449+
450+
if (!lit_char_is_white_space (current_char)
451+
&& !lit_char_is_line_terminator (current_char))
452+
{
453+
lit_utf8_iterator_decr (&iter);
454+
start = lit_utf8_iterator_get_pos (&iter);
455+
break;
456+
}
472457
}
473-
}
474458

475-
if (ecma_is_completion_value_empty (ret_value))
476-
{
477-
lit_utf8_size_t current = start;
478-
lit_utf8_size_t end = str_size;
479-
bool has_whole_part = false;
480-
bool has_fraction_part = false;
459+
bool sign = false;
460+
ecma_char_t current;
481461

482-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
462+
if (!lit_utf8_iterator_is_eos (&iter))
483463
{
484-
has_whole_part = true;
464+
/* Check if sign is present. */
465+
current = lit_utf8_iterator_read_next (&iter);
466+
if (current == LIT_CHAR_MINUS)
467+
{
468+
sign = true;
469+
}
485470

486-
/* Check digits of whole part. */
487-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
471+
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
488472
{
489-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
490-
{
491-
break;
492-
}
473+
/* Set starting position to be after the sign character. */
474+
start = lit_utf8_iterator_get_pos (&iter);
475+
}
476+
else
477+
{
478+
lit_utf8_iterator_decr (&iter);
479+
}
480+
}
481+
482+
ecma_number_t *ret_num_p = ecma_alloc_number ();
483+
484+
const lit_utf8_byte_t *infinity_utf8_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
485+
lit_utf8_iterator_t infinity_iter = lit_utf8_iterator_create (infinity_utf8_str_p,
486+
sizeof (*infinity_utf8_str_p));
487+
488+
JERRY_ASSERT (!lit_utf8_iterator_is_eos (&infinity_iter));
489+
490+
/* Check if string is equal to "Infinity". */
491+
while (!lit_utf8_iterator_is_eos (&iter)
492+
&& (lit_utf8_iterator_read_next (&iter) == lit_utf8_iterator_read_next (&infinity_iter)))
493+
{
494+
if (lit_utf8_iterator_is_eos (&infinity_iter))
495+
{
496+
/* String matched Infinity. */
497+
*ret_num_p = ecma_number_make_infinity (sign);
498+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
499+
break;
493500
}
494501
}
495502

496-
end = current;
503+
/* Reset to starting position. */
504+
lit_utf8_iterator_seek (&iter, start);
497505

498-
/* Check decimal point. */
499-
if (utf8_string_buff[current] == '.')
506+
if (ecma_is_completion_value_empty (ret_value) && !lit_utf8_iterator_is_eos (&iter))
500507
{
501-
current++;
508+
current = lit_utf8_iterator_read_next (&iter);
502509

503-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
510+
bool has_whole_part = false;
511+
bool has_fraction_part = false;
512+
513+
/* Check digits of whole part. */
514+
if (lit_char_is_decimal_digit (current))
504515
{
505-
has_fraction_part = true;
516+
has_whole_part = true;
506517

507-
/* Check digits of fractional part. */
508-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
518+
while (!lit_utf8_iterator_is_eos (&iter))
509519
{
510-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
520+
current = lit_utf8_iterator_read_next (&iter);
521+
if (!lit_char_is_decimal_digit (current))
511522
{
523+
lit_utf8_iterator_decr (&iter);
512524
break;
513525
}
514526
}
515-
516-
end = current;
517527
}
518-
}
519-
520-
/* Check exponent. */
521-
if ((utf8_string_buff[current] == 'e' || utf8_string_buff[current] == 'E')
522-
&& (has_whole_part || has_fraction_part))
523-
{
524-
current++;
528+
else
529+
{
530+
lit_utf8_iterator_decr (&iter);
531+
}
525532

526-
/* Check sign of exponent. */
527-
if (utf8_string_buff[current] == '-' || utf8_string_buff[current] == '+')
533+
/* Set end position to the end of whole part. */
534+
end = lit_utf8_iterator_get_pos (&iter);
535+
if (!lit_utf8_iterator_is_eos (&iter))
528536
{
529-
current++;
537+
current = lit_utf8_iterator_read_next (&iter);
530538
}
531539

532-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
540+
/* Check decimal point. */
541+
if (current == LIT_CHAR_DOT && !lit_utf8_iterator_is_eos (&iter))
533542
{
543+
current = lit_utf8_iterator_read_next (&iter);
534544

535-
/* Check digits of exponent part. */
536-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
545+
if (lit_char_is_decimal_digit (current))
537546
{
538-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
547+
has_fraction_part = true;
548+
549+
/* Check digits of fractional part. */
550+
while (!lit_utf8_iterator_is_eos (&iter))
539551
{
540-
break;
552+
current = lit_utf8_iterator_read_next (&iter);
553+
if (!lit_char_is_decimal_digit (current))
554+
{
555+
lit_utf8_iterator_decr (&iter);
556+
break;
557+
}
541558
}
559+
560+
/* Set end position to end of fraction part. */
561+
end = lit_utf8_iterator_get_pos (&iter);
562+
}
563+
else
564+
{
565+
lit_utf8_iterator_decr (&iter);
542566
}
567+
}
568+
else
569+
{
570+
lit_utf8_iterator_decr (&iter);
571+
}
543572

544-
end = current;
573+
if (!lit_utf8_iterator_is_eos (&iter))
574+
{
575+
current = lit_utf8_iterator_read_next (&iter);
545576
}
546-
}
547577

548-
if (start == end)
549-
{
550-
*ret_num_p = ecma_number_make_nan ();
551-
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
552-
}
553-
else
554-
{
555-
/* 5. */
556-
*ret_num_p = ecma_utf8_string_to_number (utf8_string_buff + start, end - start);
578+
/* Check exponent. */
579+
if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E)
580+
&& (has_whole_part || has_fraction_part)
581+
&& !lit_utf8_iterator_is_eos (&iter))
582+
{
583+
current = lit_utf8_iterator_read_next (&iter);
557584

558-
if (sign)
585+
/* Check sign of exponent. */
586+
if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS)
587+
&& !lit_utf8_iterator_is_eos (&iter))
588+
{
589+
current = lit_utf8_iterator_read_next (&iter);
590+
}
591+
592+
if (lit_char_is_decimal_digit (current))
593+
{
594+
/* Check digits of exponent part. */
595+
while (!lit_utf8_iterator_is_eos (&iter))
596+
{
597+
current = lit_utf8_iterator_read_next (&iter);
598+
if (!lit_char_is_decimal_digit (current))
599+
{
600+
lit_utf8_iterator_decr (&iter);
601+
break;
602+
}
603+
}
604+
605+
/* Set end position to end of exponent part. */
606+
end = lit_utf8_iterator_get_pos (&iter);
607+
}
608+
}
609+
else
610+
{
611+
lit_utf8_iterator_decr (&iter);
612+
}
613+
614+
/* String did not contain a valid number. */
615+
if (start.offset == end.offset)
559616
{
560-
*ret_num_p *= -1;
617+
*ret_num_p = ecma_number_make_nan ();
618+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
561619
}
620+
else
621+
{
622+
/* 5. */
623+
*ret_num_p = ecma_utf8_string_to_number (utf8_string_buff + start.offset,
624+
(lit_utf8_size_t) (end.offset - start.offset));
562625

626+
if (sign)
627+
{
628+
*ret_num_p *= -1;
629+
}
630+
631+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
632+
}
633+
}
634+
/* String ended after sign character, or was empty after removing leading whitespace. */
635+
else if (ecma_is_completion_value_empty (ret_value))
636+
{
637+
*ret_num_p = ecma_number_make_nan ();
563638
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
564639
}
640+
MEM_FINALIZE_LOCAL_ARRAY (utf8_string_buff);
641+
}
642+
/* String length is zero. */
643+
else
644+
{
645+
ecma_number_t *ret_num_p = ecma_alloc_number ();
646+
*ret_num_p = ecma_number_make_nan ();
647+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
565648
}
566649

567-
MEM_FINALIZE_LOCAL_ARRAY (utf8_string_buff);
568650
ECMA_FINALIZE (string_var);
569651

570652
return ret_value;

tests/jerry/global-parsefloat.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,31 @@ assert(parseFloat("Infinityfoo") === Infinity);
3838
assert(parseFloat("-Infinityfoo") === -Infinity);
3939
assert(isNaN(parseFloat("")));
4040
assert(isNaN(parseFloat(".")));
41+
assert(isNaN(parseFloat("..")));
42+
assert(isNaN(parseFloat("+")));
43+
assert(isNaN(parseFloat("-")));
44+
assert(isNaN(parseFloat("e")));
45+
assert(isNaN(parseFloat("a")));
46+
assert(isNaN(parseFloat("e+")));
47+
assert(isNaN(parseFloat("+e-")));
48+
assert(isNaN(parseFloat(".e")));
49+
assert(isNaN(parseFloat(".a")));
4150
assert(isNaN(parseFloat("e3")));
4251
assert(isNaN(parseFloat(".e3")));
52+
assert(parseFloat("1..2") === 1);
53+
assert(parseFloat("1.2.3") === 1.2);
54+
assert(parseFloat("1.2ee3") === 1.2);
4355
assert(parseFloat("0") === 0);
4456
assert(parseFloat(".0") === 0);
4557
assert(parseFloat("0.e3") === 0);
4658
assert(parseFloat("0.0e3") === 0);
59+
assert(parseFloat("1.2eA") === 1.2);
60+
assert(parseFloat("1.ae3") === 1);
61+
assert(parseFloat("\u00a0\u00a01.2e3") === 1200);
62+
assert(parseFloat("\u2029\u2029\u00a01.2e\u00D0") === 1.2);
63+
assert(isNaN(parseFloat("\u2029\u2029\u00a0\u00D01.2e3")));
64+
assert(parseFloat("\u2029\u2029\u00a01.\u20292e\u00D0") === 1);
65+
assert(isNaN(parseFloat("\u2029\u2029")));
4766

4867
var obj = new Object();
4968
var arr = [3,4,5];

0 commit comments

Comments
 (0)