Skip to content

Commit 759ac46

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 2e0334c commit 759ac46

File tree

2 files changed

+189
-93
lines changed

2 files changed

+189
-93
lines changed

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

Lines changed: 171 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -290,147 +290,225 @@ ecma_builtin_global_object_parse_float (ecma_value_t this_arg __attr_unused___,
290290
ecma_string_t *number_str_p = ecma_get_string_from_value (string_var);
291291
lit_utf8_size_t str_size = ecma_string_get_size (number_str_p);
292292

293-
MEM_DEFINE_LOCAL_ARRAY (utf8_string_buff, str_size + 1, lit_utf8_byte_t);
294-
295-
ssize_t bytes_copied = ecma_string_to_utf8_string (number_str_p,
296-
utf8_string_buff,
297-
(ssize_t) str_size);
298-
JERRY_ASSERT (bytes_copied >= 0);
299-
utf8_string_buff[str_size] = LIT_BYTE_NULL;
300-
301-
/* 2. Find first non whitespace char. */
302-
lit_utf8_size_t start = 0;
303-
for (lit_utf8_size_t i = 0; i < str_size; i++)
293+
if (str_size > 0)
304294
{
305-
if (!lit_char_is_white_space (utf8_string_buff[i])
306-
&& !lit_char_is_line_terminator (utf8_string_buff[i]))
307-
{
308-
start = i;
309-
break;
310-
}
311-
}
295+
MEM_DEFINE_LOCAL_ARRAY (utf8_string_buff, str_size, lit_utf8_byte_t);
312296

313-
bool sign = false;
297+
ssize_t bytes_copied = ecma_string_to_utf8_string (number_str_p,
298+
utf8_string_buff,
299+
(ssize_t) str_size);
300+
JERRY_ASSERT (bytes_copied >= 0);
301+
lit_utf8_iterator_t iter = lit_utf8_iterator_create (utf8_string_buff, str_size);
314302

315-
/* Check if sign is present. */
316-
if (utf8_string_buff[start] == '-')
317-
{
318-
sign = true;
319-
start++;
320-
}
321-
else if (utf8_string_buff[start] == '+')
322-
{
323-
start++;
324-
}
303+
lit_utf8_iterator_seek_eos (&iter);
325304

326-
ecma_number_t *ret_num_p = ecma_alloc_number ();
305+
lit_utf8_iterator_pos_t start = lit_utf8_iterator_get_pos (&iter);
306+
lit_utf8_iterator_pos_t end = lit_utf8_iterator_get_pos (&iter);
327307

328-
/* Check if string is equal to "Infinity". */
329-
const lit_utf8_byte_t *infinity_utf8_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
308+
lit_utf8_iterator_seek_bos (&iter);
330309

331-
for (lit_utf8_size_t i = 0; infinity_utf8_str_p[i] == utf8_string_buff[start + i]; i++)
332-
{
333-
if (infinity_utf8_str_p[i + 1] == 0)
310+
311+
/* 2. Find first non whitespace char and set starting position. */
312+
while (!lit_utf8_iterator_is_eos (&iter))
334313
{
335-
*ret_num_p = ecma_number_make_infinity (sign);
336-
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
337-
break;
314+
ecma_char_t current_char = lit_utf8_iterator_read_next (&iter);
315+
316+
if (!lit_char_is_white_space (current_char)
317+
&& !lit_char_is_line_terminator (current_char))
318+
{
319+
lit_utf8_iterator_read_prev (&iter);
320+
start = lit_utf8_iterator_get_pos (&iter);
321+
break;
322+
}
338323
}
339-
}
340324

341-
if (ecma_is_completion_value_empty (ret_value))
342-
{
343-
lit_utf8_size_t current = start;
344-
lit_utf8_size_t end = str_size;
345-
bool has_whole_part = false;
346-
bool has_fraction_part = false;
325+
bool sign = false;
347326

348-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
327+
/* Check if sign is present. */
328+
ecma_char_t current = lit_utf8_iterator_read_next (&iter);
329+
if (current == LIT_CHAR_MINUS)
349330
{
350-
has_whole_part = true;
331+
sign = true;
332+
}
351333

352-
/* Check digits of whole part. */
353-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
334+
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
335+
{
336+
/* Set starting position to be after the sign character. */
337+
start = lit_utf8_iterator_get_pos (&iter);
338+
}
339+
else
340+
{
341+
lit_utf8_iterator_read_prev (&iter);
342+
}
343+
344+
ecma_number_t *ret_num_p = ecma_alloc_number ();
345+
346+
const lit_utf8_byte_t *infinity_utf8_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
347+
lit_utf8_iterator_t infinity_iter = lit_utf8_iterator_create (infinity_utf8_str_p,
348+
sizeof (*infinity_utf8_str_p));
349+
350+
JERRY_ASSERT (!lit_utf8_iterator_is_eos (&infinity_iter));
351+
352+
/* Check if string is equal to "Infinity". */
353+
while (!lit_utf8_iterator_is_eos (&iter)
354+
&& (lit_utf8_iterator_read_next (&iter) == lit_utf8_iterator_read_next (&infinity_iter)))
355+
{
356+
if (lit_utf8_iterator_is_eos (&infinity_iter))
354357
{
355-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
356-
{
357-
break;
358-
}
358+
/* String matched Infinity. */
359+
*ret_num_p = ecma_number_make_infinity (sign);
360+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
361+
break;
359362
}
360363
}
361364

362-
end = current;
365+
/* Reset to starting position. */
366+
lit_utf8_iterator_seek (&iter, start);
363367

364-
/* Check decimal point. */
365-
if (utf8_string_buff[current] == '.')
368+
if (ecma_is_completion_value_empty (ret_value) && !lit_utf8_iterator_is_eos (&iter))
366369
{
367-
current++;
370+
current = lit_utf8_iterator_read_next (&iter);
371+
372+
bool has_whole_part = false;
373+
bool has_fraction_part = false;
368374

369-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
375+
/* Check digits of whole part. */
376+
if (lit_char_is_decimal_digit (current))
370377
{
371-
has_fraction_part = true;
378+
has_whole_part = true;
372379

373-
/* Check digits of fractional part. */
374-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
380+
while (!lit_utf8_iterator_is_eos (&iter))
375381
{
376-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
382+
current = lit_utf8_iterator_read_next (&iter);
383+
if (!lit_char_is_decimal_digit (current))
377384
{
385+
lit_utf8_iterator_read_prev (&iter);
378386
break;
379387
}
380388
}
381-
382-
end = current;
383389
}
384-
}
385-
386-
/* Check exponent. */
387-
if ((utf8_string_buff[current] == 'e' || utf8_string_buff[current] == 'E')
388-
&& (has_whole_part || has_fraction_part))
389-
{
390-
current++;
390+
else
391+
{
392+
lit_utf8_iterator_read_prev (&iter);
393+
}
391394

392-
/* Check sign of exponent. */
393-
if (utf8_string_buff[current] == '-' || utf8_string_buff[current] == '+')
395+
/* Set end position to the end of whole part. */
396+
end = lit_utf8_iterator_get_pos (&iter);
397+
if (!lit_utf8_iterator_is_eos (&iter))
394398
{
395-
current++;
399+
current = lit_utf8_iterator_read_next (&iter);
396400
}
397401

398-
if (lit_char_is_decimal_digit (utf8_string_buff[current]))
402+
/* Check decimal point. */
403+
if (current == LIT_CHAR_DOT && !lit_utf8_iterator_is_eos (&iter))
399404
{
405+
current = lit_utf8_iterator_read_next (&iter);
400406

401-
/* Check digits of exponent part. */
402-
for (lit_utf8_size_t i = current; i < str_size; i++, current++)
407+
if (lit_char_is_decimal_digit (current))
403408
{
404-
if (!lit_char_is_decimal_digit (utf8_string_buff[current]))
409+
has_fraction_part = true;
410+
411+
/* Check digits of fractional part. */
412+
while (!lit_utf8_iterator_is_eos (&iter))
405413
{
406-
break;
414+
current = lit_utf8_iterator_read_next (&iter);
415+
if (!lit_char_is_decimal_digit (current))
416+
{
417+
lit_utf8_iterator_read_prev (&iter);
418+
break;
419+
}
407420
}
421+
422+
/* Set end position to end of fraction part. */
423+
end = lit_utf8_iterator_get_pos (&iter);
424+
}
425+
else
426+
{
427+
lit_utf8_iterator_read_prev (&iter);
408428
}
429+
}
430+
else
431+
{
432+
lit_utf8_iterator_read_prev (&iter);
433+
}
409434

410-
end = current;
435+
if (!lit_utf8_iterator_is_eos (&iter))
436+
{
437+
current = lit_utf8_iterator_read_next (&iter);
411438
}
412-
}
413439

414-
if (start == end)
415-
{
416-
*ret_num_p = ecma_number_make_nan ();
417-
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
418-
}
419-
else
420-
{
421-
/* 5. */
422-
*ret_num_p = ecma_utf8_string_to_number (utf8_string_buff + start, end - start);
440+
/* Check exponent. */
441+
if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E)
442+
&& (has_whole_part || has_fraction_part)
443+
&& !lit_utf8_iterator_is_eos (&iter))
444+
{
445+
current = lit_utf8_iterator_read_next (&iter);
446+
447+
/* Check sign of exponent. */
448+
if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS)
449+
&& !lit_utf8_iterator_is_eos (&iter))
450+
{
451+
current = lit_utf8_iterator_read_next (&iter);
452+
}
453+
454+
if (lit_char_is_decimal_digit (current))
455+
{
456+
/* Check digits of exponent part. */
457+
while (!lit_utf8_iterator_is_eos (&iter))
458+
{
459+
current = lit_utf8_iterator_read_next (&iter);
460+
if (!lit_char_is_decimal_digit (current))
461+
{
462+
lit_utf8_iterator_read_prev (&iter);
463+
break;
464+
}
465+
}
423466

424-
if (sign)
467+
/* Set end position to end of exponent part. */
468+
end = lit_utf8_iterator_get_pos (&iter);
469+
}
470+
}
471+
else
425472
{
426-
*ret_num_p *= -1;
473+
lit_utf8_iterator_read_prev (&iter);
427474
}
428475

