From 5be32066807ac76b0391965ffa36c3648ed16b6f Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 19 Jan 2019 15:46:10 +0100 Subject: [PATCH 1/3] Switch transformer --- src/LuaTransformer.ts | 61 ++++++++++++++++++++++++++++++++-- test/unit/conditionals.spec.ts | 9 +++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 34155dd6a..1d68fea39 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1351,12 +1351,67 @@ export class LuaTransformer { ); } - public transformSwitchStatement(arg0: ts.SwitchStatement): StatementVisitResult { - throw new Error("Method not implemented."); + public transformSwitchStatement(statement: ts.SwitchStatement): StatementVisitResult { + if (this.options.luaTarget <= LuaTarget.Lua51) { + throw TSTLErrors.UnsupportedForTarget("Switch statements", this.options.luaTarget, statement); + } + + this.pushScope(ScopeType.Switch); + + // Give the switch a unique name to prevent nested switches from acting up. + const switchName = `____TS_switch${this.scopeStack.length}`; + + const expression = this.transformExpression(statement.expression); + const switchVariable = tstl.createIdentifier(switchName); + const switchVariableDeclaration = tstl.createVariableDeclarationStatement(switchVariable, expression); + + const statements: tstl.Statement[] = [switchVariableDeclaration]; + + const caseClauses = statement.caseBlock.clauses.filter(c => ts.isCaseClause(c)) as ts.CaseClause[]; + + for (let i = 0; i < caseClauses.length; i++) { + const clause = caseClauses[i]; + // If the clause condition holds, go to the correct label + const condition = tstl.createBinaryExpression( + switchVariable, + this.transformExpression(clause.expression), + tstl.SyntaxKind.EqualityOperator + ); + const goto = tstl.createGotoStatement(`${switchName}_case_${i}`); + const conditionalGoto = tstl.createIfStatement(condition, tstl.createBlock([goto])); + statements.push(conditionalGoto); + } + + const hasDefaultCase = statement.caseBlock.clauses.some(c => ts.isDefaultClause(c)); + if (hasDefaultCase) { + statements.push(tstl.createGotoStatement(`${switchName}_case_default`)); + } else { + statements.push(tstl.createGotoStatement(`${switchName}_end`)); + } + + for (let i = 0; i < statement.caseBlock.clauses.length; i++) { + const clause = statement.caseBlock.clauses[i]; + const label = ts.isCaseClause(clause) + ? tstl.createLabelStatement(`${switchName}_case_${i}`) + : tstl.createLabelStatement(`${switchName}_case_default`); + + const body = tstl.createDoStatement(this.transformStatements(clause.statements)); + statements.push(label, body); + } + + statements.push(tstl.createLabelStatement(`${switchName}_end`)); + + this.popScope(); + + return statements; } public transformBreakStatement(breakStatement: ts.BreakStatement): StatementVisitResult { - return tstl.createBreakStatement(undefined, breakStatement); + if (this.peekScope().type === ScopeType.Switch) { + return tstl.createGotoStatement(`____TS_switch${this.scopeStack.length}_end`); + } else { + return tstl.createBreakStatement(undefined, breakStatement); + } } public transformTryStatement(statement: ts.TryStatement): StatementVisitResult { diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index 2642cc7ae..6d330100b 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -222,10 +222,10 @@ export class LuaConditionalsTests { Expect(result).toBe(expected); } - @Test("switchLocalScope") @TestCase(0, 0) @TestCase(1, 2) @TestCase(2, 2) + @Test("switchLocalScope") public switchLocalScope(inp: number, expected: number): void { const result = util.transpileAndExecute( `let result: number = -1; @@ -253,13 +253,16 @@ export class LuaConditionalsTests { Expect(result).toBe(expected); } - @Test("switchReturn") @TestCase(0, 0) @TestCase(1, 1) @TestCase(2, 2) + @TestCase(3, -1) + @Test("switchReturn") public switchReturn(inp: number, expected: number): void { const result = util.transpileAndExecute( - `switch (${inp}) { + `const result: number = -1; + + switch (${inp}) { case 0: return 0; break; From 2d45b7f131013d2690601f9bd1eddaf4706f066a Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 19 Jan 2019 16:21:25 +0100 Subject: [PATCH 2/3] Changed incorrect version comparison to equality --- src/LuaTransformer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 1d68fea39..77e9d3f21 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1352,7 +1352,7 @@ export class LuaTransformer { } public transformSwitchStatement(statement: ts.SwitchStatement): StatementVisitResult { - if (this.options.luaTarget <= LuaTarget.Lua51) { + if (this.options.luaTarget == LuaTarget.Lua51) { throw TSTLErrors.UnsupportedForTarget("Switch statements", this.options.luaTarget, statement); } From d2410ad941b0f756750c4958346529a14ac2193b Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 19 Jan 2019 16:22:20 +0100 Subject: [PATCH 3/3] Added missing = --- src/LuaTransformer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 77e9d3f21..8a47e1f5b 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1352,7 +1352,7 @@ export class LuaTransformer { } public transformSwitchStatement(statement: ts.SwitchStatement): StatementVisitResult { - if (this.options.luaTarget == LuaTarget.Lua51) { + if (this.options.luaTarget === LuaTarget.Lua51) { throw TSTLErrors.UnsupportedForTarget("Switch statements", this.options.luaTarget, statement); }