ES7: Implement Array.prototype.includes
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Mar 2015 21:37:53 +0000 (21:37 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Mar 2015 21:37:53 +0000 (21:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142707

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Add support for the ES7 includes method on Arrays.
https://github.com/tc39/Array.prototype.includes

* builtins/Array.prototype.js:
(includes): Implementation in JS.
* runtime/ArrayPrototype.cpp: Add 'includes' to the lookup table.

LayoutTests:

* js/array-includes-expected.txt: Added.
* js/array-includes.html: Added.
* js/script-tests/array-includes.js: Added.
* js/script-tests/Object-getOwnPropertyNames.js: Add 'includes'.
* js/Object-getOwnPropertyNames-expected.txt: Add 'includes'.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181871 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/js/Object-getOwnPropertyNames-expected.txt
LayoutTests/js/array-includes-expected.txt [new file with mode: 0644]
LayoutTests/js/array-includes.html [new file with mode: 0644]
LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
LayoutTests/js/script-tests/array-includes.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/Array.prototype.js
Source/JavaScriptCore/runtime/ArrayPrototype.cpp

index ca25f3c..b8b251c 100644 (file)
@@ -1,3 +1,16 @@
+2015-03-23  Dean Jackson  <dino@apple.com>
+
+        ES7: Implement Array.prototype.includes
+        https://bugs.webkit.org/show_bug.cgi?id=142707
+
+        Reviewed by Geoffrey Garen.
+
+        * js/array-includes-expected.txt: Added.
+        * js/array-includes.html: Added.
+        * js/script-tests/array-includes.js: Added.
+        * js/script-tests/Object-getOwnPropertyNames.js: Add 'includes'.
+        * js/Object-getOwnPropertyNames-expected.txt: Add 'includes'.
+
 2015-03-23  Joseph Pecoraro  <pecoraro@apple.com>
 
         __defineGetter__/__defineSetter__ should throw exceptions
index ffc6930..b6285e1 100644 (file)
@@ -45,7 +45,7 @@ PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defi
 PASS getSortedOwnPropertyNames(Function) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']
 PASS getSortedOwnPropertyNames(Array) is ['from', 'isArray', 'length', 'name', 'of', 'prototype']
-PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
+PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
 PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
 PASS getSortedOwnPropertyNames(Boolean) is ['length', 'name', 'prototype']
diff --git a/LayoutTests/js/array-includes-expected.txt b/LayoutTests/js/array-includes-expected.txt
new file mode 100644 (file)
index 0000000..e56142e
--- /dev/null
@@ -0,0 +1,35 @@
+Tests for Array.prototype.includes
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS [].includes.length is 1
+PASS [1, 2, 3].includes(2) is true
+PASS [1, 2, 3].includes(4) is false
+PASS [].includes(1) is false
+PASS [1, 2, 3].includes(1, 2) is false
+PASS [1, 2, 3].includes(3, 3) is false
+PASS [1, 2, 3].includes(2, undefined) is true
+PASS [1, 2, 3].includes(2, null) is true
+PASS [1, 2, 3].includes(2, 1, 2) is true
+PASS [1, 2, 3].includes(2, Number) is true
+PASS [1, 2, 3].includes(2, Number(2)) is false
+PASS [1, 2, 3].includes(2, 'egg') is true
+PASS [1, 2, 3].includes(2, '3') is false
+PASS [1, 2, 3].includes(3, -1) is true
+PASS [1, 2, 3].includes(1, -2) is false
+PASS [1, 2, 3].includes(1, -3) is true
+PASS [1, 2, NaN, 4].includes(NaN) is true
+PASS ['egg', 'bacon', 'sausage'].includes('egg') is true
+PASS ['egg', 'bacon', 'sausage'].includes('spinach') is false
+Array with holes
+PASS a.includes('egg') is true
+PASS a.includes('sausage') is true
+PASS a.includes('hashbrown') is false
+PASS a.includes('toast') is false
+PASS Array.prototype.includes.call(undefined, 1) threw exception TypeError: Array.prototype.includes requires that |this| not be undefined.
+PASS Array.prototype.includes.call(null, 1) threw exception TypeError: Array.prototype.includes requires that |this| not be null.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/array-includes.html b/LayoutTests/js/array-includes.html
new file mode 100644 (file)
index 0000000..e0eaf7e
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/array-includes.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index b424b05..b0a272f 100644 (file)
@@ -53,7 +53,7 @@ var expectedPropertyNamesSet = {
     "Function": "['length', 'name', 'prototype']",
     "Function.prototype": "['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']",
     "Array": "['from', 'isArray', 'length', 'name', 'of', 'prototype']",
-    "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
+    "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
     "String": "['fromCharCode', 'length', 'name', 'prototype']",
     "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
     "Boolean": "['length', 'name', 'prototype']",
diff --git a/LayoutTests/js/script-tests/array-includes.js b/LayoutTests/js/script-tests/array-includes.js
new file mode 100644 (file)
index 0000000..b742796
--- /dev/null
@@ -0,0 +1,45 @@
+description("Tests for Array.prototype.includes");
+
+shouldBe("[].includes.length", "1");
+
+shouldBeTrue("[1, 2, 3].includes(2)");
+shouldBeFalse("[1, 2, 3].includes(4)");
+shouldBeFalse("[].includes(1)");
+
+shouldBeFalse("[1, 2, 3].includes(1, 2)");
+shouldBeFalse("[1, 2, 3].includes(3, 3)");
+shouldBeTrue("[1, 2, 3].includes(2, undefined)");
+shouldBeTrue("[1, 2, 3].includes(2, null)");
+shouldBeTrue("[1, 2, 3].includes(2, 1, 2)");
+shouldBeTrue("[1, 2, 3].includes(2, Number)");
+shouldBeFalse("[1, 2, 3].includes(2, Number(2))");
+shouldBeTrue("[1, 2, 3].includes(2, 'egg')");
+shouldBeFalse("[1, 2, 3].includes(2, '3')");
+
+shouldBeTrue("[1, 2, 3].includes(3, -1)");
+shouldBeFalse("[1, 2, 3].includes(1, -2)");
+shouldBeTrue("[1, 2, 3].includes(1, -3)");
+
+shouldBeTrue("[1, 2, NaN, 4].includes(NaN)");
+
+shouldBeTrue("['egg', 'bacon', 'sausage'].includes('egg')");
+shouldBeFalse("['egg', 'bacon', 'sausage'].includes('spinach')");
+
+debug("Array with holes");
+
+var a = [];
+a[0] = 'egg';
+a[1] = 'bacon';
+a[5] = 'sausage';
+a[6] = 'spinach';
+a[-2] = 'toast';
+
+shouldBeTrue("a.includes('egg')");
+shouldBeTrue("a.includes('sausage')");
+shouldBeFalse("a.includes('hashbrown')");
+shouldBeFalse("a.includes('toast')");
+
+shouldThrow("Array.prototype.includes.call(undefined, 1)");
+shouldThrow("Array.prototype.includes.call(null, 1)");
+
+
index 3bc4d3f..e7c19f3 100644 (file)
@@ -1,3 +1,17 @@
+2015-03-23  Dean Jackson  <dino@apple.com>
+
+        ES7: Implement Array.prototype.includes
+        https://bugs.webkit.org/show_bug.cgi?id=142707
+
+        Reviewed by Geoffrey Garen.
+
+        Add support for the ES7 includes method on Arrays.
+        https://github.com/tc39/Array.prototype.includes
+
+        * builtins/Array.prototype.js:
+        (includes): Implementation in JS.
+        * runtime/ArrayPrototype.cpp: Add 'includes' to the lookup table.
+
 2015-03-23  Joseph Pecoraro  <pecoraro@apple.com>
 
         __defineGetter__/__defineSetter__ should throw exceptions
index 8566a18..23d8ea2 100644 (file)
@@ -236,3 +236,40 @@ function findIndex(callback /*, thisArg */) {
     }
     return -1;
 }
+
+function includes(searchElement /*, fromIndex*/) {
+    "use strict";
+    if (this === null)
+        throw new @TypeError("Array.prototype.includes requires that |this| not be null");
+
+    if (this === undefined)
+        throw new @TypeError("Array.prototype.includes requires that |this| not be undefined");
+
+    var array = @Object(this);
+    var length = array.length >>> 0;
+
+    if (length === 0)
+        return false;
+
+    var fromIndex = 0;
+    if (arguments.length > 1 && arguments[1] !== undefined)
+        fromIndex = arguments[1] | 0;
+
+    var index;
+    if (fromIndex >= 0)
+        index = fromIndex;
+    else
+        index = length + fromIndex;
+
+    if (index < 0)
+        index = 0;
+
+    var currentElement;
+    for (; index < length; ++index) {
+        currentElement = array[index];
+        // Use SameValueZero comparison, rather than just StrictEquals.
+        if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement))
+            return true;
+    }
+    return false;
+}
index 3fd034a..b2fd711 100644 (file)
@@ -117,6 +117,7 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, &arrayProto
   keys           arrayProtoFuncKeys           DontEnum|Function 0
   find           arrayProtoFuncFind           DontEnum|Function 1
   findIndex      arrayProtoFuncFindIndex      DontEnum|Function 1
+  includes       arrayProtoFuncIncludes       DontEnum|Function 1
 @end
 */