Add @@iterator support for strings
authorwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 25 Jun 2014 07:43:14 +0000 (07:43 +0000)
committerwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 25 Jun 2014 07:43:14 +0000 (07:43 +0000)
R=rossberg@chromium.org
BUG=

Review URL: https://codereview.chromium.org/335423002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21994 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/bootstrapper.cc
src/string-iterator.js [new file with mode: 0644]
test/mjsunit/harmony/iteration-semantics.js
test/mjsunit/harmony/string-iterator.js [new file with mode: 0644]
tools/generate-runtime-tests.py
tools/gyp/v8.gyp

index 771b5b2..6b4a4f1 100644 (file)
@@ -2052,6 +2052,7 @@ bool Genesis::InstallExperimentalNatives() {
     INSTALL_EXPERIMENTAL_NATIVE(i, collections, "collection-iterator.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, generators, "generator.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, iteration, "array-iterator.js")
+    INSTALL_EXPERIMENTAL_NATIVE(i, iteration, "string-iterator.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, strings, "harmony-string.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, arrays, "harmony-array.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, maths, "harmony-math.js")
diff --git a/src/string-iterator.js b/src/string-iterator.js
new file mode 100644 (file)
index 0000000..728f484
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $String = global.String;
+
+
+var stringIteratorIteratedStringSymbol =
+    GLOBAL_PRIVATE("StringIterator#iteratedString");
+var stringIteratorNextIndexSymbol = GLOBAL_PRIVATE("StringIterator#next");
+
+
+function StringIterator() {}
+
+
+// 21.1.5.1 CreateStringIterator Abstract Operation
+function CreateStringIterator(string) {
+  var s = TO_STRING_INLINE(string);
+  var iterator = new StringIterator;
+  SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, s);
+  SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, 0);
+  return iterator;
+}
+
+
+// 21.1.5.2.2 %StringIteratorPrototype%[@@iterator]
+function StringIteratorIterator() {
+  return this;
+}
+
+
+// 21.1.5.2.1 %StringIteratorPrototype%.next( )
+function StringIteratorNext() {
+  var iterator = ToObject(this);
+
+  if (!HAS_PRIVATE(iterator, stringIteratorIteratedStringSymbol)) {
+    throw MakeTypeError('incompatible_method_receiver',
+                        ['String Iterator.prototype.next']);
+  }
+
+  var s = GET_PRIVATE(iterator, stringIteratorIteratedStringSymbol);
+  if (IS_UNDEFINED(s)) {
+    return CreateIteratorResultObject(UNDEFINED, true);
+  }
+
+  var position = GET_PRIVATE(iterator, stringIteratorNextIndexSymbol);
+  var length = TO_UINT32(s.length);
+
+  if (position >= length) {
+    SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, UNDEFINED);
+    return CreateIteratorResultObject(UNDEFINED, true);
+  }
+
+  var first = %_StringCharCodeAt(s, position);
+  var resultString = %_StringCharFromCode(first);
+  position++;
+
+  if (first >= 0xD800 && first <= 0xDBFF && position < length) {
+    var second = %_StringCharCodeAt(s, position);
+    if (second >= 0xDC00 && second <= 0xDFFF) {
+      resultString += %_StringCharFromCode(second);
+      position++;
+    }
+  }
+
+  SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, position);
+
+  return CreateIteratorResultObject(resultString, false);
+}
+
+
+function SetUpStringIterator() {
+  %CheckIsBootstrapping();
+
+  %FunctionSetPrototype(StringIterator, new $Object());
+  %FunctionSetInstanceClassName(StringIterator, 'String Iterator');
+
+  InstallFunctions(StringIterator.prototype, DONT_ENUM, $Array(
+    'next', StringIteratorNext
+  ));
+  %FunctionSetName(StringIteratorIterator, '[Symbol.iterator]');
+  %SetProperty(StringIterator.prototype, symbolIterator, StringIteratorIterator,
+      DONT_ENUM);
+}
+SetUpStringIterator();
+
+
+// 21.1.3.27 String.prototype [ @@iterator ]( )
+function StringPrototypeIterator() {
+  return CreateStringIterator(this);
+}
+
+
+function ExtendStringPrototypeWithIterator() {
+  %CheckIsBootstrapping();
+
+  %FunctionSetName(StringPrototypeIterator, '[Symbol.iterator]');
+  %SetProperty($String.prototype, symbolIterator, StringPrototypeIterator,
+      DONT_ENUM);
+}
+ExtendStringPrototypeWithIterator();
index 27033e1..803f12f 100644 (file)
@@ -219,7 +219,7 @@ assertEquals(0, fold(sum, 0, unreachable(undefined)));
 
 // Other non-iterators do cause an error.
 assertThrows('fold(sum, 0, unreachable({}))', TypeError);
