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 68f538b67..d862e0c7e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -2095,6 +2095,90 @@ ecma_builtin_string_prototype_object_trim (ecma_value_t this_arg) /**< this argu return ret_value; } /* ecma_builtin_string_prototype_object_trim */ +#if ENABLED (JERRY_ES2015_BUILTIN) + +/** + * The String.prototype object's 'repeat' routine + * + * See also: + * ECMA-262 v6, 21.1.3.13 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_string_prototype_object_repeat (ecma_value_t this_arg, /**< this argument */ + ecma_value_t count) /**< times to repeat */ +{ + /* 1 */ + ecma_value_t check_coercible_value = ecma_op_check_object_coercible (this_arg); + + if (ECMA_IS_VALUE_ERROR (check_coercible_value)) + { + return check_coercible_value; + } + + /* 2, 3 */ + ecma_value_t to_string_val = ecma_op_to_string (this_arg); + + if (ECMA_IS_VALUE_ERROR (to_string_val)) + { + return to_string_val; + } + + ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val); + ecma_string_t *ret_string_p; + + /* 4 */ + ecma_number_t length_number; + ecma_value_t length_value = ecma_get_number (count, &length_number); + + /* 5 */ + if (ECMA_IS_VALUE_ERROR (length_value)) + { + ecma_deref_ecma_string (original_string_p); + return length_value; + } + + int32_t length = ecma_number_to_int32 (length_number); + + bool isNan = ecma_number_is_nan (length_number); + + /* 6, 7 */ + if (length < 0 || (!isNan && ecma_number_is_infinity (length_number))) + { + ecma_deref_ecma_string (original_string_p); + return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid count value")); + } + + if (length == 0 || isNan) + { + ecma_deref_ecma_string (original_string_p); + return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); + } + + lit_utf8_size_t size = ecma_string_get_utf8_size (original_string_p); + lit_utf8_size_t total_size = size * (lit_utf8_size_t) length; + + JMEM_DEFINE_LOCAL_ARRAY (str_buffer, total_size, lit_utf8_byte_t); + + lit_utf8_byte_t *buffer_ptr = str_buffer; + + for (int32_t n = 0; n < length; n++) + { + buffer_ptr += ecma_string_copy_to_cesu8_buffer (original_string_p, buffer_ptr, + (lit_utf8_size_t) (size)); + } + + ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer)); + JMEM_FINALIZE_LOCAL_ARRAY (str_buffer); + ecma_deref_ecma_string (original_string_p); + + return ecma_make_string_value (ret_string_p); +} /* ecma_builtin_string_prototype_object_repeat */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + #if ENABLED (JERRY_BUILTIN_ANNEXB) /** 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 08eb610c4..93942e01f 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 @@ -55,6 +55,10 @@ ROUTINE (LIT_MAGIC_STRING_REPLACE, ecma_builtin_string_prototype_object_replace, ROUTINE (LIT_MAGIC_STRING_SEARCH, ecma_builtin_string_prototype_object_search, 1, 1) #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +#if ENABLED (JERRY_ES2015_BUILTIN) +ROUTINE (LIT_MAGIC_STRING_REPEAT, ecma_builtin_string_prototype_object_repeat, 1, 1) +#endif /* ENABLED (JERRY_ES2015_BUILTIN) */ + ROUTINE (LIT_MAGIC_STRING_SPLIT, ecma_builtin_string_prototype_object_split, 2, 2) ROUTINE (LIT_MAGIC_STRING_SUBSTRING, ecma_builtin_string_prototype_object_substring, 2, 2) ROUTINE (LIT_MAGIC_STRING_TO_LOWER_CASE_UL, ecma_builtin_string_prototype_object_to_lower_case, 0, 0) diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 75eb3acbd..04ba63732 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -300,6 +300,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REDUCE, "reduce") #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REJECT, "reject") #endif +#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPEAT, "repeat") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ || ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEARCH, "search") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 344dad8a6..db8369523 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -139,6 +139,7 @@ LIT_MAGIC_STRING_OBJECT = "object" LIT_MAGIC_STRING_RANDOM = "random" LIT_MAGIC_STRING_REDUCE = "reduce" LIT_MAGIC_STRING_REJECT = "reject" +LIT_MAGIC_STRING_REPEAT = "repeat" LIT_MAGIC_STRING_SEARCH = "search" LIT_MAGIC_STRING_SOURCE = "source" LIT_MAGIC_STRING_SPLICE = "splice" diff --git a/tests/jerry/es2015/string-prototype-repeat.js b/tests/jerry/es2015/string-prototype-repeat.js new file mode 100644 index 000000000..3ca2290b8 --- /dev/null +++ b/tests/jerry/es2015/string-prototype-repeat.js @@ -0,0 +1,71 @@ +/* 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. + */ + +// ES v6.0 21.1.3.13.6 +var z = "I am vengeance"; +try { + z.repeat (-1); + assert (false); +} catch (e) { + assert (e instanceof RangeError); +} + +// ES v6.0 21.1.3.13.7 +var x = "I am the night"; +try { + print(z.repeat (Infinity)); + assert (false); +} catch (e) { + assert (e instanceof RangeError); +} + +// ES v6.0 21.1.3.13.8 +assert (z.repeat (0) === ""); +assert (z.repeat (NaN) === ""); + +var y = "I am batman "; +assert (y.repeat (3) === "I am batman I am batman I am batman "); + +assert (String.prototype.repeat.call ("My cat is awesome. ", 3) === "My cat is awesome. My cat is awesome. My cat is awesome. "); + +try { + String.prototype.repeat.call (undefined); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + String.prototype.repeat.call (null); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + String.prototype.repeat.call (undefined, "Sylveon"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +var a = Symbol ("Unicorn invasion.", 3); +try { + String.prototype.repeat.call (a); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} +