Implement String.fromCodePoint method (#3281)
The algorithm is based on ECMA-262 v6, 21.1.2.2 JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
This commit is contained in:
committed by
Robert Fancsik
parent
e1fc90db0e
commit
35d9b1ab17
@@ -13,6 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lit-strings.h"
|
||||||
#include "ecma-alloc.h"
|
#include "ecma-alloc.h"
|
||||||
#include "ecma-builtins.h"
|
#include "ecma-builtins.h"
|
||||||
#include "ecma-conversion.h"
|
#include "ecma-conversion.h"
|
||||||
@@ -109,6 +110,75 @@ ecma_builtin_string_object_from_char_code (ecma_value_t this_arg, /**< 'this' ar
|
|||||||
return ret_value;
|
return ret_value;
|
||||||
} /* ecma_builtin_string_object_from_char_code */
|
} /* ecma_builtin_string_object_from_char_code */
|
||||||
|
|
||||||
|
#if ENABLED (JERRY_ES2015_BUILTIN)
|
||||||
|
/**
|
||||||
|
* The String object's 'fromCodePoint' routine
|
||||||
|
*
|
||||||
|
* See also:
|
||||||
|
* ECMA-262 v6, 21.1.2.2
|
||||||
|
*
|
||||||
|
* @return ecma value
|
||||||
|
* Returned value must be freed with ecma_free_value.
|
||||||
|
*/
|
||||||
|
static ecma_value_t
|
||||||
|
ecma_builtin_string_object_from_code_point (ecma_value_t this_arg, /**< 'this' argument */
|
||||||
|
const ecma_value_t args[], /**< arguments list */
|
||||||
|
ecma_length_t args_number) /**< number of arguments */
|
||||||
|
{
|
||||||
|
JERRY_UNUSED (this_arg);
|
||||||
|
|
||||||
|
if (args_number == 0)
|
||||||
|
{
|
||||||
|
return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_stringbuilder_t builder = ecma_stringbuilder_create ();
|
||||||
|
|
||||||
|
for (ecma_length_t index = 0; index < args_number; index++)
|
||||||
|
{
|
||||||
|
ecma_value_t to_number_value = ecma_op_to_number (args[index]);
|
||||||
|
|
||||||
|
if (ECMA_IS_VALUE_ERROR (to_number_value))
|
||||||
|
{
|
||||||
|
ecma_stringbuilder_destroy (&builder);
|
||||||
|
return to_number_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_number_t to_number_num = ecma_get_number_from_value (to_number_value);
|
||||||
|
ecma_free_value (to_number_value);
|
||||||
|
|
||||||
|
ecma_number_t to_int_num;
|
||||||
|
ecma_value_t to_int_value = ecma_op_to_integer (to_number_value, &to_int_num);
|
||||||
|
|
||||||
|
if (ECMA_IS_VALUE_ERROR (to_int_value))
|
||||||
|
{
|
||||||
|
ecma_stringbuilder_destroy (&builder);
|
||||||
|
return to_int_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_number_num != to_int_num || to_int_num < 0 || to_int_num > LIT_UNICODE_CODE_POINT_MAX)
|
||||||
|
{
|
||||||
|
ecma_stringbuilder_destroy (&builder);
|
||||||
|
return ecma_raise_range_error (ECMA_ERR_MSG ("Error: Invalid code point"));
|
||||||
|
}
|
||||||
|
|
||||||
|
lit_code_point_t code_point = (uint32_t) to_int_num;
|
||||||
|
|
||||||
|
ecma_char_t converted_cp[2];
|
||||||
|
uint8_t encoded_size = lit_utf16_encode_code_point (code_point, converted_cp);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < encoded_size; i++)
|
||||||
|
{
|
||||||
|
ecma_stringbuilder_append_char (&builder, converted_cp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_string_t *ret_str_p = ecma_stringbuilder_finalize (&builder);
|
||||||
|
|
||||||
|
return ecma_make_string_value (ret_str_p);
|
||||||
|
} /* ecma_builtin_string_object_from_code_point */
|
||||||
|
#endif /* ENABLED (JERRY_ES2015_BUILTIN) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle calling [[Call]] of built-in String object
|
* Handle calling [[Call]] of built-in String object
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE,
|
|||||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||||
ROUTINE (LIT_MAGIC_STRING_FROM_CHAR_CODE_UL, ecma_builtin_string_object_from_char_code, NON_FIXED, 1)
|
ROUTINE (LIT_MAGIC_STRING_FROM_CHAR_CODE_UL, ecma_builtin_string_object_from_char_code, NON_FIXED, 1)
|
||||||
|
|
||||||
|
#if ENABLED (JERRY_ES2015_BUILTIN)
|
||||||
|
ROUTINE (LIT_MAGIC_STRING_FROM_CODE_POINT_UL, ecma_builtin_string_object_from_code_point, NON_FIXED, 1)
|
||||||
|
#endif /* ENABLED (JERRY_ES2015_BUILTIN) */
|
||||||
|
|
||||||
#endif /* ENABLED (JERRY_BUILTIN_STRING) */
|
#endif /* ENABLED (JERRY_BUILTIN_STRING) */
|
||||||
|
|
||||||
#include "ecma-builtin-helpers-macro-undefs.inc.h"
|
#include "ecma-builtin-helpers-macro-undefs.inc.h"
|
||||||
|
|||||||
@@ -684,6 +684,11 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_EXTENSIBLE, "isExtensible")
|
|||||||
#if ENABLED (JERRY_BUILTIN_DATE)
|
#if ENABLED (JERRY_BUILTIN_DATE)
|
||||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_DATE_STRING_UL, "toDateString")
|
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_DATE_STRING_UL, "toDateString")
|
||||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_TIME_STRING_UL, "toTimeString")
|
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_TIME_STRING_UL, "toTimeString")
|
||||||
|
#endif
|
||||||
|
#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN)
|
||||||
|
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FROM_CODE_POINT_UL, "fromCodePoint")
|
||||||
|
#endif
|
||||||
|
#if ENABLED (JERRY_BUILTIN_DATE)
|
||||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_MINUTES_UL, "getUTCMinutes")
|
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_MINUTES_UL, "getUTCMinutes")
|
||||||
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_SECONDS_UL, "getUTCSeconds")
|
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_SECONDS_UL, "getUTCSeconds")
|
||||||
#endif
|
#endif
|
||||||
@@ -848,7 +853,9 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_SET_ITERATOR_UL)
|
|||||||
#else
|
#else
|
||||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_CONFIGURABLE)
|
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_CONFIGURABLE)
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED (JERRY_BUILTIN_DATE)
|
#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN)
|
||||||
|
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_FROM_CODE_POINT_UL)
|
||||||
|
#elif ENABLED (JERRY_BUILTIN_DATE)
|
||||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_GET_UTC_MINUTES_UL)
|
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_GET_UTC_MINUTES_UL)
|
||||||
#else
|
#else
|
||||||
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL)
|
LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL)
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ LIT_MAGIC_STRING_SET_ITERATOR_UL = "Set Iterator"
|
|||||||
LIT_MAGIC_STRING_MAP_ITERATOR_UL = "Map Iterator"
|
LIT_MAGIC_STRING_MAP_ITERATOR_UL = "Map Iterator"
|
||||||
LIT_MAGIC_STRING_CONFIGURABLE = "configurable"
|
LIT_MAGIC_STRING_CONFIGURABLE = "configurable"
|
||||||
LIT_MAGIC_STRING_FROM_CHAR_CODE_UL = "fromCharCode"
|
LIT_MAGIC_STRING_FROM_CHAR_CODE_UL = "fromCharCode"
|
||||||
|
LIT_MAGIC_STRING_FROM_CODE_POINT_UL = "fromCodePoint"
|
||||||
LIT_MAGIC_STRING_IS_EXTENSIBLE = "isExtensible"
|
LIT_MAGIC_STRING_IS_EXTENSIBLE = "isExtensible"
|
||||||
LIT_MAGIC_STRING_TO_DATE_STRING_UL = "toDateString"
|
LIT_MAGIC_STRING_TO_DATE_STRING_UL = "toDateString"
|
||||||
LIT_MAGIC_STRING_TO_TIME_STRING_UL = "toTimeString"
|
LIT_MAGIC_STRING_TO_TIME_STRING_UL = "toTimeString"
|
||||||
|
|||||||
@@ -243,6 +243,29 @@ convert_code_point_to_high_surrogate (lit_code_point_t code_point) /**< code poi
|
|||||||
return (LIT_UTF16_HIGH_SURROGATE_MARKER | code_unit_bits);
|
return (LIT_UTF16_HIGH_SURROGATE_MARKER | code_unit_bits);
|
||||||
} /* convert_code_point_to_high_surrogate */
|
} /* convert_code_point_to_high_surrogate */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF16 Encoding method for a code point
|
||||||
|
*
|
||||||
|
* See also:
|
||||||
|
* ECMA-262 v6, 10.1.1
|
||||||
|
*
|
||||||
|
* @return uint8_t, the number of returning code points
|
||||||
|
*/
|
||||||
|
uint8_t
|
||||||
|
lit_utf16_encode_code_point (lit_code_point_t cp, /**< the code point we encode */
|
||||||
|
ecma_char_t *cu_p) /**< result of the encoding */
|
||||||
|
{
|
||||||
|
if (cp <= LIT_UTF16_CODE_UNIT_MAX)
|
||||||
|
{
|
||||||
|
cu_p[0] = (ecma_char_t) cp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cu_p[0] = convert_code_point_to_high_surrogate (cp);
|
||||||
|
cu_p[1] = convert_code_point_to_low_surrogate (cp);
|
||||||
|
return 2;
|
||||||
|
} /* lit_utf16_encode_code_point */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate size of a zero-terminated utf-8 string
|
* Calculate size of a zero-terminated utf-8 string
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ lit_code_point_t lit_convert_surrogate_pair_to_code_point (ecma_char_t high_surr
|
|||||||
bool lit_compare_utf8_strings_relational (const lit_utf8_byte_t *string1_p, lit_utf8_size_t string1_size,
|
bool lit_compare_utf8_strings_relational (const lit_utf8_byte_t *string1_p, lit_utf8_size_t string1_size,
|
||||||
const lit_utf8_byte_t *string2_p, lit_utf8_size_t string2_size);
|
const lit_utf8_byte_t *string2_p, lit_utf8_size_t string2_size);
|
||||||
|
|
||||||
|
uint8_t lit_utf16_encode_code_point (lit_code_point_t cp, ecma_char_t *cu_p);
|
||||||
|
|
||||||
/* read code point from buffer */
|
/* read code point from buffer */
|
||||||
lit_utf8_size_t lit_read_code_point_from_utf8 (const lit_utf8_byte_t *buf_p, lit_utf8_size_t buf_size,
|
lit_utf8_size_t lit_read_code_point_from_utf8 (const lit_utf8_byte_t *buf_p, lit_utf8_size_t buf_size,
|
||||||
lit_code_point_t *code_point);
|
lit_code_point_t *code_point);
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Tests with valid inputs
|
||||||
|
assert(String.fromCodePoint(42) === "*")
|
||||||
|
assert(String.fromCodePoint(65, 90) === "AZ");
|
||||||
|
assert(String.fromCodePoint(0x404) === "Є");
|
||||||
|
assert(String.fromCodePoint(194564) === "你");
|
||||||
|
assert(String.fromCodePoint(0x1D306, 0x61, 0x1D307) === "𝌆a𝌇");
|
||||||
|
assert(String.fromCodePoint(0x1F303) === "🌃");
|
||||||
|
|
||||||
|
// Tests with invalid inputs
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint('_'));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint(Infinity));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint(-1));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint(3.14));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint(3e-2));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert(String.fromCodePoint(NaN));
|
||||||
|
assert(false);
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof RangeError);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user