Skip to content

Commit 4109927

Browse files
committed
Merge remote-tracking branch 'upstream/master' into out-file
2 parents 3193953 + 3fa2065 commit 4109927

File tree

11 files changed

+196
-96
lines changed

11 files changed

+196
-96
lines changed

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: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,8 @@ export class LuaPrinter {
571571

572572
chunks.push("{");
573573

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

587578
chunks.push("}");
@@ -632,30 +623,33 @@ export class LuaPrinter {
632623
public printCallExpression(expression: tstl.CallExpression): SourceNode {
633624
const chunks = [];
634625

635-
const parameterChunks =
636-
expression.params !== undefined ? expression.params.map(e => this.printExpression(e)) : [];
626+
chunks.push(this.printExpression(expression.expression), "(");
637627

638-
chunks.push(this.printExpression(expression.expression), "(", ...this.joinChunks(", ", parameterChunks), ")");
628+
if (expression.params) {
629+
chunks.push(...this.printExpressionList(expression.params));
630+
}
631+
632+
chunks.push(")");
639633

640634
return this.createSourceNode(expression, chunks);
641635
}
642636

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

646-
const parameterChunks =
647-
expression.params !== undefined ? expression.params.map(e => this.printExpression(e)) : [];
640+
const prefix = this.printExpression(expression.prefixExpression);
648641

649642
const name = this.printIdentifier(expression.name);
650643

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

661655
public printIdentifier(expression: tstl.Identifier): SourceNode {
@@ -715,6 +709,25 @@ export class LuaPrinter {
715709
return result;
716710
}
717711

712+
protected printExpressionList(expressions: tstl.Expression[]): SourceChunk[] {
713+
const chunks: SourceChunk[] = [];
714+
715+
if (expressions.every(e => tsHelper.isSimpleExpression(e))) {
716+
chunks.push(...this.joinChunks(", ", expressions.map(e => this.printExpression(e))));
717+
} else {
718+
chunks.push("\n");
719+
this.pushIndent();
720+
expressions.forEach((p, i) => {
721+
const tail = i < expressions.length - 1 ? ",\n" : "\n";
722+
chunks.push(this.indent(), this.printExpression(p), tail);
723+
});
724+
this.popIndent();
725+
chunks.push(this.indent());
726+
}
727+
728+
return chunks;
729+
}
730+
718731
// The key difference between this and SourceNode.toStringWithSourceMap() is that SourceNodes with null line/column
719732
// will not generate 'empty' mappings in the source map that point to nothing in the original TS.
720733
private buildSourceMap(sourceFile: string, sourceRoot: string, rootSourceNode: SourceNode): SourceMapGenerator {

src/LuaTransformer.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,6 +2720,8 @@ export class LuaTransformer {
27202720
return this.transformArrayLiteral(expression as ts.ArrayLiteralExpression);
27212721
case ts.SyntaxKind.ObjectLiteralExpression:
27222722
return this.transformObjectLiteral(expression as ts.ObjectLiteralExpression);
2723+
case ts.SyntaxKind.OmittedExpression:
2724+
return this.transformOmittedExpression(expression as ts.OmittedExpression);
27232725
case ts.SyntaxKind.DeleteExpression:
27242726
return this.transformDeleteExpression(expression as ts.DeleteExpression);
27252727
case ts.SyntaxKind.FunctionExpression:
@@ -2946,7 +2948,7 @@ export class LuaTransformer {
29462948
// Destructuring assignment
29472949
const left =
29482950
expression.left.elements.length > 0
2949-
? expression.left.elements.map(e => this.transformExpression(e))
2951+
? expression.left.elements.map(e => this.transformArrayBindingExpression(e))
29502952
: [tstl.createAnonymousIdentifier(expression.left)];
29512953
let right: tstl.Expression[];
29522954
if (ts.isArrayLiteralExpression(expression.right)) {
@@ -3503,6 +3505,11 @@ export class LuaTransformer {
35033505
return tstl.createTableExpression(properties, expression);
35043506
}
35053507

3508+
public transformOmittedExpression(node: ts.OmittedExpression): ExpressionVisitResult {
3509+
const isWithinBindingAssignmentStatement = tsHelper.isWithinLiteralAssignmentStatement(node);
3510+
return isWithinBindingAssignmentStatement ? tstl.createAnonymousIdentifier() : tstl.createNilLiteral(node);
3511+
}
3512+
35063513
public transformDeleteExpression(expression: ts.DeleteExpression): ExpressionVisitResult {
35073514
const lhs = this.transformExpression(expression.expression) as tstl.AssignmentLeftHandSideExpression;
35083515
const assignment = tstl.createAssignmentStatement(lhs, tstl.createNilLiteral(), expression);
@@ -4614,14 +4621,18 @@ export class LuaTransformer {
46144621
}
46154622

46164623
public transformArrayBindingElement(name: ts.ArrayBindingElement): ExpressionVisitResult {
4624+
return this.transformArrayBindingExpression(name as ts.Expression);
4625+
}
4626+
4627+
public transformArrayBindingExpression(name: ts.Expression): ExpressionVisitResult {
46174628
if (ts.isOmittedExpression(name)) {
4618-
return tstl.createIdentifier("__", name);
4629+
return this.transformOmittedExpression(name);
46194630
} else if (ts.isIdentifier(name)) {
46204631
return this.transformIdentifier(name);
46214632
} else if (ts.isBindingElement(name) && ts.isIdentifier(name.name)) {
46224633
return this.transformIdentifier(name.name);
46234634
} else {
4624-
throw TSTLErrors.UnsupportedKind("array binding element", name.kind, name);
4635+
throw TSTLErrors.UnsupportedKind("array binding expression", name.kind, name);
46254636
}
46264637
}
46274638

src/TSHelper.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as ts from "typescript";
22
import { Decorator, DecoratorKind } from "./Decorator";
3+
import * as tstl from "./LuaAST";
34

45
export enum ContextType {
56
None,
@@ -793,6 +794,19 @@ export function isEnumMember(
793794
}
794795
}
795796

797+
export function isWithinLiteralAssignmentStatement(node: ts.Node): boolean {
798+
if (!node.parent) {
799+
return false;
800+
}
801+
if (ts.isArrayLiteralExpression(node.parent) || ts.isObjectLiteralExpression(node.parent)) {
802+
return isWithinLiteralAssignmentStatement(node.parent);
803+
} else if (ts.isBinaryExpression(node.parent) && node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
804+
return true;
805+
} else {
806+
return false;
807+
}
808+
}
809+
796810
export function moduleHasEmittedBody(
797811
statement: ts.ModuleDeclaration
798812
): statement is ts.ModuleDeclaration & { body: ts.ModuleBlock | ts.ModuleDeclaration } {
@@ -835,3 +849,39 @@ export function isArrayLengthAssignment(
835849

836850
return name === "length";
837851
}
852+
853+
// Returns true if expression contains no function calls
854+
export function isSimpleExpression(expression: tstl.Expression): boolean {
855+
switch (expression.kind) {
856+
case tstl.SyntaxKind.CallExpression:
857+
case tstl.SyntaxKind.MethodCallExpression:
858+
case tstl.SyntaxKind.FunctionExpression:
859+
return false;
860+
861+
case tstl.SyntaxKind.TableExpression:
862+
const tableExpression = expression as tstl.TableExpression;
863+
return !tableExpression.fields || tableExpression.fields.every(e => isSimpleExpression(e));
864+
865+
case tstl.SyntaxKind.TableFieldExpression:
866+
const fieldExpression = expression as tstl.TableFieldExpression;
867+
return (
868+
(!fieldExpression.key || isSimpleExpression(fieldExpression.key)) &&
869+
isSimpleExpression(fieldExpression.value)
870+
);
871+
872+
case tstl.SyntaxKind.TableIndexExpression:
873+
const indexExpression = expression as tstl.TableIndexExpression;
874+
return isSimpleExpression(indexExpression.table) && isSimpleExpression(indexExpression.index);
875+
876+
case tstl.SyntaxKind.UnaryExpression:
877+
return isSimpleExpression((expression as tstl.UnaryExpression).operand);
878+
879+
case tstl.SyntaxKind.BinaryExpression:
880+
const binaryExpression = expression as tstl.BinaryExpression;
881+
return isSimpleExpression(binaryExpression.left) && isSimpleExpression(binaryExpression.right);
882+
883+
case tstl.SyntaxKind.ParenthesizedExpression:
884+
return isSimpleExpression((expression as tstl.ParenthesizedExpression).innerExpression);
885+
}
886+
return true;
887+
}

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/array.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,22 @@ test.each([
191191
`;
192192
expect(() => util.transpileAndExecute(code)).toThrowError(`invalid array length: ${result}`);
193193
});
194+
195+
test.each([0, 1, 2])("Array with OmittedExpression", index => {
196+
const result = util.transpileAndExecute(
197+
`const myarray = [1, , 2];
198+
return myarray[${index}];`
199+
);
200+
201+
expect(result).toBe([1, , 2][index]);
202+
});
203+
204+
test("OmittedExpression in Array Binding Assignment Statement", () => {
205+
const result = util.transpileAndExecute(
206+
`let a, c;
207+
[a, , c] = [1, 2, 3];
208+
return a + c;`
209+
);
210+
211+
expect(result).toBe(4);
212+
});

0 commit comments

Comments
 (0)