Skip to content

Commit 9d9ffee

Browse files
committed
updated call/table expression formatting
Arguments/fields will now only be split into multiple lines if one or more has evaluation side-effects that would be beneficial for a debugger to step on.
1 parent 3c41892 commit 9d9ffee

8 files changed

Lines changed: 150 additions & 93 deletions

File tree

src/LuaAST.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ export function createTableFieldExpression(
677677
tsOriginal?: ts.Node,
678678
parent?: Node
679679
): TableFieldExpression {
680-
const expression = createNode(SyntaxKind.TableExpression, tsOriginal, parent) as TableFieldExpression;
680+
const expression = createNode(SyntaxKind.TableFieldExpression, tsOriginal, parent) as TableFieldExpression;
681681
setParent(value, expression);
682682
expression.value = value;
683683
setParent(key, expression);

src/LuaPrinter.ts

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -573,17 +573,8 @@ export class LuaPrinter {
573573

574574
chunks.push("{");
575575

576-
if (expression.fields && expression.fields.length > 0) {
577-
if (expression.fields.length === 1) {
578-
// Inline tables with only one entry
579-
chunks.push(this.printTableFieldExpression(expression.fields[0]));
580-
} else {
581-
chunks.push("\n");
582-
this.pushIndent();
583-
expression.fields.forEach(f => chunks.push(this.indent(), this.printTableFieldExpression(f), ",\n"));
584-
this.popIndent();
585-
chunks.push(this.indent());
586-
}
576+
if (expression.fields) {
577+
chunks.push(...this.printExpressionList(expression.fields));
587578
}
588579

589580
chunks.push("}");
@@ -634,30 +625,33 @@ export class LuaPrinter {
634625
public printCallExpression(expression: tstl.CallExpression): SourceNode {
635626
const chunks = [];
636627

637-
const parameterChunks =
638-
expression.params !== undefined ? expression.params.map(e => this.printExpression(e)) : [];
628+
chunks.push(this.printExpression(expression.expression), "(");
629+
630+
if (expression.params) {
631+
chunks.push(...this.printExpressionList(expression.params));
632+
}
639633

640-
chunks.push(this.printExpression(expression.expression), "(", ...this.joinChunks(", ", parameterChunks), ")");
634+
chunks.push(")");
641635

642636
return this.createSourceNode(expression, chunks);
643637
}
644638

645639
public printMethodCallExpression(expression: tstl.MethodCallExpression): SourceNode {
646-
const prefix = this.printExpression(expression.prefixExpression);
640+
const chunks = [];
647641

648-
const parameterChunks =
649-
expression.params !== undefined ? expression.params.map(e => this.printExpression(e)) : [];
642+
const prefix = this.printExpression(expression.prefixExpression);
650643

651644
const name = this.printIdentifier(expression.name);
652645

653-
return this.createSourceNode(expression, [
654-
prefix,
655-
":",
656-
name,
657-
"(",
658-
...this.joinChunks(", ", parameterChunks),
659-
")",
660-
]);
646+
chunks.push(prefix, ":", name, "(");
647+
648+
if (expression.params) {
649+
chunks.push(...this.printExpressionList(expression.params));
650+
}
651+
652+
chunks.push(")");
653+
654+
return this.createSourceNode(expression, chunks);
661655
}
662656

663657
public printIdentifier(expression: tstl.Identifier): SourceNode {
@@ -713,6 +707,62 @@ export class LuaPrinter {
713707
return result;
714708
}
715709

710+
protected isSimpleExpression(expression: tstl.Expression): boolean {
711+
switch (expression.kind) {
712+
case tstl.SyntaxKind.CallExpression:
713+
case tstl.SyntaxKind.MethodCallExpression:
714+
case tstl.SyntaxKind.FunctionExpression:
715+
return false;
716+
717+
case tstl.SyntaxKind.TableExpression:
718+
const tableExpression = expression as tstl.TableExpression;
719+
return !tableExpression.fields || tableExpression.fields.every(e => this.isSimpleExpression(e));
720+
721+
case tstl.SyntaxKind.TableFieldExpression:
722+
const fieldExpression = expression as tstl.TableFieldExpression;
723+
return (
724+
(!fieldExpression.key || this.isSimpleExpression(fieldExpression.key)) &&
725+
this.isSimpleExpression(fieldExpression.value)
726+
);
727+
728+
case tstl.SyntaxKind.TableIndexExpression:
729+
const indexExpression = expression as tstl.TableIndexExpression;
730+
return this.isSimpleExpression(indexExpression.table) && this.isSimpleExpression(indexExpression.index);
731+
732+
case tstl.SyntaxKind.UnaryExpression:
733+
return this.isSimpleExpression((expression as tstl.UnaryExpression).operand);
734+
735+
case tstl.SyntaxKind.BinaryExpression:
736+
const binaryExpression = expression as tstl.BinaryExpression;
737+
return (
738+
this.isSimpleExpression(binaryExpression.left) && this.isSimpleExpression(binaryExpression.right)
739+
);
740+
741+
case tstl.SyntaxKind.ParenthesizedExpression:
742+
return this.isSimpleExpression((expression as tstl.ParenthesizedExpression).innerExpression);
743+
}
744+
return true;
745+
}
746+
747+
protected printExpressionList(expressions: tstl.Expression[]): SourceChunk[] {
748+
const chunks: SourceChunk[] = [];
749+
750+
if (expressions.every(e => this.isSimpleExpression(e))) {
751+
chunks.push(...this.joinChunks(", ", expressions.map(e => this.printExpression(e))));
752+
} else {
753+
chunks.push("\n");
754+
this.pushIndent();
755+
expressions.forEach((p, i) => {
756+
const tail = i < expressions.length - 1 ? ",\n" : "\n";
757+
chunks.push(this.indent(), this.printExpression(p), tail);
758+
});
759+
this.popIndent();
760+
chunks.push(this.indent());
761+
}
762+
763+
return chunks;
764+
}
765+
716766
// The key difference between this and SourceNode.toStringWithSourceMap() is that SourceNodes with null line/column
717767
// will not generate 'empty' mappings in the source map that point to nothing in the original TS.
718768
private buildSourceMap(sourceFile: string, sourceRoot: string, rootSourceNode: SourceNode): SourceMapGenerator {

test/translation/__snapshots__/transformation.spec.ts.snap

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -228,28 +228,12 @@ end"
228228
`;
229229

230230
exports[`Transformation (forIn) 1`] = `
231-
"for i in pairs({
232-
a = 1,
233-
b = 2,
234-
c = 3,
235-
d = 4,
236-
}) do
231+
"for i in pairs({a = 1, b = 2, c = 3, d = 4}) do
237232
end"
238233
`;
239234

240235
exports[`Transformation (forOf) 1`] = `
241-
"for ____, i in ipairs({
242-
1,
243-
2,
244-
3,
245-
4,
246-
5,
247-
6,
248-
7,
249-
8,
250-
9,
251-
10,
252-
}) do
236+
"for ____, i in ipairs({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) do
253237
end"
254238
`;
255239

@@ -577,9 +561,11 @@ f = function(____, x) return ({x = x}) end"
577561

578562
exports[`Transformation (tryCatch) 1`] = `
579563
"do
580-
local ____TS_try, er = pcall(function()
581-
local a = 42
582-
end)
564+
local ____TS_try, er = pcall(
565+
function()
566+
local a = 42
567+
end
568+
)
583569
if not ____TS_try then
584570
local b = \\"fail\\"
585571
end
@@ -588,9 +574,11 @@ end"
588574

589575
exports[`Transformation (tryCatchFinally) 1`] = `
590576
"do
591-
local ____TS_try, er = pcall(function()
592-
local a = 42
593-
end)
577+
local ____TS_try, er = pcall(
578+
function()
579+
local a = 42
580+
end
581+
)
594582
if not ____TS_try then
595583
local b = \\"fail\\"
596584
end
@@ -602,9 +590,11 @@ end"
602590

603591
exports[`Transformation (tryFinally) 1`] = `
604592
"do
605-
pcall(function()
606-
local a = 42
607-
end)
593+
pcall(
594+
function()
595+
local a = 42
596+
end
597+
)
608598
do
609599
local b = \\"finally\\"
610600
end
@@ -618,30 +608,47 @@ end
618608
tupleReturn(_G)
619609
noTupleReturn(_G)
620610
local a, b = tupleReturn(_G)
621-
local c, d = table.unpack(noTupleReturn(_G))
611+
local c, d = table.unpack(
612+
noTupleReturn(_G)
613+
)
622614
a, b = tupleReturn(_G)
623-
c, d = table.unpack(noTupleReturn(_G))
624-
local e = ({tupleReturn(_G)})
615+
c, d = table.unpack(
616+
noTupleReturn(_G)
617+
)
618+
local e = ({
619+
tupleReturn(_G)
620+
})
625621
local f = noTupleReturn(_G)
626-
e = ({tupleReturn(_G)})
622+
e = ({
623+
tupleReturn(_G)
624+
})
627625
f = noTupleReturn(_G)
628-
foo(_G, ({tupleReturn(_G)}))
629-
foo(_G, noTupleReturn(_G))
626+
foo(
627+
_G,
628+
({
629+
tupleReturn(_G)
630+
})
631+
)
632+
foo(
633+
_G,
634+
noTupleReturn(_G)
635+
)
630636
function tupleReturnFromVar(self)
631-
local r = {
632-
1,
633-
\\"baz\\",
634-
}
637+
local r = {1, \\"baz\\"}
635638
return table.unpack(r)
636639
end
637640
function tupleReturnForward(self)
638641
return tupleReturn(_G)
639642
end
640643
function tupleNoForward(self)
641-
return ({tupleReturn(_G)})
644+
return ({
645+
tupleReturn(_G)
646+
})
642647
end
643648
function tupleReturnUnpack(self)
644-
return table.unpack(tupleNoForward(_G))
649+
return table.unpack(
650+
tupleNoForward(_G)
651+
)
645652
end"
646653
`;
647654

test/unit/assignmentDestructuring.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ test("Assignment destructuring [5.1]", () => {
1010
luaTarget: tstl.LuaTarget.Lua51,
1111
luaLibImport: tstl.LuaLibImportKind.None,
1212
});
13-
expect(lua).toBe(`local a, b = unpack(myFunc())`);
13+
expect(lua).toBe(`local a, b = unpack(\n myFunc()\n)`);
1414
});
1515

1616
test("Assignment destructuring [5.2]", () => {
1717
const lua = util.transpileString(assignmentDestruturingTs, {
1818
luaTarget: tstl.LuaTarget.Lua52,
1919
luaLibImport: tstl.LuaLibImportKind.None,
2020
});
21-
expect(lua).toBe(`local a, b = table.unpack(myFunc())`);
21+
expect(lua).toBe(`local a, b = table.unpack(\n myFunc()\n)`);
2222
});
2323

2424
test("Assignment destructuring [JIT]", () => {
2525
const lua = util.transpileString(assignmentDestruturingTs, {
2626
luaTarget: tstl.LuaTarget.LuaJIT,
2727
luaLibImport: tstl.LuaLibImportKind.None,
2828
});
29-
expect(lua).toBe(`local a, b = unpack(myFunc())`);
29+
expect(lua).toBe(`local a, b = unpack(\n myFunc()\n)`);
3030
});
3131

3232
test.each([

test/unit/assignments/assignments.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import * as util from "../../util";
44
test.each([
55
{ inp: `"abc"`, out: `"abc"` },
66
{ inp: "3", out: "3" },
7-
{ inp: "[1,2,3]", out: "{\n 1,\n 2,\n 3,\n}" },
7+
{ inp: "[1,2,3]", out: "{1, 2, 3}" },
88
{ inp: "true", out: "true" },
99
{ inp: "false", out: "false" },
10-
{ inp: `{a:3,b:"4"}`, out: `{\n a = 3,\n b = "4",\n}` },
10+
{ inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` },
1111
])("Const assignment (%p)", ({ inp, out }) => {
1212
const lua = util.transpileString(`const myvar = ${inp}`);
1313
expect(lua).toBe(`local myvar = ${out}`);
@@ -16,10 +16,10 @@ test.each([
1616
test.each([
1717
{ inp: `"abc"`, out: `"abc"` },
1818
{ inp: "3", out: "3" },
19-
{ inp: "[1,2,3]", out: "{\n 1,\n 2,\n 3,\n}" },
19+
{ inp: "[1,2,3]", out: "{1, 2, 3}" },
2020
{ inp: "true", out: "true" },
2121
{ inp: "false", out: "false" },
22-
{ inp: `{a:3,b:"4"}`, out: `{\n a = 3,\n b = "4",\n}` },
22+
{ inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` },
2323
])("Let assignment (%p)", ({ inp, out }) => {
2424
const lua = util.transpileString(`let myvar = ${inp}`);
2525
expect(lua).toBe(`local myvar = ${out}`);
@@ -28,10 +28,10 @@ test.each([
2828
test.each([
2929
{ inp: `"abc"`, out: `"abc"` },
3030
{ inp: "3", out: "3" },
31-
{ inp: "[1,2,3]", out: "{\n 1,\n 2,\n 3,\n}" },
31+
{ inp: "[1,2,3]", out: "{1, 2, 3}" },
3232
{ inp: "true", out: "true" },
3333
{ inp: "false", out: "false" },
34-
{ inp: `{a:3,b:"4"}`, out: `{\n a = 3,\n b = "4",\n}` },
34+
{ inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` },
3535
])("Var assignment (%p)", ({ inp, out }) => {
3636
const lua = util.transpileString(`var myvar = ${inp}`);
3737
expect(lua).toBe(`myvar = ${out}`);
@@ -95,7 +95,7 @@ test("TupleReturn Single assignment", () => {
9595
`;
9696

9797
const lua = util.transpileString(code);
98-
expect(lua).toBe("local a = ({abc()})\na = ({abc()})");
98+
expect(lua).toBe("local a = ({\n abc()\n})\na = ({\n abc()\n})");
9999
});
100100

101101
test("TupleReturn interface assignment", () => {

0 commit comments

Comments
 (0)