X Tutup
Skip to content

Commit 28397f4

Browse files
authored
Added support for reduceRight (#732)
* Fixed out of spec behavior of array.reduce * Moved select declarations from ArrayReduce to lualib declaration files * Fixed issue in reduce with undefined returning callback * Changed reduce loop from while to for for performance reasons * Cleaned up code a little from PR feedback * testcase formatting * Added reduceRight * Added tests, fixed implementation * Changed test structure for reduce to describe * Removed duplicate test
1 parent b7e7296 commit 28397f4

File tree

4 files changed

+56
-22
lines changed

4 files changed

+56
-22
lines changed

src/LuaLib.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export enum LuaLibFeature {
1212
ArrayMap = "ArrayMap",
1313
ArrayPush = "ArrayPush",
1414
ArrayReduce = "ArrayReduce",
15+
ArrayReduceRight = "ArrayReduceRight",
1516
ArrayReverse = "ArrayReverse",
1617
ArrayShift = "ArrayShift",
1718
ArrayUnshift = "ArrayUnshift",

src/LuaTransformer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5130,6 +5130,8 @@ export class LuaTransformer {
51305130
return this.transformLuaLibFunction(LuaLibFeature.ArrayFilter, node, caller, ...params);
51315131
case "reduce":
51325132
return this.transformLuaLibFunction(LuaLibFeature.ArrayReduce, node, caller, ...params);
5133+
case "reduceRight":
5134+
return this.transformLuaLibFunction(LuaLibFeature.ArrayReduceRight, node, caller, ...params);
51335135
case "some":
51345136
return this.transformLuaLibFunction(LuaLibFeature.ArraySome, node, caller, ...params);
51355137
case "every":

src/lualib/ArrayReduceRight.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.reduce
2+
function __TS__ArrayReduceRight<T>(
3+
this: void,
4+
arr: T[],
5+
callbackFn: (accumulator: T, currentValue: T, index: number, array: T[]) => T,
6+
...initial: Vararg<T>
7+
): T {
8+
const len = arr.length;
9+
10+
let k = len - 1;
11+
let accumulator = undefined;
12+
13+
// Check if initial value is present in function call
14+
if (select("#", ...initial) !== 0) {
15+
accumulator = select(1, ...initial);
16+
} else if (len > 0) {
17+
accumulator = arr[k];
18+
k = k - 1;
19+
} else {
20+
// tslint:disable-next-line: no-string-throw
21+
throw "Reduce of empty array with no initial value";
22+
}
23+
24+
for (const i of forRange(k, 0, -1)) {
25+
accumulator = callbackFn(accumulator, arr[i], i, arr);
26+
}
27+
28+
return accumulator;
29+
}

test/unit/builtins/array.spec.ts

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -507,31 +507,33 @@ test.each([
507507
util.testExpressionTemplate`${array}.flatMap(${map})`.expectToEqual(expected);
508508
});
509509

510-
test.each<[[(total: number, currentItem: number, index: number, array: number[]) => number, number?]]>([
511-
[[(total, currentItem) => total + currentItem]],
512-
[[(total, currentItem) => total * currentItem]],
513-
[[(total, currentItem) => total + currentItem, 10]],
514-
[[(total, currentItem) => total * currentItem, 10]],
515-
[[(total, _, index, array) => total + array[index]]],
516-
[[(a, b) => a + b]],
517-
])("array.reduce (%p)", args => {
518-
util.testExpression`[1, 3, 5, 7].reduce(${util.formatCode(...args)})`.expectToMatchJsResult();
519-
});
510+
describe.each(["reduce", "reduceRight"])("array.%s", reduce => {
511+
test.each<[[(total: number, currentItem: number, index: number, array: number[]) => number, number?]]>([
512+
[[(total, currentItem) => total + currentItem]],
513+
[[(total, currentItem) => total * currentItem]],
514+
[[(total, currentItem) => total + currentItem, 10]],
515+
[[(total, currentItem) => total * currentItem, 10]],
516+
[[(total, _, index, array) => total + array[index]]],
517+
[[(a, b) => a + b]],
518+
])("usage (%p)", args => {
519+
util.testExpression`[1, 3, 5, 7].${reduce}(${util.formatCode(...args)})`.expectToMatchJsResult();
520+
});
520521

521-
test("array.reduce empty undefined initial", () => {
522-
util.testExpression`[].reduce(() => {}, undefined)`.expectToMatchJsResult();
523-
});
522+
test("empty undefined initial", () => {
523+
util.testExpression`[].${reduce}(() => {}, undefined)`.expectToMatchJsResult();
524+
});
524525

525-
test("array.reduce empty no initial", () => {
526-
util.testExpression`[].reduce(() => {})`.expectToMatchJsResult(true);
527-
});
526+
test("empty no initial", () => {
527+
util.testExpression`[].${reduce}(() => {})`.expectToMatchJsResult(true);
528+
});
528529

529-
test("array.reduce undefined returning callback", () => {
530-
util.testFunction`
531-
const calls: Array<{ a: void, b: string }> = [];
532-
["a", "b"].reduce<void>((a, b) => { calls.push({ a, b }) }, undefined);
533-
return calls;
534-
`.expectToMatchJsResult();
530+
test("undefined returning callback", () => {
531+
util.testFunction`
532+
const calls: Array<{ a: void, b: string }> = [];
533+
["a", "b"].${reduce}<void>((a, b) => { calls.push({ a, b }) }, undefined);
534+
return calls;
535+
`.expectToMatchJsResult();
536+
});
535537
});
536538

537539
const genericChecks = [

0 commit comments

Comments
 (0)
X Tutup