Skip to content

Commit 07c836c

Browse files
authored
Stop block transpilation after encountering a return statement (#161)
* Stop block transpilation after encountering a return statement * Added workaround + test for returning in switch
1 parent 5afaa2d commit 07c836c

File tree

5 files changed

+131
-50
lines changed

5 files changed

+131
-50
lines changed

.codecov.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
comment: off
2+
13
coverage:
24
status:
3-
patch: false
4-
changes: false
5-
project: false
6-
7-
comment: false
5+
project:
6+
default:
7+
target: 95
8+
threshold: null
9+
base: auto
10+
changes: off
11+
patch: off

src/Transpiler.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,17 @@ export abstract class LuaTranspiler {
224224
// Transpile a block
225225
public transpileBlock(block: ts.Block): string {
226226
this.exportStack.push([]);
227-
let result = block.statements.map(statement => this.transpileNode(statement)).join("");
227+
228+
let result = "";
229+
for (const statement of block.statements) {
230+
result += this.transpileNode(statement);
231+
232+
// Don't transpile any dead code after a return
233+
if (ts.isReturnStatement(statement)) {
234+
break;
235+
}
236+
}
237+
228238
result += this.makeExports();
229239

230240
return result;
@@ -587,13 +597,14 @@ export abstract class LuaTranspiler {
587597
this.pushIndent();
588598

589599
this.transpilingSwitch++;
590-
clause.statements.forEach(statement => {
591-
result += this.transpileNode(statement);
592-
});
600+
result += this.transpileBlock(ts.createBlock(clause.statements));
593601
this.transpilingSwitch--;
594602

595603
let i = index + 1;
596-
if (i < clauses.length && !tsHelper.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement)) {
604+
if (i < clauses.length
605+
&& !tsHelper.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement)
606+
&& !tsHelper.containsStatement(clause.statements, ts.SyntaxKind.ReturnStatement)
607+
) {
597608
let nextClause = clauses[i];
598609
while (i < clauses.length
599610
&& ts.isCaseClause(nextClause)
@@ -605,8 +616,8 @@ export abstract class LuaTranspiler {
605616

606617
if (i !== index && nextClause) {
607618
if (ts.isCaseClause(nextClause)) {
608-
result += this.indent +
609-
`${jumpTableName}[${this.transpileExpression(nextClause.expression, true)}]()\n`;
619+
const nextValue = this.transpileExpression(nextClause.expression, true);
620+
result += this.indent + `return ${jumpTableName}[${nextValue}]()\n`;
610621
} else {
611622
result += this.indent + `${jumpTableName}["____default${this.genVarCounter}"]()\n`;
612623
}
@@ -619,11 +630,13 @@ export abstract class LuaTranspiler {
619630

620631
result += this.indent + `end\n`;
621632
});
622-
result += this.indent +
623-
`if ${jumpTableName}[${expression}] then ${jumpTableName}[${expression}]()\n`;
624-
result += this.indent +
625-
`elseif ${jumpTableName}["____default${this.genVarCounter}"] ` +
626-
`then ${jumpTableName}["____default${this.genVarCounter}"]() end\n`;
633+
result += this.indent + `if ${jumpTableName}[${expression}] then\n`
634+
+ this.indent + ` local ${jumpTableName}Return = ${jumpTableName}[${expression}]()\n`
635+
+ this.indent + ` if ${jumpTableName}Return ~= nil then return ${jumpTableName}Return end\n`;
636+
result += this.indent + `elseif ${jumpTableName}["____default${this.genVarCounter}"] then\n`
637+
+ this.indent + ` local ${jumpTableName}Return = ${jumpTableName}["____default${this.genVarCounter}"]()\n`
638+
+ this.indent + ` if ${jumpTableName}Return ~= nil then return ${jumpTableName}Return end\n`
639+
+ this.indent + `end\n`;
627640
result += this.indent +
628641
"--------Switch statement end--------\n";
629642

test/unit/conditionals.spec.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export class LuaConditionalsTests {
66
@TestCase(0, 0)
77
@TestCase(1, 1)
88
@Test("if")
9-
public if(inp: number, expected: number) {
9+
public if(inp: number, expected: number): void {
1010
// Transpile
1111
const lua = util.transpileString(
1212
`let input = ${inp}
@@ -26,7 +26,7 @@ export class LuaConditionalsTests {
2626
@TestCase(0, 0)
2727
@TestCase(1, 1)
2828
@Test("ifelse")
29-
public ifelse(inp: number, expected: number) {
29+
public ifelse(inp: number, expected: number): void {
3030
// Transpile
3131
const lua = util.transpileString(
3232
`let input = ${inp}
@@ -49,7 +49,7 @@ export class LuaConditionalsTests {
4949
@TestCase(2, 2)
5050
@TestCase(3, 3)
5151
@Test("ifelseif")
52-
public ifelseif(inp: number, expected: number) {
52+
public ifelseif(inp: number, expected: number): void {
5353
// Transpile
5454
const lua = util.transpileString(
5555
`let input = ${inp}
@@ -75,7 +75,7 @@ export class LuaConditionalsTests {
7575
@TestCase(2, 2)
7676
@TestCase(3, 3)
7777
@Test("ifelseifelse")
78-
public ifelseifelse(inp: number, expected: number) {
78+
public ifelseifelse(inp: number, expected: number): void {
7979
// Transpile
8080
const lua = util.transpileString(
8181
`let input = ${inp}
@@ -102,7 +102,7 @@ export class LuaConditionalsTests {
102102
@TestCase(2, 2)
103103
@TestCase(3, -1)
104104
@Test("switch")
105-
public switch(inp: number, expected: number) {
105+
public switch(inp: number, expected: number): void {
106106
// Transpile
107107
const lua = util.transpileString(
108108
`let result = -1;
@@ -133,7 +133,7 @@ export class LuaConditionalsTests {
133133
@TestCase(2, 2)
134134
@TestCase(3, -2)
135135
@Test("switchdefault")
136-
public switchdefault(inp: number, expected: number) {
136+
public switchdefault(inp: number, expected: number): void {
137137
// Transpile
138138
const lua = util.transpileString(
139139
`let result = -1;
@@ -170,7 +170,7 @@ export class LuaConditionalsTests {
170170
@TestCase(5, 15)
171171
@TestCase(7, -2)
172172
@Test("switchfallthrough")
173-
public switchfallthrough(inp: number, expected: number) {
173+
public switchfallthrough(inp: number, expected: number): void {
174174
/// Transpile
175175
const lua = util.transpileString(
176176
`let result = -1;
@@ -213,7 +213,7 @@ export class LuaConditionalsTests {
213213
@TestCase(2, 2)
214214
@TestCase(3, -2)
215215
@Test("nestedSwitch")
216-
public nestedSwitch(inp: number, expected: number) {
216+
public nestedSwitch(inp: number, expected: number): void {
217217
// Transpile
218218
const lua = util.transpileString(
219219
`let result = -1;
@@ -251,4 +251,20 @@ export class LuaConditionalsTests {
251251
// Assert
252252
Expect(result).toBe(expected);
253253
}
254+
255+
@Test("If dead code after return")
256+
public ifDeadCodeAfterReturn(): void {
257+
const result = util.transpileAndExecute(
258+
`if (true) { return 3; const b = 8; }`);
259+
260+
Expect(result).toBe(3);
261+
}
262+
263+
@Test("switch dead code after return")
264+
public whileDeadCodeAfterReturn(): void {
265+
const result = util.transpileAndExecute(
266+
`switch ("abc") { case "def": return 4; let abc = 4; case "abc": return 5; let def = 6; }`);
267+
268+
Expect(result).toBe(5);
269+
}
254270
}

test/unit/functions.spec.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as util from "../src/util";
66
export class FunctionTests {
77

88
@Test("Arrow Function Expression")
9-
public arrowFunctionExpression() {
9+
public arrowFunctionExpression(): void {
1010
// Transpile
1111
const lua = util.transpileString(`let add = (a, b) => a+b; return add(1,2);`);
1212

@@ -25,7 +25,7 @@ export class FunctionTests {
2525
@TestCase("b => a **= b", 100000)
2626
@TestCase("b => a %= b", 0)
2727
@Test("Arrow function assignment")
28-
public arrowFunctionAssignment(lambda: string, expected: number) {
28+
public arrowFunctionAssignment(lambda: string, expected: number): void {
2929
// Transpile
3030
const lua = util.transpileString(`let a = 10; let lambda = ${lambda};
3131
lambda(5); return a;`);
@@ -41,7 +41,7 @@ export class FunctionTests {
4141
@TestCase([5])
4242
@TestCase([1, 2])
4343
@Test("Arrow Default Values")
44-
public arrowFunctionDefaultValues(inp: number[]) {
44+
public arrowFunctionDefaultValues(inp: number[]): void {
4545
// Default value is 3 for v1
4646
const v1 = inp.length > 0 ? inp[0] : 3;
4747
// Default value is 4 for v2
@@ -61,7 +61,7 @@ export class FunctionTests {
6161
}
6262

6363
@Test("Function Expression")
64-
public functionExpression() {
64+
public functionExpression(): void {
6565
// Transpile
6666
const lua = util.transpileString(`let add = function(a, b) {return a+b}; return add(1,2);`);
6767

@@ -76,7 +76,7 @@ export class FunctionTests {
7676
@TestCase([5], 9)
7777
@TestCase([1, 2], 3)
7878
@Test("Arrow Default Values")
79-
public functionExpressionDefaultValues(inp: number[]) {
79+
public functionExpressionDefaultValues(inp: number[]): void {
8080
// Default value is 3 for v1
8181
const v1 = inp.length > 0 ? inp[0] : 3;
8282
// Default value is 4 for v2
@@ -96,7 +96,7 @@ export class FunctionTests {
9696
}
9797

9898
@Test("Class method call")
99-
public classMethod() {
99+
public classMethod(): void {
100100
const returnValue = 4;
101101
const source = `class TestClass {
102102
public classMethod(): number { return ${returnValue}; }
@@ -116,7 +116,7 @@ export class FunctionTests {
116116
}
117117

118118
@Test("Class dot method call void")
119-
public classDotMethod() {
119+
public classDotMethod(): void {
120120
const returnValue = 4;
121121
const source = `class TestClass {
122122
public dotMethod: () => number = () => ${returnValue};
@@ -136,7 +136,7 @@ export class FunctionTests {
136136
}
137137

138138
@Test("Class dot method call with parameter")
139-
public classDotMethod2() {
139+
public classDotMethod2(): void {
140140
const returnValue = 4;
141141
const source = `class TestClass {
142142
public dotMethod: (x: number) => number = x => 3 * x;
@@ -156,7 +156,7 @@ export class FunctionTests {
156156
}
157157

158158
@Test("Class static dot method")
159-
public classDotMethodStatic() {
159+
public classDotMethodStatic(): void {
160160
const returnValue = 4;
161161
const source = `class TestClass {
162162
public static dotMethod: () => number = () => ${returnValue};
@@ -175,7 +175,7 @@ export class FunctionTests {
175175
}
176176

177177
@Test("Class static dot method with parameter")
178-
public classDotMethodStaticWithParameter() {
178+
public classDotMethodStaticWithParameter(): void {
179179
const returnValue = 4;
180180
const source = `class TestClass {
181181
public static dotMethod: (x: number) => number = x => 3 * x;
@@ -194,7 +194,7 @@ export class FunctionTests {
194194
}
195195

196196
@Test("Invalid property access call transpilation")
197-
public invalidPropertyCall() {
197+
public invalidPropertyCall(): void {
198198
const transpiler = util.makeTestTranspiler();
199199

200200
const mockObject: any = {
@@ -204,4 +204,20 @@ export class FunctionTests {
204204
Expect(() => transpiler.transpilePropertyCall(mockObject as ts.CallExpression))
205205
.toThrowError(Error, "Tried to transpile a non-property call as property call.");
206206
}
207+
208+
@Test("Function dead code after return")
209+
public functionDeadCodeAfterReturn(): void {
210+
const result = util.transpileAndExecute(
211+
`function abc() { return 3; const a = 5; } return abc();`);
212+
213+
Expect(result).toBe(3);
214+
}
215+
216+
@Test("Method dead code after return")
217+
public methodDeadCodeAfterReturn(): void {
218+
const result = util.transpileAndExecute(
219+
`class def { public static abc() { return 3; const a = 5; } } return def.abc();`);
220+
221+
Expect(result).toBe(3);
222+
}
207223
}

0 commit comments

Comments
 (0)