diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index 403593e84..f37eab89e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -30,6 +30,7 @@ #include "jrt.h" #include "jrt-libc-includes.h" #include "lit-char-helpers.h" +#include "lit-strings.h" #if ENABLED (JERRY_BUILTIN_REGEXP) #include "ecma-regexp-object.h" @@ -77,6 +78,7 @@ enum ECMA_STRING_PROTOTYPE_SUBSTR, ECMA_STRING_PROTOTYPE_REPEAT, + ECMA_STRING_PROTOTYPE_CODE_POINT_AT, /* Note: These 5 routines MUST be in this order */ ECMA_STRING_PROTOTYPE_INDEX_OF, ECMA_STRING_PROTOTYPE_LAST_INDEX_OF, @@ -1401,6 +1403,54 @@ ecma_builtin_string_prototype_object_repeat (ecma_string_t *original_string_p, / return ecma_make_string_value (ret_string_p); } /* ecma_builtin_string_prototype_object_repeat */ +/** + * The String.prototype object's 'codePointAt' routine + * + * See also: + * ECMA-262 v6, 21.1.3.3 + * + * @return lit_code_point_t + */ +static ecma_value_t +ecma_builtin_string_prototype_object_code_point_at (ecma_string_t *this_string_p, /**< this argument */ + ecma_value_t pos) /**< given position */ +{ + ecma_number_t pos_num; + ecma_value_t error = ecma_op_to_integer (pos, &pos_num); + + if (ECMA_IS_VALUE_ERROR (error)) + { + return error; + } + + ecma_length_t size = ecma_string_get_length (this_string_p); + + if (pos_num < 0 || pos_num >= size) + { + return ECMA_VALUE_UNDEFINED; + } + + uint32_t index = (uint32_t) pos_num; + + ecma_char_t first = ecma_string_get_char_at_pos (this_string_p, index); + + if (first < LIT_UTF16_HIGH_SURROGATE_MIN + || first > LIT_UTF16_HIGH_SURROGATE_MAX + || index + 1 == size) + { + return ecma_make_uint32_value (first); + } + + ecma_char_t second = ecma_string_get_char_at_pos (this_string_p, index + 1); + + if (second < LIT_UTF16_LOW_SURROGATE_MARKER + || second > LIT_UTF16_LOW_SURROGATE_MAX) + { + return ecma_make_uint32_value (first); + } + + return ecma_make_uint32_value (lit_convert_surrogate_pair_to_code_point (first, second)); +} /* ecma_builtin_string_prototype_object_code_point_at */ #endif /* ENABLED (JERRY_ES2015_BUILTIN) */ #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -1615,6 +1665,11 @@ ecma_builtin_string_prototype_dispatch_routine (uint16_t builtin_routine_id, /** ret_value = ecma_builtin_string_prototype_object_repeat (string_p, arg1); break; } + case ECMA_STRING_PROTOTYPE_CODE_POINT_AT: + { + ret_value = ecma_builtin_string_prototype_object_code_point_at (string_p, arg1); + break; + } #endif /* ENABLED (JERRY_ES2015_BUILTIN) */ #if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) case ECMA_STRING_PROTOTYPE_ITERATOR: diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h index 5679079c0..3b8ae7909 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.inc.h @@ -72,6 +72,7 @@ ROUTINE (LIT_MAGIC_STRING_REPEAT, ECMA_STRING_PROTOTYPE_REPEAT, 1, 1) ROUTINE (LIT_MAGIC_STRING_STARTS_WITH, ECMA_STRING_PROTOTYPE_STARTS_WITH, 2, 1) ROUTINE (LIT_MAGIC_STRING_INCLUDES, ECMA_STRING_PROTOTYPE_INCLUDES, 2, 1) ROUTINE (LIT_MAGIC_STRING_ENDS_WITH, ECMA_STRING_PROTOTYPE_ENDS_WITH, 2, 1) +ROUTINE (LIT_MAGIC_STRING_CODE_POINT_AT, ECMA_STRING_PROTOTYPE_CODE_POINT_AT, 1, 1) #endif /* ENABLED (JERRY_ES2015_BUILTIN) */ #if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 367b57038..aea9df57e 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -612,6 +612,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYNTAX_ERROR_UL, "SyntaxError") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UINT16_ARRAY_UL, "Uint16Array") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UINT32_ARRAY_UL, "Uint32Array") #endif +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CODE_POINT_AT, "codePointAt") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONSTRUCTOR, "constructor") #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FULL_YEAR_UL, "getFullYear") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 200a64e8d..a1fd4b246 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -261,6 +261,7 @@ LIT_MAGIC_STRING_SYNTAX_ERROR_UL = "SyntaxError" LIT_MAGIC_STRING_UINT16_ARRAY_UL = "Uint16Array" LIT_MAGIC_STRING_UINT32_ARRAY_UL = "Uint32Array" LIT_MAGIC_STRING_CONSTRUCTOR = "constructor" +LIT_MAGIC_STRING_CODE_POINT_AT = "codePointAt" LIT_MAGIC_STRING_GET_FULL_YEAR_UL = "getFullYear" LIT_MAGIC_STRING_GET_UTC_HOURS_UL = "getUTCHours" LIT_MAGIC_STRING_GET_UTC_MONTH_UL = "getUTCMonth" diff --git a/tests/jerry/es2015/string-prototype-codepointat.js b/tests/jerry/es2015/string-prototype-codepointat.js new file mode 100644 index 000000000..6f50af966 --- /dev/null +++ b/tests/jerry/es2015/string-prototype-codepointat.js @@ -0,0 +1,54 @@ +// 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. + +var str = "A🌃B\uD800"; +var obj = {}; + +// Test with normal inputs +assert(str.codePointAt(0) === 65); +assert(str.codePointAt(1) === 127747); +assert(str.codePointAt(2) === 57091); +assert(str.codePointAt(3) === 66); +assert(str.codePointAt(4) === 55296); + +// Test with string +assert(str.codePointAt("a") === 65); +assert(str.codePointAt("B") === 65); + +// Test with object +assert(str.codePointAt(obj) === 65); + +// Test with NaN +assert(str.codePointAt(NaN) === 65); + +// Test when the input >= length +assert(str.codePointAt(5) === undefined); +assert(str.codePointAt(10) === undefined); + +// Test witn negative +assert(str.codePointAt(-1) === undefined); +assert(str.codePointAt(-5) === undefined); +assert(str.codePointAt(-0) === 65); + +// Test with undefined and +/- Infinity +assert(str.codePointAt(undefined) === 65); +assert(str.codePointAt(Infinity) === undefined); +assert(str.codePointAt(-Infinity) === undefined); + +// Test with boolean +assert(str.codePointAt(true) === 127747); +assert(str.codePointAt(false) === 65); + +// Test when input > UINT32_MAX +assert(str.codePointAt(4294967299) === undefined);