Skip to content

Commit 6712f54

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 55ffb0c commit 6712f54

File tree

2 files changed

+193
-93
lines changed

2 files changed

+193
-93
lines changed

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

Lines changed: 174 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -424,147 +424,228 @@ 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;
481460

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

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

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

498-
/* Check decimal point. */
499-
if (utf8_string_buff[current] == '.')
505+
if (ecma_is_completion_value_empty (ret_value) && !lit_utf8_iterator_is_eos (&iter))
500506
{
501-
current++;
507+
current = lit_utf8_iterator_read_next (&iter);
502508

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

507-
/* Check digits of fractional part. */
508-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
517+
while (!lit_utf8_iterator_is_eos (&iter))
509518
{
510-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
519+
current = lit_utf8_iterator_read_next (&iter);
520+
if (!lit_char_is_decimal_digit (current))
511521
{
522+
lit_utf8_iterator_decr (&iter);
512523
break;
513524
}
514525
}
515-
516-
end = current;
517526
}
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++;
527+
else
528+
{
529+
lit_utf8_iterator_decr (&iter);
530+
}
525531

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

532-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
539+
/* Check decimal point. */
540+
if (current == LIT_CHAR_DOT && !lit_utf8_iterator_is_eos (&iter))
533541
{
542+
current = lit_utf8_iterator_read_next (&iter);
534543

535-
/* Check digits of exponent part. */
536-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
544+
if (lit_char_is_decimal_digit (current))
537545
{
538-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
546+
has_fraction_part = true;
547+
548+
/* Check digits of fractional part. */
549+
while (!lit_utf8_iterator_is_eos (&iter))
539550
{
540-
break;
551+
current = lit_utf8_iterator_read_next (&iter);
552+
if (!lit_char_is_decimal_digit (current))
553+
{
554+
lit_utf8_iterator_decr (&iter);
555+
break;
556+
}
541557
}
558+
559+
/* Set end position to end of fraction part. */
560+
end = lit_utf8_iterator_get_pos (&iter);
561+
}
562+
else
563+
{
564+
lit_utf8_iterator_decr (&iter);
542565
}
566+
}
567+
else
568+
{
569+
lit_utf8_iterator_decr (&iter);
570+
}
543571

544-
end = current;
572+
if (!lit_utf8_iterator_is_eos (&iter))
573+
{
574+
current = lit_utf8_iterator_read_next (&iter);
545575
}
546-
}
547576

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);
577+
/* Check exponent. */
578+
if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E)
579+
&& (has_whole_part || has_fraction_part)
580+
&& !lit_utf8_iterator_is_eos (&iter))
581+
{
582+
current = lit_utf8_iterator_read_next (&iter);
557583

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

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

567-
MEM_FINALIZE_LOCAL_ARRAY (utf8_string_buff);
568649
ECMA_FINALIZE (string_var);
569650

570651
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)