Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/TSHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ export class TSHelper {
}
}

public static isInTupleReturnFunction(node: ts.Node, checker: ts.TypeChecker): boolean {
const declaration = this.findFirstNodeAbove(node, (n): n is ts.Node =>
ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n));
if (declaration) {
const decorators = this.getCustomDecorators(
checker.getTypeAtLocation(declaration),
checker
);
return decorators.has(DecoratorKind.TupleReturn);
} else {
return false;
}
}

public static getCustomDecorators(type: ts.Type, checker: ts.TypeChecker): Map<DecoratorKind, Decorator> {
if (type.symbol) {
const comments = type.symbol.getDocumentationComment(checker);
Expand Down
30 changes: 14 additions & 16 deletions src/Transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,20 +685,15 @@ export abstract class LuaTranspiler {

public transpileReturn(node: ts.ReturnStatement): string {
if (node.expression) {
// If parent function is a TupleReturn function
// and return expression is an array literal, leave out brackets.
const declaration = tsHelper.findFirstNodeAbove(node, (n): n is ts.Node =>
ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n));
let isTupleReturn = false;
if (declaration) {
const decorators = tsHelper.getCustomDecorators(
this.checker.getTypeAtLocation(declaration),
this.checker
);
isTupleReturn = decorators.has(DecoratorKind.TupleReturn);
}
if (isTupleReturn && ts.isArrayLiteralExpression(node.expression)) {
return "return " + node.expression.elements.map(elem => this.transpileExpression(elem)).join(",");
if (tsHelper.isInTupleReturnFunction(node, this.checker)) {
// Parent function is a TupleReturn function
if (ts.isArrayLiteralExpression(node.expression)) {
// If return expression is an array literal, leave out brackets.
return "return " + node.expression.elements.map(elem => this.transpileExpression(elem)).join(",");
} else if (!tsHelper.isTupleReturnCall(node.expression, this.checker)) {
// If return expression is not another TupleReturn call, unpack it
return `return ${this.transpileDestructingAssignmentValue(node.expression)}`;
}
}

return "return " + this.transpileExpression(node.expression);
Expand Down Expand Up @@ -1081,12 +1076,15 @@ export abstract class LuaTranspiler {
let callPath;

const isTupleReturn = tsHelper.isTupleReturnCall(node, this.checker);
const isTupleReturnForward = node.parent && ts.isReturnStatement(node.parent)
&& tsHelper.isInTupleReturnFunction(node, this.checker);
const isInDestructingAssignment = tsHelper.isInDestructingAssignment(node);
const returnValueIsUsed = node.parent && !ts.isExpressionStatement(node.parent);

if (ts.isPropertyAccessExpression(node.expression)) {
const result = this.transpilePropertyCall(node);
return isTupleReturn && !isInDestructingAssignment && returnValueIsUsed ? `({ ${result} })` : result;
return isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment && returnValueIsUsed
? `({ ${result} })` : result;
}

// Handle super calls properly
Expand All @@ -1098,7 +1096,7 @@ export abstract class LuaTranspiler {

callPath = this.transpileExpression(node.expression);
params = this.transpileArguments(node.arguments);
return isTupleReturn && !isInDestructingAssignment && returnValueIsUsed
return isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment && returnValueIsUsed
? `({ ${callPath}(${params}) })` : `${callPath}(${params})`;
}

Expand Down
16 changes: 16 additions & 0 deletions test/translation/lua/tupleReturn.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
function tupleReturn()
return 0,"foobar"
end
tupleReturn();
noTupleReturn();
local a,b=tupleReturn();
Expand All @@ -10,3 +13,16 @@ e = ({ tupleReturn() });
f = noTupleReturn();
foo(({ tupleReturn() }));
foo(noTupleReturn());
function tupleReturnFromVar()
local r = {1,"baz"};
return table.unpack(r)
end
function tupleReturnForward()
return tupleReturn()
end
function tupleNoForward()
return ({ tupleReturn() })
end
function tupleReturnUnpack()
return table.unpack(tupleNoForward())
end
20 changes: 19 additions & 1 deletion test/translation/ts/tupleReturn.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/** !TupleReturn */
declare function tupleReturn(): [number, string];
function tupleReturn(): [number, string] {
return [0, "foobar"];
}
declare function noTupleReturn(): [number, string];
declare function foo(a: [number, string]): void;
tupleReturn();
Expand All @@ -14,3 +16,19 @@ e = tupleReturn();
f = noTupleReturn();
foo(tupleReturn());
foo(noTupleReturn());
/** !TupleReturn */
function tupleReturnFromVar(): [number, string] {
const r: [number, string] = [1, "baz"];
return r;
}
/** !TupleReturn */
function tupleReturnForward(): [number, string] {
return tupleReturn();
}
function tupleNoForward(): [number, string] {
return tupleReturn();
}
/** !TupleReturn */
function tupleReturnUnpack(): [number, string] {
return tupleNoForward();
}