Bug 866847 - Implement map#forEach and Set#forEach. r=evilpie

This commit is contained in:
Sankha Narayan Guria 2013-07-19 08:19:44 +05:30
Родитель 63736e952d
Коммит 245df3eac1
7 изменённых файлов: 197 добавлений и 1 удалений

Просмотреть файл

@ -642,6 +642,8 @@ selfhosting_srcs := \
$(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 := \

36
js/src/builtin/Map.js Normal file
Просмотреть файл

@ -0,0 +1,36 @@
/* 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 (!IsObject(M))
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. */
var entries = std_Map_iterator.call(M);
while (true) {
try {
var entry = std_Map_iterator_next.call(entries);
} catch (err) {
if (err instanceof StopIteration)
break;
throw err;
}
callFunction(callbackfn, thisArg, entry[1], entry[0], M);
}
}

Просмотреть файл

@ -1036,6 +1036,7 @@ const JSFunctionSpec MapObject::methods[] = {
JS_FN("keys", keys, 0, 0),
JS_FN("values", values, 0, 0),
JS_FN("clear", clear, 0, 0),
{"forEach", {NULL, NULL}, 2, 0, "MapForEach"},
JS_FS_END
};
@ -1592,6 +1593,7 @@ const JSFunctionSpec SetObject::methods[] = {
JS_FN("delete", delete_, 1, 0),
JS_FN("entries", entries, 0, 0),
JS_FN("clear", clear, 0, 0),
{"forEach", {NULL, NULL}, 2, 0, "SetForEach"},
JS_FS_END
};

36
js/src/builtin/Set.js Normal file
Просмотреть файл

@ -0,0 +1,36 @@
/* 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 (!IsObject(S))
ThrowError(JSMSG_BAD_TYPE, typeof S);
/* Step 3-4. */
try {
std_Set_has.call(S);
} catch (e) {
ThrowError(JSMSG_BAD_TYPE, typeof S);
}
/* Step 5-6. */
if (!IsCallable(callbackfn))
ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
/* Step 7-8. */
var values = std_Set_iterator.call(S);
while (true) {
try {
var entry = std_Set_iterator_next.call(values);
} catch (err) {
if (err instanceof StopIteration)
break;
throw err;
}
callFunction(callbackfn, thisArg, entry, entry, S);
}
}

Просмотреть файл

@ -73,7 +73,12 @@ 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;
var std_Map_iterator = Map().iterator;
var std_Set_iterator = Set().iterator;
var std_Map_iterator_next = Object.getPrototypeOf(Map().iterator()).next;
var std_Set_iterator_next = Object.getPrototypeOf(Set().iterator()).next;
/********** List specification type **********/

Просмотреть файл

@ -0,0 +1,58 @@
/* 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], [false, undefined]]);
initialMap.forEach(callback);
// test that both the Maps are equal and are in same order
var iterator = initialMap.iterator();
var count = 0;
for (var [k, v] of testMap) {
assertEq(initialMap.has(k), true);
assertEq(initialMap.get(k), testMap.get(k));
assertEq(iterator.next()[1], testMap.get(k));
count++;
}
//check both the Maps we have are equal in size
assertEq(initialMap.size, testMap.size);
assertEq(initialMap.size, count);
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 used on a Map");
var fn = 2;
assertThrowsInstanceOf(function() {
initialMap.forEach(fn);
}, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function");
// testing that Map#forEach uses internal next() function and does not stop when
// StopIteration exception is thrown
var m = new Map([["one", 1]]);
Object.getPrototypeOf(m.iterator()).next = function () { throw "FAIL"; };
assertThrowsInstanceOf(function () {
m.forEach(function () { throw StopIteration; });
}, StopIteration, "Map.prototype.forEach should use intrinsic next method.");

Просмотреть файл

@ -0,0 +1,57 @@
/* 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);
// test that both the Sets are equal and are in same order
var iterator = initialSet.iterator();
var count = 0;
for (var v of testSet) {
assertEq(initialSet.has(v), true);
assertEq(iterator.next(), v);
count++;
}
//check both the Sets we have are equal in size
assertEq(initialSet.size, testSet.size);
assertEq(initialSet.size, count);
var x = { abc: 'test'};
function callback2(value, key, set) {
assertEq(x, this);
}
initialSet = new Set(['a']);
initialSet.forEach(callback2, x);
// testing failure conditions of Set.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 used on a Set");
var fn = 2;
assertThrowsInstanceOf(function() {
initialSet.forEach(fn);
}, TypeError, "Set.prototype.forEach should raise TypeError if callback is not a function");
// testing that Set#forEach uses internal next() function and does not stop when
// StopIteration exception is thrown
var s = new Set(["one", 1]);
Object.getPrototypeOf(s.iterator()).next = function () { throw "FAIL"; };
assertThrowsInstanceOf(function () {
s.forEach(function () { throw StopIteration; });
}, StopIteration, "Set.prototype.forEach should use intrinsic next method.");