Implement Number.parseFloat and Number.parseInt (#3576)
The Global object parseFloat and parseInt fuctions have been moved to the number helpers and intrinsic properties have been created the are used for both the Number and Global methods. JerryScript-DCO-1.0-Signed-off-by: Virag Orkenyi orkvi@inf.u-szeged.hu
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "lit-char-helpers.h"
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
* @{
|
||||
@@ -681,6 +681,372 @@ ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */
|
||||
return ecma_make_integer_value (left_integer * right_integer);
|
||||
} /* ecma_integer_multiply */
|
||||
|
||||
/**
|
||||
* The Number object's 'parseInt' routine
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 15.1.2.2
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first argument's
|
||||
* string buffer */
|
||||
lit_utf8_size_t string_buff_size, /**< routine's first argument's
|
||||
* string buffer's size */
|
||||
ecma_value_t radix) /**< routine's second argument */
|
||||
{
|
||||
if (string_buff_size <= 0)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
const lit_utf8_byte_t *string_curr_p = string_buff;
|
||||
|
||||
/* 2. Remove leading whitespace. */
|
||||
ecma_string_trim_helper (&string_curr_p, &string_buff_size);
|
||||
|
||||
const lit_utf8_byte_t *string_end_p = string_curr_p + string_buff_size;
|
||||
const lit_utf8_byte_t *start_p = string_curr_p;
|
||||
const lit_utf8_byte_t *end_p = string_end_p;
|
||||
|
||||
if (string_curr_p >= string_end_p)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
/* 3. */
|
||||
int sign = 1;
|
||||
|
||||
/* 4. */
|
||||
ecma_char_t current = lit_cesu8_read_next (&string_curr_p);
|
||||
if (current == LIT_CHAR_MINUS)
|
||||
{
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
/* 5. */
|
||||
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
|
||||
{
|
||||
start_p = string_curr_p;
|
||||
if (string_curr_p < string_end_p)
|
||||
{
|
||||
current = lit_cesu8_read_next (&string_curr_p);
|
||||
}
|
||||
}
|
||||
|
||||
/* 6. */
|
||||
ecma_number_t radix_num;
|
||||
radix = ecma_get_number (radix, &radix_num);
|
||||
|
||||
if (!ecma_is_value_empty (radix))
|
||||
{
|
||||
return radix;
|
||||
}
|
||||
|
||||
int32_t rad = ecma_number_to_int32 (radix_num);
|
||||
|
||||
/* 7.*/
|
||||
bool strip_prefix = true;
|
||||
|
||||
/* 8. */
|
||||
if (rad != 0)
|
||||
{
|
||||
/* 8.a */
|
||||
if (rad < 2 || rad > 36)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
/* 8.b */
|
||||
else if (rad != 16)
|
||||
{
|
||||
strip_prefix = false;
|
||||
}
|
||||
}
|
||||
/* 9. */
|
||||
else
|
||||
{
|
||||
rad = 10;
|
||||
}
|
||||
|
||||
/* 10. */
|
||||
if (strip_prefix
|
||||
&& ((end_p - start_p) >= 2)
|
||||
&& (current == LIT_CHAR_0))
|
||||
{
|
||||
ecma_char_t next = *string_curr_p;
|
||||
if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X)
|
||||
{
|
||||
/* Skip the 'x' or 'X' characters. */
|
||||
start_p = ++string_curr_p;
|
||||
rad = 16;
|
||||
}
|
||||
}
|
||||
|
||||
/* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */
|
||||
string_curr_p = start_p;
|
||||
while (string_curr_p < string_end_p)
|
||||
{
|
||||
ecma_char_t current_char = *string_curr_p++;
|
||||
int32_t current_number;
|
||||
|
||||
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
|
||||
{
|
||||
current_number = current_char - LIT_CHAR_LOWERCASE_A + 10;
|
||||
}
|
||||
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
|
||||
{
|
||||
current_number = current_char - LIT_CHAR_UPPERCASE_A + 10;
|
||||
}
|
||||
else if (lit_char_is_decimal_digit (current_char))
|
||||
{
|
||||
current_number = current_char - LIT_CHAR_0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a valid number char, set value to radix so it fails to pass as a valid character. */
|
||||
current_number = rad;
|
||||
}
|
||||
|
||||
if (!(current_number < rad))
|
||||
{
|
||||
end_p = --string_curr_p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 12. */
|
||||
if (end_p == start_p)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
ecma_number_t value = ECMA_NUMBER_ZERO;
|
||||
ecma_number_t multiplier = 1.0f;
|
||||
|
||||
/* 13. and 14. */
|
||||
string_curr_p = end_p;
|
||||
|
||||
while (string_curr_p > start_p)
|
||||
{
|
||||
ecma_char_t current_char = *(--string_curr_p);
|
||||
ecma_number_t current_number = ECMA_NUMBER_MINUS_ONE;
|
||||
|
||||
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
|
||||
{
|
||||
current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10;
|
||||
}
|
||||
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
|
||||
{
|
||||
current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (lit_char_is_decimal_digit (current_char));
|
||||
current_number = (ecma_number_t) current_char - LIT_CHAR_0;
|
||||
}
|
||||
|
||||
value += current_number * multiplier;
|
||||
multiplier *= (ecma_number_t) rad;
|
||||
}
|
||||
|
||||
/* 15. */
|
||||
if (sign < 0)
|
||||
{
|
||||
value *= (ecma_number_t) sign;
|
||||
}
|
||||
return ecma_make_number_value (value);
|
||||
} /* ecma_number_parse_int */
|
||||
|
||||
/**
|
||||
* The Number object's 'parseFloat' routine
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 15.1.2.2
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_number_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's first argument's
|
||||
* string buffer */
|
||||
lit_utf8_size_t string_buff_size) /**< routine's first argument's
|
||||
* string buffer's size */
|
||||
{
|
||||
if (string_buff_size <= 0)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
const lit_utf8_byte_t *str_curr_p = string_buff;
|
||||
|
||||
/* 2. Remove leading whitespace. */
|
||||
ecma_string_trim_helper (&str_curr_p, &string_buff_size);
|
||||
|
||||
const lit_utf8_byte_t *str_end_p = str_curr_p + string_buff_size;
|
||||
const lit_utf8_byte_t *start_p = str_curr_p;
|
||||
const lit_utf8_byte_t *end_p = str_end_p;
|
||||
|
||||
bool sign = false;
|
||||
ecma_char_t current;
|
||||
|
||||
if (str_curr_p < str_end_p)
|
||||
{
|
||||
/* Check if sign is present. */
|
||||
current = *str_curr_p;
|
||||
if (current == LIT_CHAR_MINUS)
|
||||
{
|
||||
sign = true;
|
||||
}
|
||||
|
||||
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
|
||||
{
|
||||
/* Set starting position to be after the sign character. */
|
||||
start_p = ++str_curr_p;
|
||||
}
|
||||
}
|
||||
|
||||
const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL);
|
||||
lit_utf8_byte_t *infinity_str_curr_p = (lit_utf8_byte_t *) infinity_str_p;
|
||||
lit_utf8_byte_t *infinity_str_end_p = infinity_str_curr_p + sizeof (*infinity_str_p);
|
||||
|
||||
/* Check if string is equal to "Infinity". */
|
||||
while (str_curr_p < str_end_p
|
||||
&& *str_curr_p++ == *infinity_str_curr_p++)
|
||||
{
|
||||
if (infinity_str_curr_p == infinity_str_end_p)
|
||||
{
|
||||
/* String matched Infinity. */
|
||||
return ecma_make_number_value (ecma_number_make_infinity (sign));
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset to starting position. */
|
||||
str_curr_p = start_p;
|
||||
|
||||
/* String ended after sign character, or was empty after removing leading whitespace. */
|
||||
if (str_curr_p >= str_end_p)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
/* Reset to starting position. */
|
||||
str_curr_p = start_p;
|
||||
|
||||
current = *str_curr_p;
|
||||
|
||||
bool has_whole_part = false;
|
||||
bool has_fraction_part = false;
|
||||
|
||||
/* Check digits of whole part. */
|
||||
if (lit_char_is_decimal_digit (current))
|
||||
{
|
||||
has_whole_part = true;
|
||||
str_curr_p++;
|
||||
|
||||
while (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
if (!lit_char_is_decimal_digit (current))
|
||||
{
|
||||
str_curr_p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set end position to the end of whole part. */
|
||||
end_p = str_curr_p;
|
||||
if (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p;
|
||||
|
||||
/* Check decimal point. */
|
||||
if (current == LIT_CHAR_DOT)
|
||||
{
|
||||
str_curr_p++;
|
||||
|
||||
if (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p;
|
||||
|
||||
if (lit_char_is_decimal_digit (current))
|
||||
{
|
||||
has_fraction_part = true;
|
||||
|
||||
/* Check digits of fractional part. */
|
||||
while (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
if (!lit_char_is_decimal_digit (current))
|
||||
{
|
||||
str_curr_p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set end position to end of fraction part. */
|
||||
end_p = str_curr_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
}
|
||||
|
||||
/* Check exponent. */
|
||||
if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E)
|
||||
&& (has_whole_part || has_fraction_part)
|
||||
&& str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
|
||||
/* Check sign of exponent. */
|
||||
if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS)
|
||||
&& str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
}
|
||||
|
||||
if (lit_char_is_decimal_digit (current))
|
||||
{
|
||||
/* Check digits of exponent part. */
|
||||
while (str_curr_p < str_end_p)
|
||||
{
|
||||
current = *str_curr_p++;
|
||||
if (!lit_char_is_decimal_digit (current))
|
||||
{
|
||||
str_curr_p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set end position to end of exponent part. */
|
||||
end_p = str_curr_p;
|
||||
}
|
||||
}
|
||||
|
||||
/* String did not contain a valid number. */
|
||||
if (start_p == end_p)
|
||||
{
|
||||
return ecma_make_nan_value ();
|
||||
}
|
||||
|
||||
/* 5. */
|
||||
ecma_number_t ret_num = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (end_p - start_p));
|
||||
|
||||
if (sign)
|
||||
{
|
||||
ret_num *= ECMA_NUMBER_MINUS_ONE;
|
||||
}
|
||||
|
||||
return ecma_make_number_value (ret_num);
|
||||
} /* ecma_number_parse_float */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@@ -400,6 +400,11 @@ ecma_number_t ecma_number_get_prev (ecma_number_t num);
|
||||
ecma_number_t ecma_number_get_next (ecma_number_t num);
|
||||
ecma_number_t ecma_number_trunc (ecma_number_t num);
|
||||
ecma_number_t ecma_number_calc_remainder (ecma_number_t left_num, ecma_number_t right_num);
|
||||
ecma_value_t ecma_number_parse_int (const lit_utf8_byte_t *string_buff,
|
||||
lit_utf8_size_t string_buff_size,
|
||||
ecma_value_t radix);
|
||||
ecma_value_t ecma_number_parse_float (const lit_utf8_byte_t *string_buff,
|
||||
lit_utf8_size_t string_buff_size);
|
||||
ecma_value_t ecma_integer_multiply (ecma_integer_value_t left_integer, ecma_integer_value_t right_integer);
|
||||
lit_utf8_size_t ecma_number_to_decimal (ecma_number_t num, lit_utf8_byte_t *out_digits_p, int32_t *out_decimal_exp_p);
|
||||
lit_utf8_size_t ecma_number_to_binary_floating_point_number (ecma_number_t num,
|
||||
|
||||
Reference in New Issue
Block a user