diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index dda5fe42a5..18994cf327 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -2079,6 +2079,11 @@ bool Genesis::InstallExperimentalNatives() { "native array-iterator.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } + if (FLAG_harmony_strings && + strcmp(ExperimentalNatives::GetScriptName(i).start(), + "native harmony-string.js") == 0) { + if (!CompileExperimentalBuiltin(isolate(), i)) return false; + } } InstallExperimentalNativeFunctions(); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index fa202f921a..5fc5d880b3 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -173,6 +173,7 @@ DEFINE_bool(harmony_generators, false, "enable harmony generators") DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)") DEFINE_bool(harmony_numeric_literals, false, "enable harmony numeric literals (0o77, 0b11)") +DEFINE_bool(harmony_strings, false, "enable harmony string") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) @@ -183,6 +184,7 @@ DEFINE_implication(harmony, harmony_observation) DEFINE_implication(harmony, harmony_generators) DEFINE_implication(harmony, harmony_iteration) DEFINE_implication(harmony, harmony_numeric_literals) +DEFINE_implication(harmony, harmony_strings) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_observation, harmony_collections) // TODO[dslomov] add harmony => harmony_typed_arrays diff --git a/src/harmony-string.js b/src/harmony-string.js new file mode 100644 index 0000000000..a5c6f4e2ec --- /dev/null +++ b/src/harmony-string.js @@ -0,0 +1,154 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +'use strict'; + +// This file relies on the fact that the following declaration has been made +// in runtime.js: +// var $String = global.String; +// var $Array = global.Array; + +// ------------------------------------------------------------------- + +// ES6 draft 07-15-13, section 15.5.3.21 +function StringRepeat(count) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["String.prototype.repeat"]); + } + + var s = TO_STRING_INLINE(this); + var n = ToInteger(count); + if (n < 0 || !NUMBER_IS_FINITE(n)) { + throw MakeRangeError("invalid_count_value", []); + } + + var elements = new InternalArray(n); + for (var i = 0; i < n; i++) { + elements[i] = s; + } + + return %StringBuilderConcat(elements, n, ""); +} + + +// ES6 draft 07-15-13, section 15.5.3.22 +function StringStartsWith(searchString /* position */) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["String.prototype.startsWith"]); + } + + var s = TO_STRING_INLINE(this); + var ss = TO_STRING_INLINE(searchString); + var pos = 0; + if (%_ArgumentsLength() > 1) { + pos = %_Arguments(1); // position + pos = ToInteger(pos); + } + + var s_len = s.length; + var start = MathMin(MathMax(pos, 0), s_len); + var ss_len = ss.length; + if (ss_len + start > s_len) { + return false; + } + + return %StringIndexOf(s, ss, start) === start; +} + + +// ES6 draft 07-15-13, section 15.5.3.23 +function StringEndsWith(searchString /* position */) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["String.prototype.endsWith"]); + } + + var s = TO_STRING_INLINE(this); + var ss = TO_STRING_INLINE(searchString); + var s_len = s.length; + var pos = s_len; + if (%_ArgumentsLength() > 1) { + var arg = %_Arguments(1); // position + if (!IS_UNDEFINED(arg)) { + pos = ToInteger(arg); + } + } + + var end = MathMin(MathMax(pos, 0), s_len); + var ss_len = ss.length; + var start = end - ss_len; + if (start < 0) { + return false; + } + + return %StringLastIndexOf(s, ss, start) === start; +} + + +// ES6 draft 07-15-13, section 15.5.3.24 +function StringContains(searchString /* position */) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["String.prototype.contains"]); + } + + var s = TO_STRING_INLINE(this); + var ss = TO_STRING_INLINE(searchString); + var pos = 0; + if (%_ArgumentsLength() > 1) { + pos = %_Arguments(1); // position + pos = ToInteger(pos); + } + + var s_len = s.length; + var start = MathMin(MathMax(pos, 0), s_len); + var ss_len = ss.length; + if (ss_len + start > s_len) { + return false; + } + + return %StringIndexOf(s, ss, start) !== -1; +} + + +// ------------------------------------------------------------------- + +function ExtendStringPrototype() { + %CheckIsBootstrapping(); + + // Set up the non-enumerable functions on the String prototype object. + InstallFunctions($String.prototype, DONT_ENUM, $Array( + "repeat", StringRepeat, + "startsWith", StringStartsWith, + "endsWith", StringEndsWith, + "contains", StringContains + )); +} + +ExtendStringPrototype(); \ No newline at end of file diff --git a/src/messages.js b/src/messages.js index 92ac1bc46a..b586d24882 100644 --- a/src/messages.js +++ b/src/messages.js @@ -126,6 +126,7 @@ var kMessages = { stack_overflow: ["Maximum call stack size exceeded"], invalid_time_value: ["Invalid time value"], + invalid_count_value: ["Invalid count value"], // SyntaxError paren_in_arg_string: ["Function arg string contains parenthesis"], not_isvar: ["builtin %IS_VAR: not a variable"], diff --git a/test/mjsunit/harmony/string-contains.js b/test/mjsunit/harmony/string-contains.js new file mode 100644 index 0000000000..700a6ed6bc --- /dev/null +++ b/test/mjsunit/harmony/string-contains.js @@ -0,0 +1,151 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-strings + +assertEquals(1, String.prototype.contains.length); + +var reString = "asdf[a-z]+(asdf)?"; +assertTrue(reString.contains("[a-z]+")); +assertTrue(reString.contains("(asdf)?")); + +// Random greek letters +var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395"; + +// Test single char pattern +assertTrue(twoByteString.contains("\u039a"), "Lamda"); +assertTrue(twoByteString.contains("\u0391"), "Alpha"); +assertTrue(twoByteString.contains("\u03a3"), "First Sigma"); +assertTrue(twoByteString.contains("\u03a3",3), "Second Sigma"); +assertTrue(twoByteString.contains("\u0395"), "Epsilon"); +assertFalse(twoByteString.contains("\u0392"), "Not beta"); + +// Test multi-char pattern +assertTrue(twoByteString.contains("\u039a\u0391"), "lambda Alpha"); +assertTrue(twoByteString.contains("\u0391\u03a3"), "Alpha Sigma"); +assertTrue(twoByteString.contains("\u03a3\u03a3"), "Sigma Sigma"); +assertTrue(twoByteString.contains("\u03a3\u0395"), "Sigma Epsilon"); + +assertFalse(twoByteString.contains("\u0391\u03a3\u0395"), + "Not Alpha Sigma Epsilon"); + +//single char pattern +assertTrue(twoByteString.contains("\u0395")); + +assertThrows("String.prototype.contains.call(null, 'test')", TypeError); +assertThrows("String.prototype.contains.call(null, null)", TypeError); +assertThrows("String.prototype.contains.call(undefined, undefined)", TypeError); + +assertThrows("String.prototype.contains.apply(null, ['test'])", TypeError); +assertThrows("String.prototype.contains.apply(null, [null])", TypeError); +assertThrows("String.prototype.contains.apply(undefined, [undefined])", TypeError); + +var TEST_INPUT = [{ + msg: "Empty string", val: "" +}, { + msg: "Number 1234.34", val: 1234.34 +}, { + msg: "Integer number 0", val: 0 +}, { + msg: "Negative number -1", val: -1 +}, { + msg: "Boolean true", val: true +}, { + msg: "Boolean false", val: false +}, { + msg: "Regular expression /\d+/", val: /\d+/ +}, { + msg: "Empty array []", val: [] +}, { + msg: "Empty object {}", val: {} +}, { + msg: "Array of size 3", val: new Array(3) +}]; + +var i = 0; +var l = TEST_INPUT.length; + +for (; i < l; i++) { + var e = TEST_INPUT[i]; + var v = e.val; + var s = String(v); + assertTrue(s.contains(v), e.msg); + assertTrue(String.prototype.contains.call(v, v), e.msg); + assertTrue(String.prototype.contains.apply(v, [v]), e.msg); +} + +// Test cases found in FF +assertTrue("abc".contains("a")); +assertTrue("abc".contains("b")); +assertTrue("abc".contains("abc")); +assertTrue("abc".contains("bc")); +assertFalse("abc".contains("d")); +assertFalse("abc".contains("abcd")); +assertFalse("abc".contains("ac")); +assertTrue("abc".contains("abc", 0)); +assertTrue("abc".contains("bc", 0)); +assertFalse("abc".contains("de", 0)); +assertTrue("abc".contains("bc", 1)); +assertTrue("abc".contains("c", 1)); +assertFalse("abc".contains("a", 1)); +assertFalse("abc".contains("abc", 1)); +assertTrue("abc".contains("c", 2)); +assertFalse("abc".contains("d", 2)); +assertFalse("abc".contains("dcd", 2)); +assertFalse("abc".contains("a", 42)); +assertFalse("abc".contains("a", Infinity)); +assertTrue("abc".contains("ab", -43)); +assertFalse("abc".contains("cd", -42)); +assertTrue("abc".contains("ab", -Infinity)); +assertFalse("abc".contains("cd", -Infinity)); +assertTrue("abc".contains("ab", NaN)); +assertFalse("abc".contains("cd", NaN)); +assertFalse("xyzzy".contains("zy\0", 2)); + +var dots = Array(10000).join('.'); +assertFalse(dots.contains("\x01", 10000)); +assertFalse(dots.contains("\0", 10000)); + +var myobj = { + toString: function () { + return "abc"; + }, + contains: String.prototype.contains +}; +assertTrue(myobj.contains("abc")); +assertFalse(myobj.contains("cd")); + +var gotStr = false; +var gotPos = false; +myobj = { + toString: function () { + assertFalse(gotPos); + gotStr = true; + return "xyz"; + }, + contains: String.prototype.contains +}; diff --git a/test/mjsunit/harmony/string-endswith.js b/test/mjsunit/harmony/string-endswith.js new file mode 100644 index 0000000000..128cf1d023 --- /dev/null +++ b/test/mjsunit/harmony/string-endswith.js @@ -0,0 +1,136 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-strings + +assertEquals(1, String.prototype.endsWith.length); + +var testString = "Hello World"; +assertTrue(testString.endsWith("")); +assertTrue(testString.endsWith("World")); +assertFalse(testString.endsWith("world")); +assertFalse(testString.endsWith("Hello World!")); +assertFalse(testString.endsWith(null)); +assertFalse(testString.endsWith(undefined)); + +assertTrue("null".endsWith(null)); +assertTrue("undefined".endsWith(undefined)); + +var georgianUnicodeString = "\u10D0\u10D1\u10D2\u10D3\u10D4\u10D5\u10D6\u10D7"; +assertTrue(georgianUnicodeString.endsWith(georgianUnicodeString)); +assertTrue(georgianUnicodeString.endsWith("\u10D4\u10D5\u10D6\u10D7")); +assertFalse(georgianUnicodeString.endsWith("\u10D0")); + +assertThrows("String.prototype.endsWith.call(null, 'test')", TypeError); +assertThrows("String.prototype.endsWith.call(null, null)", TypeError); +assertThrows("String.prototype.endsWith.call(undefined, undefined)", TypeError); + +assertThrows("String.prototype.endsWith.apply(null, ['test'])", TypeError); +assertThrows("String.prototype.endsWith.apply(null, [null])", TypeError); +assertThrows("String.prototype.endsWith.apply(undefined, [undefined])", TypeError); + +var TEST_INPUT = [{ + msg: "Empty string", val: "" +}, { + msg: "Number 1234.34", val: 1234.34 +}, { + msg: "Integer number 0", val: 0 +}, { + msg: "Negative number -1", val: -1 +}, { + msg: "Boolean true", val: true +}, { + msg: "Boolean false", val: false +}, { + msg: "Regular expression /\d+/", val: /\d+/ +}, { + msg: "Empty array []", val: [] +}, { + msg: "Empty object {}", val: {} +}, { + msg: "Array of size 3", val: new Array(3) +}]; + +function testNonStringValues() { + var i = 0; + var l = TEST_INPUT.length; + + for (; i < l; i++) { + var e = TEST_INPUT[i]; + var v = e.val; + var s = String(v); + assertTrue(s.endsWith(v), e.msg); + assertTrue(String.prototype.endsWith.call(v, v), e.msg); + assertTrue(String.prototype.endsWith.apply(v, [v]), e.msg); + } +} +testNonStringValues(); + +var CustomType = function(value) { + this.endsWith = String.prototype.endsWith; + this.toString = function() { + return String(value); + } +}; + +function testCutomType() { + var i = 0; + var l = TEST_INPUT.length; + + for (; i < l; i++) { + var e = TEST_INPUT[i]; + var v = e.val; + var o = new CustomType(v); + assertTrue(o.endsWith(v), e.msg); + } +} +testCutomType(); + + +// Test cases found in FF +assertTrue("abc".endsWith("abc")); +assertTrue("abcd".endsWith("bcd")); +assertTrue("abc".endsWith("c")); +assertFalse("abc".endsWith("abcd")); +assertFalse("abc".endsWith("bbc")); +assertFalse("abc".endsWith("b")); +assertTrue("abc".endsWith("abc", 3)); +assertTrue("abc".endsWith("bc", 3)); +assertFalse("abc".endsWith("a", 3)); +assertTrue("abc".endsWith("bc", 3)); +assertTrue("abc".endsWith("a", 1)); +assertFalse("abc".endsWith("abc", 1)); +assertTrue("abc".endsWith("b", 2)); +assertFalse("abc".endsWith("d", 2)); +assertFalse("abc".endsWith("dcd", 2)); +assertFalse("abc".endsWith("a", 42)); +assertTrue("abc".endsWith("bc", Infinity)); +assertFalse("abc".endsWith("a", Infinity)); +assertTrue("abc".endsWith("bc", undefined)); +assertFalse("abc".endsWith("bc", -43)); +assertFalse("abc".endsWith("bc", -Infinity)); +assertFalse("abc".endsWith("bc", NaN)); diff --git a/test/mjsunit/harmony/string-repeat.js b/test/mjsunit/harmony/string-repeat.js new file mode 100644 index 0000000000..182e5c0e0e --- /dev/null +++ b/test/mjsunit/harmony/string-repeat.js @@ -0,0 +1,74 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-strings + +assertEquals("000", String.prototype.repeat.call(0, 3)); +assertEquals("-1-1-1", String.prototype.repeat.call(-1, 3)); +assertEquals("2.12.12.1", String.prototype.repeat.call(2.1, 3)); +assertEquals("", String.prototype.repeat.call([], 3)); +assertEquals("1,2,3", String.prototype.repeat.call([1, 2, 3], 1)); +assertEquals("true", String.prototype.repeat.call(true, 1)); +assertEquals("false", String.prototype.repeat.call(false, 1)); +assertEquals("[object Object]", String.prototype.repeat.call({}, 1)); + +assertEquals("000", String.prototype.repeat.apply(0, [3])); +assertEquals("-1-1-1", String.prototype.repeat.apply(-1, [3])); +assertEquals("2.12.12.1", String.prototype.repeat.apply(2.1, [3])); +assertEquals("", String.prototype.repeat.apply([], [3])); +assertEquals("1,2,3", String.prototype.repeat.apply([1, 2, 3], [1])); +assertEquals("true", String.prototype.repeat.apply(true, [1])); +assertEquals("false", String.prototype.repeat.apply(false, [1])); +assertEquals("[object Object]", String.prototype.repeat.apply({}, [1])); + +assertEquals("\u10D8\u10D8\u10D8", "\u10D8".repeat(3)); + +assertThrows('String.prototype.repeat.call(null, 1)', TypeError); +assertThrows('String.prototype.repeat.call(undefined, 1)', TypeError); +assertThrows('String.prototype.repeat.apply(null, [1])', TypeError); +assertThrows('String.prototype.repeat.apply(undefined, [1])', TypeError); + +// Test cases found in FF +assertEquals("abc", "abc".repeat(1)); +assertEquals("abcabc", "abc".repeat(2)); +assertEquals("abcabcabc", "abc".repeat(3)); +assertEquals("aaaaaaaaaa", "a".repeat(10)); +assertEquals("", "".repeat(5)); +assertEquals("", "abc".repeat(0)); +assertEquals("abcabc", "abc".repeat(2.0)); + +assertThrows('"a".repeat(-1)', RangeError); +assertThrows('"a".repeat(Number.POSITIVE_INFINITY)', RangeError); + +var myobj = { + toString: function() { + return "abc"; + }, + repeat : String.prototype.repeat +}; +assertEquals("abc", myobj.repeat(1)); +assertEquals("abcabc", myobj.repeat(2)); \ No newline at end of file diff --git a/test/mjsunit/harmony/string-startswith.js b/test/mjsunit/harmony/string-startswith.js new file mode 100644 index 0000000000..60c85d31b3 --- /dev/null +++ b/test/mjsunit/harmony/string-startswith.js @@ -0,0 +1,135 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-strings + +assertEquals(1, String.prototype.startsWith.length); + +var testString = "Hello World"; +assertTrue(testString.startsWith("")); +assertTrue(testString.startsWith("Hello")); +assertFalse(testString.startsWith("hello")); +assertFalse(testString.startsWith("Hello World!")); +assertFalse(testString.startsWith(null)); +assertFalse(testString.startsWith(undefined)); + +assertTrue("null".startsWith(null)); +assertTrue("undefined".startsWith(undefined)); + +var georgianUnicodeString = "\u10D0\u10D1\u10D2\u10D3\u10D4\u10D5\u10D6\u10D7"; +assertTrue(georgianUnicodeString.startsWith(georgianUnicodeString)); +assertTrue(georgianUnicodeString.startsWith("\u10D0\u10D1\u10D2")); +assertFalse(georgianUnicodeString.startsWith("\u10D8")); + +assertThrows("String.prototype.startsWith.call(null, 'test')", TypeError); +assertThrows("String.prototype.startsWith.call(null, null)", TypeError); +assertThrows("String.prototype.startsWith.call(undefined, undefined)", TypeError); + +assertThrows("String.prototype.startsWith.apply(null, ['test'])", TypeError); +assertThrows("String.prototype.startsWith.apply(null, [null])", TypeError); +assertThrows("String.prototype.startsWith.apply(undefined, [undefined])", TypeError); + +var TEST_INPUT = [{ + msg: "Empty string", val: "" +}, { + msg: "Number 1234.34", val: 1234.34 +}, { + msg: "Integer number 0", val: 0 +}, { + msg: "Negative number -1", val: -1 +}, { + msg: "Boolean true", val: true +}, { + msg: "Boolean false", val: false +}, { + msg: "Regular expression /\d+/", val: /\d+/ +}, { + msg: "Empty array []", val: [] +}, { + msg: "Empty object {}", val: {} +}, { + msg: "Array of size 3", val: new Array(3) +}]; + +function testNonStringValues() { + var i = 0; + var l = TEST_INPUT.length; + + for (; i < l; i++) { + var e = TEST_INPUT[i]; + var v = e.val; + var s = String(v); + assertTrue(s.startsWith(v), e.msg); + assertTrue(String.prototype.startsWith.call(v, v), e.msg); + assertTrue(String.prototype.startsWith.apply(v, [v]), e.msg); + } +} +testNonStringValues(); + +var CustomType = function(value) { + this.startsWith = String.prototype.startsWith; + this.toString = function() { + return String(value); + } +}; + +function testCutomType() { + var i = 0; + var l = TEST_INPUT.length; + + for (; i < l; i++) { + var e = TEST_INPUT[i]; + var v = e.val; + var o = new CustomType(v); + assertTrue(o.startsWith(v), e.msg); + } +} +testCutomType(); + +// Test cases found in FF +assertTrue("abc".startsWith("abc")); +assertTrue("abcd".startsWith("abc")); +assertTrue("abc".startsWith("a")); +assertFalse("abc".startsWith("abcd")); +assertFalse("abc".startsWith("bcde")); +assertFalse("abc".startsWith("b")); +assertTrue("abc".startsWith("abc", 0)); +assertFalse("abc".startsWith("bc", 0)); +assertTrue("abc".startsWith("bc", 1)); +assertFalse("abc".startsWith("c", 1)); +assertFalse("abc".startsWith("abc", 1)); +assertTrue("abc".startsWith("c", 2)); +assertFalse("abc".startsWith("d", 2)); +assertFalse("abc".startsWith("dcd", 2)); +assertFalse("abc".startsWith("a", 42)); +assertFalse("abc".startsWith("a", Infinity)); +assertTrue("abc".startsWith("a", NaN)); +assertFalse("abc".startsWith("b", NaN)); +assertTrue("abc".startsWith("ab", -43)); +assertTrue("abc".startsWith("ab", -Infinity)); +assertFalse("abc".startsWith("bc", -42)); +assertFalse("abc".startsWith("bc", -Infinity)); diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 0c1ad6843f..bdbc7163df 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -906,7 +906,8 @@ '../../src/arraybuffer.js', '../../src/typedarray.js', '../../src/generator.js', - '../../src/array-iterator.js' + '../../src/array-iterator.js', + '../../src/harmony-string.js' ], 'i18n_library_files': [ '../../src/extensions/i18n/header.js',