476+
/* String did not contain a valid number. */
477+
if (start.offset == end.offset)
478+
{
479+
*ret_num_p = ecma_number_make_nan ();
480+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
481+
}
482+
else
483+
{
484+
/* 5. */
485+
*ret_num_p = ecma_utf8_string_to_number (utf8_string_buff + start.offset,
486+
(lit_utf8_size_t) (end.offset - start.offset));
487+
488+
if (sign)
489+
{
490+
*ret_num_p *= -1;
491+
}
492+
493+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
494+
}
495+
}
496+
/* String ended after sign character, or was empty after removing leading whitespace. */
497+
else if (ecma_is_completion_value_empty (ret_value))
498+
{
499+
*ret_num_p = ecma_number_make_nan ();
429500
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
430501
}
502+
MEM_FINALIZE_LOCAL_ARRAY (utf8_string_buff);
503+
}
504+
/* String length is zero. */
505+
else
506+
{
507+
ecma_number_t *ret_num_p = ecma_alloc_number ();
508+
*ret_num_p = ecma_number_make_nan ();
509+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p));
431510
}
432511

433-
MEM_FINALIZE_LOCAL_ARRAY (utf8_string_buff);
434512
ECMA_FINALIZE (string_var);
435513

436514
return ret_value;

tests/jerry/global-parsefloat.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,30 @@ 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);
4765

4866
var obj = new Object();
4967
var arr = [3,4,5];

0 commit comments

Comments
 (0)