Skip to content

Commit 978d025

Browse files
authored
fixed return-forwarding of luaIterator functions (#395)
fixes #389
1 parent b51e826 commit 978d025

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed

src/LuaTransformer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,10 @@ export class LuaTransformer {
14951495
// If return expression is an array literal, leave out brackets.
14961496
return tstl.createReturnStatement(statement.expression.elements
14971497
.map(elem => this.transformExpression(elem)));
1498-
} else if (!tsHelper.isTupleReturnCall(statement.expression, this.checker)) {
1498+
} else if (
1499+
!tsHelper.isTupleReturnCall(statement.expression, this.checker)
1500+
&& !tsHelper.isInLuaIteratorFunction(statement, this.checker))
1501+
{
14991502
// If return expression is not another TupleReturn call, unpack it
15001503
const expression = this.createUnpackCall(
15011504
this.transformExpression(statement.expression),

src/TSHelper.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,20 @@ export class TSHelper {
177177
}
178178

179179
public static isInTupleReturnFunction(node: ts.Node, checker: ts.TypeChecker): boolean {
180-
const declaration = TSHelper.findFirstNodeAbove(
181-
node,
182-
(n): n is ts.Node => ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n)
183-
);
180+
const declaration = TSHelper.findFirstNodeAbove(node, ts.isFunctionLike);
181+
if (declaration) {
182+
const decorators = TSHelper.getCustomDecorators(checker.getTypeAtLocation(declaration), checker);
183+
return decorators.has(DecoratorKind.TupleReturn);
184+
} else {
185+
return false;
186+
}
187+
}
188+
189+
public static isInLuaIteratorFunction(node: ts.Node, checker: ts.TypeChecker): boolean {
190+
const declaration = TSHelper.findFirstNodeAbove(node, ts.isFunctionLike);
184191
if (declaration) {
185192
const decorators = TSHelper.getCustomDecorators(checker.getTypeAtLocation(declaration), checker);
186-
return decorators.has(DecoratorKind.TupleReturn)
187-
// Lua iterators are not 'true' tupleReturn functions as they actually return a function
188-
&& !decorators.has(DecoratorKind.LuaIterator);
193+
return decorators.has(DecoratorKind.LuaIterator);
189194
} else {
190195
return false;
191196
}

test/unit/loops.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,61 @@ export class LuaLoopTests
680680
+ "the TupleReturn decorator.");
681681
}
682682

683+
@Test("forof forwarded lua iterator")
684+
public forofForwardedLuaIterator(): void {
685+
const code =
686+
`const arr = ["a", "b", "c"];
687+
/** @luaIterator */
688+
function luaIter(): Iterable<string> {
689+
let i = 0;
690+
function iter() { return arr[i++]; }
691+
return iter as any;
692+
}
693+
/** @luaIterator */
694+
function forward(): Iterable<string> {
695+
return luaIter();
696+
}
697+
let result = "";
698+
for (let a of forward()) { result += a; }
699+
return result;`;
700+
const compilerOptions = {
701+
luaLibImport: LuaLibImportKind.Require,
702+
luaTarget: LuaTarget.Lua53,
703+
target: ts.ScriptTarget.ES2015,
704+
};
705+
const result = util.transpileAndExecute(code, compilerOptions);
706+
Expect(result).toBe("abc");
707+
}
708+
709+
@Test("forof forwarded lua iterator with tupleReturn")
710+
public forofForwardedLuaIteratorWithTupleReturn(): void {
711+
const code =
712+
`const arr = ["a", "b", "c"];
713+
/** @luaIterator */
714+
/** @tupleReturn */
715+
function luaIter(): Iterable<[string, string]> {
716+
let i = 0;
717+
/** @tupleReturn */
718+
function iter() { return arr[i] && [i.toString(), arr[i++]] || []; }
719+
return iter as any;
720+
}
721+
/** @luaIterator */
722+
/** @tupleReturn */
723+
function forward(): Iterable<[string, string]> {
724+
return luaIter();
725+
}
726+
let result = "";
727+
for (let [a, b] of forward()) { result += a + b; }
728+
return result;`;
729+
const compilerOptions = {
730+
luaLibImport: LuaLibImportKind.Require,
731+
luaTarget: LuaTarget.Lua53,
732+
target: ts.ScriptTarget.ES2015,
733+
};
734+
const result = util.transpileAndExecute(code, compilerOptions);
735+
Expect(result).toBe("0a1b2c");
736+
}
737+
683738
@TestCase("while (a < b) { i++; }")
684739
@TestCase("do { i++; } while (a < b)")
685740
@TestCase("for (let i = 0; i < 3; i++) {}")

0 commit comments

Comments
 (0)