From 8971c76d85dcdc2f501fd57dc3f2dee3c4ce6099 Mon Sep 17 00:00:00 2001 From: Kirill Artemov Date: Wed, 8 Jan 2020 15:28:57 +0100 Subject: [PATCH 1/2] Switch case goto chain is now transpiled to an elseif chain instead of multiple ifs --- src/transformation/visitors/switch.ts | 17 +++++++- .../__snapshots__/conditionals.spec.ts.snap | 39 +++++++++++++++++++ test/unit/conditionals.spec.ts | 29 +++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 test/unit/__snapshots__/conditionals.spec.ts.snap diff --git a/src/transformation/visitors/switch.ts b/src/transformation/visitors/switch.ts index d198362ba..3073191ee 100644 --- a/src/transformation/visitors/switch.ts +++ b/src/transformation/visitors/switch.ts @@ -19,6 +19,8 @@ export const transformSwitchStatement: FunctionVisitor = (st let statements: lua.Statement[] = []; const caseClauses = statement.caseBlock.clauses.filter(ts.isCaseClause); + const resultIfStatements: lua.IfStatement[] = []; + for (const [index, clause] of caseClauses.entries()) { // If the clause condition holds, go to the correct label const condition = lua.createBinaryExpression( @@ -29,7 +31,20 @@ export const transformSwitchStatement: FunctionVisitor = (st const goto = lua.createGotoStatement(`${switchName}_case_${index}`); const conditionalGoto = lua.createIfStatement(condition, lua.createBlock([goto])); - statements.push(conditionalGoto); + + resultIfStatements.push(conditionalGoto); + } + + if (resultIfStatements.length > 0) { + for (let index = 1; index < resultIfStatements.length; index++) { + const previousIf = resultIfStatements[index - 1]; + + previousIf.elseBlock = resultIfStatements[index]; + } + + const firstIf = resultIfStatements[0]; + + statements.push(firstIf); } const hasDefaultCase = statement.caseBlock.clauses.some(ts.isDefaultClause); diff --git a/test/unit/__snapshots__/conditionals.spec.ts.snap b/test/unit/__snapshots__/conditionals.spec.ts.snap new file mode 100644 index 000000000..f03f3853e --- /dev/null +++ b/test/unit/__snapshots__/conditionals.spec.ts.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`array 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local result = -1 + local ____switch3 = 2 + if ____switch3 == 0 then + goto ____switch3_case_0 + elseif ____switch3 == 1 then + goto ____switch3_case_1 + elseif ____switch3 == 2 then + goto ____switch3_case_2 + end + goto ____switch3_end + ::____switch3_case_0:: + do + do + goto ____switch3_end + end + end + ::____switch3_case_1:: + do + do + goto ____switch3_end + end + end + ::____switch3_case_2:: + do + do + result = 1 + goto ____switch3_end + end + end + ::____switch3_end:: + return result +end +return ____exports" +`; diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index 54534e9c8..51b8dcac1 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -184,7 +184,7 @@ test("variable in nested scope does not interfere with case scope", () => { `.expectToMatchJsResult(); }); -test.only("switch using variable re-declared in cases", () => { +test("switch using variable re-declared in cases", () => { util.testFunction` let foo: number = 0; switch (foo) { @@ -311,6 +311,33 @@ test.each([0, 1, 2, 3])("switchWithBracketsBreakInInternalLoop (%p)", inp => { `.expectToMatchJsResult(); }); +test("switch uses elseif", () => { + test("array", () => { + util.testFunction` + let result: number = -1; + + switch (2 as number) { + case 0: { + break; + } + + case 1: { + break; + } + + case 2: { + result = 1; + break; + } + } + + return result; + ` + .expectLuaToMatchSnapshot() + .expectToMatchJsResult(); + }); +}); + test("switch not allowed in 5.1", () => { util.testFunction` switch ("abc") {} From 0e171c5616ee02d1378c69993a6b00296a58314c Mon Sep 17 00:00:00 2001 From: Kirill Artemov Date: Thu, 9 Jan 2020 14:20:17 +0100 Subject: [PATCH 2/2] Switch case goto chain is now transpiled to an elseif chain instead of multiple ifs --- src/transformation/visitors/switch.ts | 22 +++++-------------- .../__snapshots__/conditionals.spec.ts.snap | 2 ++ test/unit/conditionals.spec.ts | 2 ++ 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/transformation/visitors/switch.ts b/src/transformation/visitors/switch.ts index 3073191ee..941d8182d 100644 --- a/src/transformation/visitors/switch.ts +++ b/src/transformation/visitors/switch.ts @@ -19,9 +19,9 @@ export const transformSwitchStatement: FunctionVisitor = (st let statements: lua.Statement[] = []; const caseClauses = statement.caseBlock.clauses.filter(ts.isCaseClause); - const resultIfStatements: lua.IfStatement[] = []; - for (const [index, clause] of caseClauses.entries()) { + // Starting from the back, concatenating ifs into one big if/elseif statement + const concatenatedIf = caseClauses.reduceRight((previousCondition, clause, index) => { // If the clause condition holds, go to the correct label const condition = lua.createBinaryExpression( switchVariable, @@ -30,21 +30,11 @@ export const transformSwitchStatement: FunctionVisitor = (st ); const goto = lua.createGotoStatement(`${switchName}_case_${index}`); - const conditionalGoto = lua.createIfStatement(condition, lua.createBlock([goto])); + return lua.createIfStatement(condition, lua.createBlock([goto]), previousCondition); + }, undefined as lua.IfStatement | undefined); - resultIfStatements.push(conditionalGoto); - } - - if (resultIfStatements.length > 0) { - for (let index = 1; index < resultIfStatements.length; index++) { - const previousIf = resultIfStatements[index - 1]; - - previousIf.elseBlock = resultIfStatements[index]; - } - - const firstIf = resultIfStatements[0]; - - statements.push(firstIf); + if (concatenatedIf) { + statements.push(concatenatedIf); } const hasDefaultCase = statement.caseBlock.clauses.some(ts.isDefaultClause); diff --git a/test/unit/__snapshots__/conditionals.spec.ts.snap b/test/unit/__snapshots__/conditionals.spec.ts.snap index f03f3853e..e1c59f48f 100644 --- a/test/unit/__snapshots__/conditionals.spec.ts.snap +++ b/test/unit/__snapshots__/conditionals.spec.ts.snap @@ -16,12 +16,14 @@ function ____exports.__main(self) ::____switch3_case_0:: do do + result = 200 goto ____switch3_end end end ::____switch3_case_1:: do do + result = 100 goto ____switch3_end end end diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index 51b8dcac1..a11fd0595 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -318,10 +318,12 @@ test("switch uses elseif", () => { switch (2 as number) { case 0: { + result = 200; break; } case 1: { + result = 100; break; }