Skip to content

Commit 4a68d9c

Browse files
committed
Optimize array push array
1 parent 0ae4d05 commit 4a68d9c

File tree

6 files changed

+58
-5
lines changed

6 files changed

+58
-5
lines changed

src/LuaAST.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export enum NodeFlags {
129129
None = 0,
130130
Inline = 1 << 0, // Keep function body on same line
131131
Declaration = 1 << 1, // Prefer declaration syntax `function foo()` over assignment syntax `foo = function()`
132+
TableUnpackCall = 1 << 2, // This is a table.unpack call
132133
}
133134

134135
export interface TextRange {
@@ -197,6 +198,11 @@ export function getOriginalPos(node: Node): TextRange {
197198
return { line: node.line, column: node.column };
198199
}
199200

201+
export function setNodeFlags<T extends Node>(node: T, flags: NodeFlags): T {
202+
node.flags = flags;
203+
return node;
204+
}
205+
200206
export interface File extends Node {
201207
kind: SyntaxKind.File;
202208
statements: Statement[];

src/LuaLib.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum LuaLibFeature {
1616
ArrayJoin = "ArrayJoin",
1717
ArrayMap = "ArrayMap",
1818
ArrayPush = "ArrayPush",
19+
ArrayPushArray = "ArrayPushArray",
1920
ArrayReduce = "ArrayReduce",
2021
ArrayReduceRight = "ArrayReduceRight",
2122
ArrayReverse = "ArrayReverse",

src/lualib/ArrayPushArray.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function __TS__ArrayPushArray<T>(this: T[], items: T[]): number {
2+
let len = this.length;
3+
for (const i of $range(1, items.length)) {
4+
len++;
5+
this[len - 1] = items[i - 1];
6+
}
7+
return len;
8+
}

src/transformation/builtins/array.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
66
import { PropertyCallExpression, transformArguments, transformCallAndArguments } from "../visitors/call";
77
import { isStringType, isNumberType, findFirstNonOuterParent } from "../utils/typescript";
88
import { moveToPrecedingTemp } from "../visitors/expression-list";
9+
import { isUnpackCall } from "../utils/lua-ast";
910

1011
export function transformArrayConstructorCall(
1112
context: TransformationContext,
@@ -76,8 +77,20 @@ export function transformArrayPrototypeCall(
7677
case "entries":
7778
return transformLuaLibFunction(context, LuaLibFeature.ArrayEntries, node, caller);
7879
case "push":
79-
if (node.arguments.length === 1 && !ts.isSpreadElement(node.arguments[0])) {
80-
return transformSingleElementArrayPush(context, node, caller, params[0]);
80+
if (node.arguments.length === 1) {
81+
const param = params[0];
82+
if (isUnpackCall(param)) {
83+
return transformLuaLibFunction(
84+
context,
85+
LuaLibFeature.ArrayPushArray,
86+
node,
87+
caller,
88+
(param as lua.CallExpression).params[0]
89+
);
90+
}
91+
if (!lua.isDotsLiteral(param)) {
92+
return transformSingleElementArrayPush(context, node, caller, param);
93+
}
8194
}
8295

8396
return transformLuaLibFunction(context, LuaLibFeature.ArrayPush, node, caller, ...params);

src/transformation/utils/lua-ast.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ export function createUnpackCall(
7676
? lua.createIdentifier("unpack")
7777
: lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("unpack"));
7878

79-
return lua.createCallExpression(unpack, [expression], tsOriginal);
79+
return lua.setNodeFlags(lua.createCallExpression(unpack, [expression], tsOriginal), lua.NodeFlags.TableUnpackCall);
80+
}
81+
82+
export function isUnpackCall(node: lua.Node): boolean {
83+
return lua.isCallExpression(node) && (node.flags & lua.NodeFlags.TableUnpackCall) !== 0;
8084
}
8185

8286
export function wrapInTable(...expressions: lua.Expression[]): lua.TableExpression {

test/unit/builtins/array.spec.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,33 @@ test.each([
472472
util.testExpression`${util.formatCode(array)}.indexOf(${util.formatCode(...args)})`.expectToMatchJsResult();
473473
});
474474

475-
test.each([{ args: "1" }, { args: "1, 2, 3" }, { args: "...[1, 2, 3]" }])("array.push (%p)", ({ args }) => {
475+
test.each([
476+
{ args: "1" },
477+
{ args: "1, 2, 3" },
478+
{ args: "...[1, 2, 3]" },
479+
{ args: "1, 2, ...[3, 4]" },
480+
{ args: "1, 2, ...[3, 4], 5" },
481+
])("array.push (%p)", ({ args }) => {
476482
util.testFunction`
477483
const array = [0];
478484
const value = array.push(${args});
479485
return { array, value };
480-
`.expectToMatchJsResult();
486+
`
487+
.debug()
488+
.expectToMatchJsResult();
489+
});
490+
491+
test("array.push(...)", () => {
492+
util.testFunction`
493+
const array = [0];
494+
function push(...args: any[]) {
495+
return array.push(...args);
496+
}
497+
const value = push(1, 2, 3);
498+
return { array, value };
499+
`
500+
.debug()
501+
.expectToMatchJsResult();
481502
});
482503

483504
test.each([

0 commit comments

Comments
 (0)