From ef3782ae27753384bc39f7c888c5c7133b23faf7 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 10 Oct 2018 17:20:18 -0600 Subject: [PATCH 1/2] TupleReturn functions now correctly unpack return values or forward results from other TupleReturn call --- src/TSHelper.ts | 14 +++++++++++++ src/Transpiler.ts | 30 +++++++++++++--------------- test/translation/lua/tupleReturn.lua | 16 +++++++++++++++ test/translation/ts/tupleReturn.ts | 20 ++++++++++++++++++- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 210410d27..c4e7b2a33 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -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 { if (type.symbol) { const comments = type.symbol.getDocumentationComment(checker); diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 60d11f767..855de2be7 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -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); @@ -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 @@ -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})`; } diff --git a/test/translation/lua/tupleReturn.lua b/test/translation/lua/tupleReturn.lua index 8841a2f82..d485f97a7 100644 --- a/test/translation/lua/tupleReturn.lua +++ b/test/translation/lua/tupleReturn.lua @@ -1,3 +1,6 @@ +function tupleReturn() + return 0,"foobar" +end tupleReturn(); noTupleReturn(); local a,b=tupleReturn(); @@ -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 diff --git a/test/translation/ts/tupleReturn.ts b/test/translation/ts/tupleReturn.ts index 20a4e4da3..86fd32e97 100644 --- a/test/translation/ts/tupleReturn.ts +++ b/test/translation/ts/tupleReturn.ts @@ -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(); @@ -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(); +} From ceb13cbdda526afa4ca093144aeb9de1abec3eaf Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 13 Oct 2018 05:33:33 -0600 Subject: [PATCH 2/2] indentation fix --- src/TSHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TSHelper.ts b/src/TSHelper.ts index c4e7b2a33..1e608da09 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -84,7 +84,7 @@ 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)); + ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n)); if (declaration) { const decorators = this.getCustomDecorators( checker.getTypeAtLocation(declaration),