Commit 925d99a4 authored by oliver@apple.com's avatar oliver@apple.com

Bug 25159: Support Array.prototype.reduce

<https://bugs.webkit.org/show_bug.cgi?id=25159>

Reviewed by Gavin Barraclough

Implement Array.prototype.reduce


git-svn-id: svn://svn.chromium.org/blink/trunk@42563 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 4a615a04
2009-04-13 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Bug 25159: Support Array.prototype.reduce
<https://bugs.webkit.org/show_bug.cgi?id=25159>
Implement Array.prototype.reduce
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncReduce):
2009-04-15 Oliver Hunt <oliver@apple.com>
Reviewed by NOBODY (Build fix).
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
......@@ -57,6 +57,7 @@ static JSValuePtr arrayProtoFuncSome(ExecState*, JSObject*, JSValuePtr, const Ar
static JSValuePtr arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncFilter(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncMap(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncReduce(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValuePtr, const ArgList&);
}
......@@ -105,6 +106,7 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a
indexOf arrayProtoFuncIndexOf DontEnum|Function 1
lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1
filter arrayProtoFuncFilter DontEnum|Function 1
reduce arrayProtoFuncReduce DontEnum|Function 1
map arrayProtoFuncMap DontEnum|Function 1
@end
*/
......@@ -767,6 +769,76 @@ JSValuePtr arrayProtoFuncSome(ExecState* exec, JSObject*, JSValuePtr thisValue,
return result;
}
JSValuePtr arrayProtoFuncReduce(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
{
JSObject* thisObj = thisValue.toThisObject(exec);
JSValuePtr function = args.at(exec, 0);
CallData callData;
CallType callType = function.getCallData(callData);
if (callType == CallTypeNone)
return throwError(exec, TypeError);
unsigned i = 0;
JSValuePtr rv;
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
if (!length && args.size() == 1)
return throwError(exec, TypeError);
JSArray* array = 0;
if (isJSArray(&exec->globalData(), thisObj))
array = asArray(thisObj);
if (args.size() >= 2)
rv = args.at(exec, 1);
else if (array && array->canGetIndex(0)){
rv = array->getIndex(0);
i = 1;
} else {
for (i = 0; i < length; i++) {
rv = getProperty(exec, thisObj, i);
if (rv)
break;
}
if (!rv)
return throwError(exec, TypeError);
i++;
}
if (callType == CallTypeJS && array) {
CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot());
for (; i < length && !exec->hadException(); ++i) {
cachedCall.setThis(jsNull());
cachedCall.setArgument(0, rv);
JSValuePtr v;
if (LIKELY(array->canGetIndex(i)))
v = array->getIndex(i);
else
break; // length has been made unsafe while we enumerate fallback to slow path
cachedCall.setArgument(1, v);
cachedCall.setArgument(2, jsNumber(exec, i));
cachedCall.setArgument(3, array);
rv = cachedCall.call();
}
if (i == length) // only return if we reached the end of the array
return rv;
}
for (; i < length && !exec->hadException(); ++i) {
JSValuePtr prop = getProperty(exec, thisObj, i);
if (!prop)
continue;
ArgList eachArguments;
eachArguments.append(rv);
eachArguments.append(prop);
eachArguments.append(jsNumber(exec, i));
eachArguments.append(thisObj);
rv = call(exec, function, callType, callData, jsNull(), eachArguments);
}
return rv;
}
JSValuePtr arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
{
// JavaScript 1.5 Extension by Mozilla
......
2009-04-13 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Add tests for Array.prototype.reduce
* fast/js/array-reduce-expected.txt: Added.
* fast/js/array-reduce.html: Added.
* fast/js/resources/array-reduce.js: Added.
(toObject):
2009-04-15 Eric Carlson <eric.carlson@apple.com>
Fix incorrect expected result.
......
This test checks the behavior of the reduce() method on a number of objects.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS [0,1,2,3].reduce(function(a,b){ return a + b; }) is 6
PASS [1,2,3].reduce(function(a,b){ return a + b; }) is 6
PASS [0,1,2,3].reduce(function(a,b){ return a + b; }, 4) is 10
PASS [1,2,3].reduce(function(a,b){ return a + b; }, 4) is 10
PASS toObject([0,1,2,3]).reduce(function(a,b){ return a + b; }) is 6
PASS toObject([1,2,3]).reduce(function(a,b){ return a + b; }) is 6
PASS toObject([0,1,2,3]).reduce(function(a,b){ return a + b; }, 4) is 10
PASS toObject([1,2,3]).reduce(function(a,b){ return a + b; }, 4) is 10
PASS toUnorderedObject([0,1,2,3]).reduce(function(a,b){ return a + b; }) is 6
PASS toUnorderedObject([1,2,3]).reduce(function(a,b){ return a + b; }) is 6
PASS toUnorderedObject([0,1,2,3]).reduce(function(a,b){ return a + b; }, 4) is 10
PASS toUnorderedObject([1,2,3]).reduce(function(a,b){ return a + b; }, 4) is 10
PASS sparseArray.reduce(function(a,b){ return a + b; }, 0) is 10
PASS toObject(sparseArray).reduce(function(a,b){ return a + b; }, 0) is 10
PASS sparseArray.reduce(function(a,b){ callCount++; }); callCount is 0
PASS toObject(sparseArray).reduce(function(a,b){ callCount++; }); callCount is 0
PASS sparseArray.reduce(function(a,b){ callCount++; }, 0); callCount is 1
PASS toObject(sparseArray).reduce(function(a,b){ callCount++; }, 0); callCount is 1
PASS [0,1,2,3,4].reduce(function(a,b){ callCount++; }, 0); callCount is 5
PASS [0,1,2,3,4].reduce(function(a,b){ callCount++; }); callCount is 4
PASS [1, 2, 3, 4].reduce(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount is 2
PASS [1, 2, 3, 4].reduce(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount is 4
PASS toObject([1, 2, 3, 4]).reduce(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount is 4
PASS toObject([1, 2, 3, 4]).reduce(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount is 4
PASS [[0,1], [2,3], [4,5]].reduce(function(a,b) {return a.concat(b);}, []) is [0,1,2,3,4,5]
PASS toObject([[0,1], [2,3], [4,5]]).reduce(function(a,b) {return a.concat(b);}, []) is [0,1,2,3,4,5]
PASS toObject([0,1,2,3,4,5]).reduce(function(a,b,i) {return a.concat([i,b]);}, []) is [0,0,1,1,2,2,3,3,4,4,5,5]
PASS toUnorderedObject([[0,1], [2,3], [4,5]]).reduce(function(a,b) {return a.concat(b);}, []) is [0,1,2,3,4,5]
PASS toUnorderedObject([0,1,2,3,4,5]).reduce(function(a,b,i) {return a.concat([i,b]);}, []) is [0,0,1,1,2,2,3,3,4,4,5,5]
PASS [0,1,2,3,4,5].reduce(function(a,b,i) {return a.concat([i,b]);}, []) is [0,0,1,1,2,2,3,3,4,4,5,5]
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="resources/array-reduce.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
description(
"This test checks the behavior of the reduce() method on a number of objects."
);
function toObject(array) {
var o = {};
for (var i in array)
o[i] = array[i];
o.length = array.length;
o.reduce = Array.prototype.reduce;
return o;
}
function toUnorderedObject(array) {
var o = {};
var props = [];
for (var i in array)
props.push(i);
for (var i = props.length - 1; i >= 0; i--)
o[props[i]] = array[props[i]];
o.length = array.length;
o.reduce = Array.prototype.reduce;
return o;
}
shouldBe("[0,1,2,3].reduce(function(a,b){ return a + b; })", "6");
shouldBe("[1,2,3].reduce(function(a,b){ return a + b; })", "6");
shouldBe("[0,1,2,3].reduce(function(a,b){ return a + b; }, 4)", "10");
shouldBe("[1,2,3].reduce(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toObject([0,1,2,3]).reduce(function(a,b){ return a + b; })", "6");
shouldBe("toObject([1,2,3]).reduce(function(a,b){ return a + b; })", "6");
shouldBe("toObject([0,1,2,3]).reduce(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toObject([1,2,3]).reduce(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toUnorderedObject([0,1,2,3]).reduce(function(a,b){ return a + b; })", "6");
shouldBe("toUnorderedObject([1,2,3]).reduce(function(a,b){ return a + b; })", "6");
shouldBe("toUnorderedObject([0,1,2,3]).reduce(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toUnorderedObject([1,2,3]).reduce(function(a,b){ return a + b; }, 4)", "10");
sparseArray = [];
sparseArray[10] = 10;
shouldBe("sparseArray.reduce(function(a,b){ return a + b; }, 0)", "10");
shouldBe("toObject(sparseArray).reduce(function(a,b){ return a + b; }, 0)", "10");
var callCount = 0;
shouldBe("sparseArray.reduce(function(a,b){ callCount++; }); callCount", "0");
callCount = 0;
shouldBe("toObject(sparseArray).reduce(function(a,b){ callCount++; }); callCount", "0");
var callCount = 0;
shouldBe("sparseArray.reduce(function(a,b){ callCount++; }, 0); callCount", "1");
callCount = 0;
shouldBe("toObject(sparseArray).reduce(function(a,b){ callCount++; }, 0); callCount", "1");
callCount = 0;
shouldBe("[0,1,2,3,4].reduce(function(a,b){ callCount++; }, 0); callCount", "5");
callCount = 0;
shouldBe("[0,1,2,3,4].reduce(function(a,b){ callCount++; }); callCount", "4");
callCount = 0;
shouldBe("[1, 2, 3, 4].reduce(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount", "2");
callCount = 0;
shouldBe("[1, 2, 3, 4].reduce(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount", "4");
callCount = 0;
shouldBe("toObject([1, 2, 3, 4]).reduce(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount", "4");
callCount = 0;
shouldBe("toObject([1, 2, 3, 4]).reduce(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount", "4");
shouldBe("[[0,1], [2,3], [4,5]].reduce(function(a,b) {return a.concat(b);}, [])", "[0,1,2,3,4,5]");
shouldBe("toObject([[0,1], [2,3], [4,5]]).reduce(function(a,b) {return a.concat(b);}, [])", "[0,1,2,3,4,5]");
shouldBe("toObject([0,1,2,3,4,5]).reduce(function(a,b,i) {return a.concat([i,b]);}, [])", "[0,0,1,1,2,2,3,3,4,4,5,5]");
shouldBe("toUnorderedObject([[0,1], [2,3], [4,5]]).reduce(function(a,b) {return a.concat(b);}, [])", "[0,1,2,3,4,5]");
shouldBe("toUnorderedObject([0,1,2,3,4,5]).reduce(function(a,b,i) {return a.concat([i,b]);}, [])", "[0,0,1,1,2,2,3,3,4,4,5,5]");
shouldBe("[0,1,2,3,4,5].reduce(function(a,b,i) {return a.concat([i,b]);}, [])", "[0,0,1,1,2,2,3,3,4,4,5,5]");
successfullyParsed = true;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment