diff --git a/src/Transpiler.ts b/src/Transpiler.ts index f4882b363..17509b8ce 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -558,21 +558,32 @@ export abstract class LuaTranspiler { const variable = (node.initializer as ts.VariableDeclarationList).declarations[0]; // Transpile expression - const expression = this.transpileExpression(node.expression); + const iterable = this.transpileExpression(node.expression); // Use ipairs for array types, pairs otherwise const isArray = tsHelper.isArrayType(this.checker.getTypeAtLocation(node.expression), this.checker); - const pairs = isArray ? "ipairs" : "pairs"; - // Make header let result = ""; - if (ts.isIdentifier(variable.name)) { - result = this.indent + `for _, ${this.transpileIdentifier(variable.name)} in ${pairs}(${expression}) do\n`; - } else if (ts.isArrayBindingPattern(variable.name)) { - const valueVar = "__forOfValue" + this.genVarCounter; - result = this.indent + `for _, ${valueVar} in ${pairs}(${expression}) do\n`; - const declaration = ts.createVariableDeclaration(variable.name, undefined, ts.createIdentifier(valueVar)); - result += this.indent + this.transpileVariableDeclaration(declaration); + + if (!isArray && ts.isIdentifier(variable.name)) { + result = this.indent + `for _, ${this.transpileIdentifier(variable.name)} in pairs(${iterable}) do\n`; + } else { + let itemVariable: ts.Identifier; + if (isArray) { + // Cache the expression result + result += this.indent + `local __loopVariable${this.genVarCounter} = ${iterable};\n`; + result += this.indent + `for i${this.genVarCounter}=1, #__loopVariable${this.genVarCounter} do\n`; + itemVariable = ts.createIdentifier(`__loopVariable${this.genVarCounter}[i${this.genVarCounter}]`); + } else { + const variableName = `__forOfValue${this.genVarCounter}`; + itemVariable = ts.createIdentifier(variableName); + result += this.indent + `for _, ${variableName} in pairs(${iterable}) do\n`; + } + + const declaration = ts.createVariableDeclaration(variable.name, undefined, itemVariable); + this.pushIndent(); + result += this.indent + this.transpileVariableDeclaration(declaration) + ";\n"; + this.popIndent(); } // For body @@ -580,6 +591,8 @@ export abstract class LuaTranspiler { result += this.transpileLoopBody(node); this.popIndent(); + this.genVarCounter++; + return result + this.indent + "end\n"; } diff --git a/test/translation/lua/forOf.lua b/test/translation/lua/forOf.lua index 79c0a9fed..4a7ca76a9 100644 --- a/test/translation/lua/forOf.lua +++ b/test/translation/lua/forOf.lua @@ -1,4 +1,6 @@ -for _, i in ipairs({1,2,3,4,5,6,7,8,9,10}) do +local __loopVariable0 = {1,2,3,4,5,6,7,8,9,10}; +for i0=1, #__loopVariable0 do + local i = __loopVariable0[i0]; do end ::__continue0:: diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 007127d33..4d6d6e985 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -286,6 +286,26 @@ export class LuaLoopTests { Expect(result).toBe(JSON.stringify(expected)); } + @TestCase([[1, 2], [2, 3], [3, 4]], [3, 5, 7]) + @Test("forof destructing") + public forofDestructing(inp: number[][], expected: any): void { + // Transpile + const lua = util.transpileString( + `let objTest = ${JSON.stringify(inp)}; + let arrResultTest = []; + for (let [a,b] of objTest) { + arrResultTest.push(a + b) + } + return JSONStringify(arrResultTest);` + ); + + // Execute + const result = util.executeLua(lua); + + // Assert + Expect(result).toBe(JSON.stringify(expected)); + } + @TestCase([0, 1, 2, 3, 4], [0, 0, 2, 0, 4]) @Test("forof with continue") public forofWithContinue(inp: number[], expected: number[]): void {