# HG changeset patch # User Sankha Narayan Guria # Date 1370879696 -19800 # Node ID 41683b7608bbd2c32dcebd34f925f9aea79ab493 # Parent 855a29c9dd686ddeb5fdb485a24ca975589d445e Bug 866847 - Implements map#forEach and Set#forEach; r=evilpie diff --git a/js/src/Makefile.in b/js/src/Makefile.in --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -644,16 +644,18 @@ selfhosting_srcs := \ $(srcdir)/builtin/Utilities.js \ $(srcdir)/builtin/Array.js \ $(srcdir)/builtin/Date.js \ $(srcdir)/builtin/Intl.js \ $(srcdir)/builtin/IntlData.js \ $(srcdir)/builtin/Number.js \ $(srcdir)/builtin/ParallelArray.js \ $(srcdir)/builtin/String.js \ + $(srcdir)/builtin/Set.js \ + $(srcdir)/builtin/Map.js \ $(NULL) selfhosted_out_h_deps := \ $(selfhosting_srcs) \ $(srcdir)/js.msg \ $(srcdir)/builtin/embedjs.py \ $(NULL) diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js new file mode 100644 --- /dev/null +++ b/js/src/builtin/Map.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ES6 20121122 draft 15.14.4.4. */ + +function MapForEach(callbackfn, thisArg = undefined) { + /* Step 1-2 */ + var M = this; + if(typeof M != "object") + ThrowError(JSMSG_BAD_TYPE, typeof M); + + /* Step 3-4 */ + try { + std_Map_has.call(M); + } catch (e) { + ThrowError(JSMSG_BAD_TYPE, typeof M); + } + + /* Step 5 */ + if (!IsCallable(callbackfn)) + ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 6-8 */ + for (var [k, v] of M) { + if (k) + callFunction(callbackfn, thisArg, v, k, M); + } +} diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1037,16 +1037,17 @@ const JSPropertySpec MapObject::properti const JSFunctionSpec MapObject::methods[] = { JS_FN("get", get, 1, 0), JS_FN("has", has, 1, 0), JS_FN("set", set, 2, 0), JS_FN("delete", delete_, 1, 0), JS_FN("keys", keys, 0, 0), JS_FN("values", values, 0, 0), JS_FN("clear", clear, 0, 0), + {"forEach", {NULL, NULL}, 1, 0, "MapForEach"}, JS_FS_END }; static JSObject * InitClass(JSContext *cx, Handle global, Class *clasp, JSProtoKey key, Native construct, const JSPropertySpec *properties, const JSFunctionSpec *methods) { Rooted proto(cx, global->createBlankPrototype(cx, clasp)); @@ -1615,16 +1616,17 @@ const JSPropertySpec SetObject::properti }; const JSFunctionSpec SetObject::methods[] = { JS_FN("has", has, 1, 0), JS_FN("add", add, 1, 0), JS_FN("delete", delete_, 1, 0), JS_FN("entries", entries, 0, 0), JS_FN("clear", clear, 0, 0), + {"forEach", {NULL, NULL}, 1, 0, "SetForEach"}, JS_FS_END }; JSObject * SetObject::initClass(JSContext *cx, JSObject *obj) { Rooted global(cx, &obj->asGlobal()); RootedObject proto(cx, diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js new file mode 100644 --- /dev/null +++ b/js/src/builtin/Set.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ES6 20121122 draft 15.16.4.6. */ + +function SetForEach(callbackfn, thisArg = undefined) { + /* Step 1-2 */ + var S = this; + if(typeof S != "object") + ThrowError(JSMSG_BAD_TYPE, typeof S); + + /* Step 3-4 */ + try { + std_Set_has.call(S); + } catch (e) { + ThrowError(JSMSG_BAD_TYPE, typeof M); + } + + /* Step 5-6 */ + if (!IsCallable(callbackfn)) + ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 7-8 */ + for (var e of S) { + if (e) + callFunction(callbackfn, thisArg, e, e, S); + } +} diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -61,17 +61,18 @@ var std_String_replace = String.prototyp var std_String_split = String.prototype.split; var std_String_startsWith = String.prototype.startsWith; var std_String_substring = String.prototype.substring; var std_String_toLowerCase = String.prototype.toLowerCase; var std_String_toUpperCase = String.prototype.toUpperCase; var std_WeakMap_get = WeakMap.prototype.get; var std_WeakMap_has = WeakMap.prototype.has; var std_WeakMap_set = WeakMap.prototype.set; - +var std_Map_has = Map.prototype.has; +var std_Set_has = Set.prototype.has; /********** List specification type **********/ /* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */ function List() {} { let ListProto = std_Object_create(null); diff --git a/js/src/jit-test/tests/collections/Map-forEach.js b/js/src/jit-test/tests/collections/Map-forEach.js new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/collections/Map-forEach.js @@ -0,0 +1,40 @@ +/* test Map.prototype.forEach */ + +load(libdir + 'asserts.js'); + +// testing success conditions of Map.prototype.forEach + +var testMap = new Map(); + +function callback(value, key, map) { + testMap.set(key, value); + assertEq(map.has(key), true); + assertEq(map.get(key), value); +} + +var initialMap = new Map([['a', 1], ['b', 2.3], ['c', undefined]]); +initialMap.forEach(callback); + +for (var [k, v] of testMap) { + assertEq(initialMap.has(k), true); + assertEq(initialMap.get(k), testMap.get(k)); +} + +var x = { abc: 'test'}; +function callback2(value, key, map) { + assertEq(x, this); +} +initialMap = new Map([['a', 1]]); +initialMap.forEach(callback2, x); + +// testing failure conditions of Map.prototype.forEach + +var s = new Set([1, 2, 3]); +assertThrowsInstanceOf(function() { + Map.prototype.forEach.call(s, callback); +}, TypeError, "Map.prototype.forEach should raise TypeError if not a Map"); + +var fn = 2; +assertThrowsInstanceOf(function() { + initialMap.forEach(fn); +}, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function"); diff --git a/js/src/jit-test/tests/collections/Set-forEach.js b/js/src/jit-test/tests/collections/Set-forEach.js new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/collections/Set-forEach.js @@ -0,0 +1,39 @@ +/* test Set.prototype.forEach */ + +load(libdir + 'asserts.js'); + +// testing success conditions of Set.prototype.forEach + +var testSet = new Set(); + +function callback(value, key, set) { + assertEq(value, key); + testSet.add(value); + assertEq(set.has(key), true); +} + +var initialSet = new Set(['a', 1, undefined]); +initialSet.forEach(callback); + +for (var v of testSet) { + assertEq(initialSet.has(v), true); +} + +var x = { abc: 'test'}; +function callback2(value, key, set) { + assertEq(x, this); +} +initialSet = new Set(['a']); +initialSet.forEach(callback2, x); + +// testing failure conditions of Map.prototype.forEach + +var m = new Map([['a', 1], ['b', 2.3], ['c', undefined]]); +assertThrowsInstanceOf(function() { + Set.prototype.forEach.call(m, callback); +}, TypeError, "Set.prototype.forEach should raise TypeError if not a Set"); + +var fn = 2; +assertThrowsInstanceOf(function() { + initialSet.forEach(fn); +}, TypeError, "Set.prototype.forEach should raise TypeError if callback is not a function");