-assertThrows('fold(sum, 0, unreachable("foo"))', TypeError);
+assertThrows('fold(sum, 0, unreachable(false))', TypeError);
 assertThrows('fold(sum, 0, unreachable(37))', TypeError);
 
 // "next" is looked up each time.
diff --git a/test/mjsunit/harmony/string-iterator.js b/test/mjsunit/harmony/string-iterator.js
new file mode 100644 (file)
index 0000000..3e37178
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-iteration
+
+
+function TestStringPrototypeIterator() {
+  assertTrue(String.prototype.hasOwnProperty(Symbol.iterator));
+  assertFalse("".hasOwnProperty(Symbol.iterator));
+  assertFalse("".propertyIsEnumerable(Symbol.iterator));
+}
+TestStringPrototypeIterator();
+
+
+function assertIteratorResult(value, done, result) {
+  assertEquals({value: value, done: done}, result);
+}
+
+
+function TestManualIteration() {
+  var string = "abc";
+  var iterator = string[Symbol.iterator]();
+  assertIteratorResult('a', false, iterator.next());
+  assertIteratorResult('b', false, iterator.next());
+  assertIteratorResult('c', false, iterator.next());
+  assertIteratorResult(void 0, true, iterator.next());
+  assertIteratorResult(void 0, true, iterator.next());
+}
+TestManualIteration();
+
+
+function TestSurrogatePairs() {
+  var lo = "\uD834";
+  var hi = "\uDF06";
+  var pair = lo + hi;
+  var string = "abc" + pair + "def" + lo + pair + hi + lo;
+  var iterator = string[Symbol.iterator]();
+  assertIteratorResult('a', false, iterator.next());
+  assertIteratorResult('b', false, iterator.next());
+  assertIteratorResult('c', false, iterator.next());
+  assertIteratorResult(pair, false, iterator.next());
+  assertIteratorResult('d', false, iterator.next());
+  assertIteratorResult('e', false, iterator.next());
+  assertIteratorResult('f', false, iterator.next());
+  assertIteratorResult(lo, false, iterator.next());
+  assertIteratorResult(pair, false, iterator.next());
+  assertIteratorResult(hi, false, iterator.next());
+  assertIteratorResult(lo, false, iterator.next());
+  assertIteratorResult(void 0, true, iterator.next());
+  assertIteratorResult(void 0, true, iterator.next());
+}
+TestSurrogatePairs();
+
+
+function TestStringIteratorPrototype() {
+  var iterator = ""[Symbol.iterator]();
+  var StringIteratorPrototype = iterator.__proto__;
+  assertFalse(StringIteratorPrototype.hasOwnProperty('constructor'));
+  assertEquals(StringIteratorPrototype.__proto__, Object.prototype);
+  assertArrayEquals(['next'],
+      Object.getOwnPropertyNames(StringIteratorPrototype));
+  assertEquals('[object String Iterator]', "" + iterator);
+}
+TestStringIteratorPrototype();
+
+
+function TestForOf() {
+  var lo = "\uD834";
+  var hi = "\uDF06";
+  var pair = lo + hi;
+  var string = "abc" + pair + "def" + lo + pair + hi + lo;
+  var expected = ['a', 'b', 'c', pair, 'd', 'e', 'f', lo, pair, hi, lo];
+
+  var i = 0;
+  for (var char of string) {
+    assertEquals(expected[i++], char);
+  }
+
+  assertEquals(expected.length, i);
+}
+TestForOf();
+
+
+function TestNonOwnSlots() {
+  var iterator = ""[Symbol.iterator]();
+  var object = {__proto__: iterator};
+
+  assertThrows(function() { object.next(); }, TypeError);
+}
+TestNonOwnSlots();
index e8d4c64..d15d0d4 100755 (executable)
@@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 358
 EXPECTED_FUZZABLE_COUNT = 326
 EXPECTED_CCTEST_COUNT = 6
 EXPECTED_UNKNOWN_COUNT = 4
-EXPECTED_BUILTINS_COUNT = 800
+EXPECTED_BUILTINS_COUNT = 807
 
 
 # Don't call these at all.
index c7d04c6..06990c7 100644 (file)
           '../../src/collection-iterator.js',
           '../../src/generator.js',
           '../../src/array-iterator.js',
+          '../../src/string-iterator.js',
           '../../src/harmony-string.js',
           '../../src/harmony-array.js',
           '../../src/harmony-math.js'