X Tutup
Skip to content

Commit b849364

Browse files
DoctorGesterPerryvw
authored andcommitted
Fixed transpiling break in switches with block cases and nested breaks (#315)
* Fixed transpiling break in switches with block cases and nested breaks * Adjustments * Getting away from the test police * Done a whoopsy
1 parent e8b55ae commit b849364

File tree

4 files changed

+161
-34
lines changed

4 files changed

+161
-34
lines changed

src/TSHelper.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ export class TSHelper {
5454
return result;
5555
}
5656

57-
public static containsStatement(statements: ts.NodeArray<ts.Statement>, kind: ts.SyntaxKind): boolean {
58-
return statements.some(statement => statement.kind === kind);
59-
}
60-
6157
public static getExtendedType(node: ts.ClassLikeDeclarationBase, checker: ts.TypeChecker): ts.Type | undefined {
6258
if (node && node.heritageClauses) {
6359
for (const clause of node.heritageClauses) {

src/Transpiler.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ interface ExportInfo {
5757
dummy: boolean;
5858
}
5959

60+
export enum ScopeType {
61+
Function,
62+
Switch,
63+
Loop,
64+
}
65+
66+
interface SpecialScope {
67+
type: ScopeType;
68+
id: number;
69+
}
70+
6071
export abstract class LuaTranspiler {
6172
// Lua key words for this Lua target
6273
// https://www.lua.org/manual/5.0/manual.html#2.1
@@ -70,13 +81,12 @@ export abstract class LuaTranspiler {
7081
public checker: ts.TypeChecker;
7182
public options: CompilerOptions;
7283
public genVarCounter: number;
73-
public transpilingSwitch: number;
7484
public namespace: string[];
7585
public importCount: number;
7686
public isModule: boolean;
7787
public isStrict: boolean;
7888
public sourceFile: ts.SourceFile;
79-
public loopStack: number[];
89+
public scopeStack: SpecialScope[];
8090
public classStack: string[];
8191
public exportStack: ExportInfo[][];
8292

@@ -89,15 +99,14 @@ export abstract class LuaTranspiler {
8999
this.checker = checker;
90100
this.options = options;
91101
this.genVarCounter = 0;
92-
this.transpilingSwitch = 0;
93102
this.namespace = [];
94103
this.importCount = 0;
95104
this.sourceFile = sourceFile;
96105
this.isModule = tsHelper.isFileModule(sourceFile);
97106
this.isStrict = options.alwaysStrict
98107
|| (options.strict && options.alwaysStrict !== false)
99108
|| (this.isModule && options.target && options.target >= ts.ScriptTarget.ES2015);
100-
this.loopStack = [];
109+
this.scopeStack = [];
101110
this.classStack = [];
102111
this.exportStack = [];
103112
this.luaLibFeatureSet = new Set<LuaLibFeature>();
@@ -128,6 +137,19 @@ export abstract class LuaTranspiler {
128137
this.exportStack[this.exportStack.length - 1].push({name: nameIn, node: nodeIn, dummy: dummyIn});
129138
}
130139

140+
public peekSpecialScope(): SpecialScope {
141+
return this.scopeStack[this.scopeStack.length - 1];
142+
}
143+
144+
public pushSpecialScope(scopeType: ScopeType): void {
145+
this.scopeStack.push({ type: scopeType, id: this.genVarCounter });
146+
this.genVarCounter++;
147+
}
148+
149+
public popSpecialScope(): SpecialScope {
150+
return this.scopeStack.pop();
151+
}
152+
131153
public makeExport(name: string, node: ts.Node, dummy?: boolean): string {
132154
let result: string = "";
133155
if (node &&
@@ -327,7 +349,7 @@ export abstract class LuaTranspiler {
327349
case ts.SyntaxKind.SwitchStatement:
328350
return this.transpileSwitch(node as ts.SwitchStatement);
329351
case ts.SyntaxKind.BreakStatement:
330-
return this.transpileBreak();
352+
return this.transpileBreak(node as ts.BreakStatement);
331353
case ts.SyntaxKind.TryStatement:
332354
return this.transpileTry(node as ts.TryStatement);
333355
case ts.SyntaxKind.ThrowStatement:
@@ -459,12 +481,8 @@ export abstract class LuaTranspiler {
459481
return result;
460482
}
461483

462-
public transpileBreak(): string {
463-
if (this.transpilingSwitch > 0) {
464-
return "";
465-
} else {
466-
return this.indent + "break\n";
467-
}
484+
public transpileBreak(node: ts.BreakStatement): string {
485+
return this.indent + "break\n";
468486
}
469487

470488
public transpileContinue(node: ts.ContinueStatement): string {
@@ -506,8 +524,6 @@ export abstract class LuaTranspiler {
506524
| ts.ForOfStatement
507525
| ts.ForInStatement
508526
): string {
509-
this.loopStack.push(this.genVarCounter);
510-
this.genVarCounter++;
511527
let result = this.indent + "do\n";
512528
this.pushIndent();
513529
result += this.transpileStatement(node.statement);
@@ -1880,6 +1896,7 @@ export abstract class LuaTranspiler {
18801896
body: ts.Block,
18811897
spreadIdentifier: string = ""
18821898
): string {
1899+
this.pushSpecialScope(ScopeType.Function);
18831900
let result = "";
18841901

18851902
// Add default parameters
@@ -1892,6 +1909,7 @@ export abstract class LuaTranspiler {
18921909
}
18931910

18941911
result += this.transpileBlock(body);
1912+
this.popSpecialScope();
18951913

18961914
return result;
18971915
}

src/targets/Transpiler.52.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TSTLErrors } from "../Errors";
2-
import { TSHelper as tsHelper } from "../TSHelper";
2+
import { ScopeType } from "../Transpiler";
33
import { LuaTranspiler51 } from "./Transpiler.51";
44

55
import * as ts from "typescript";
@@ -13,20 +13,26 @@ export class LuaTranspiler52 extends LuaTranspiler51 {
1313
| ts.ForOfStatement
1414
| ts.ForInStatement
1515
): string {
16-
this.loopStack.push(this.genVarCounter);
17-
this.genVarCounter++;
18-
let result = this.indent + "do\n";
19-
this.pushIndent();
20-
result += this.transpileStatement(node.statement);
21-
this.popIndent();
22-
result += this.indent + "end\n";
23-
result += this.indent + `::__continue${this.loopStack.pop()}::\n`;
16+
this.pushSpecialScope(ScopeType.Loop);
17+
let result = super.transpileLoopBody(node);
18+
result += this.indent + `::__continue${this.popSpecialScope().id}::\n`;
2419
return result;
2520
}
2621

2722
/** @override */
2823
public transpileContinue(node: ts.ContinueStatement): string {
29-
return this.indent + `goto __continue${this.loopStack[this.loopStack.length - 1]}\n`;
24+
return this.indent + `goto __continue${this.peekSpecialScope().id}\n`;
25+
}
26+
27+
/** @override */
28+
public transpileBreak(node: ts.BreakStatement): string {
29+
const topScope = this.peekSpecialScope();
30+
31+
if (topScope.type === ScopeType.Switch) {
32+
return this.indent + `goto ____switch${topScope.id}_end\n`;
33+
} else {
34+
return super.transpileBreak(node);
35+
}
3036
}
3137

3238
/** @override */
@@ -67,7 +73,7 @@ export class LuaTranspiler52 extends LuaTranspiler51 {
6773
let result = this.indent + "-------Switch statement start-------\n";
6874

6975
const switchVarName = "____switch" + this.genVarCounter;
70-
this.genVarCounter++;
76+
this.pushSpecialScope(ScopeType.Switch);
7177

7278
result += this.indent + `local ${switchVarName} = ${expression}\n`;
7379

@@ -101,24 +107,18 @@ export class LuaTranspiler52 extends LuaTranspiler51 {
101107
result += "\n";
102108

103109
const transpileClauseBody = (clause: ts.CaseOrDefaultClause) => {
104-
this.transpilingSwitch++;
105110
result += this.indent + "do\n";
106111
this.pushIndent();
107112
result += this.transpileBlock(ts.createBlock(clause.statements));
108113
this.popIndent();
109114
result += this.indent + "end\n";
110-
this.transpilingSwitch--;
111115
};
112116

113117
clauses.forEach((clause, index) => {
114118
if (ts.isCaseClause(clause)) {
115119
result += this.indent + `::${switchVarName}_case_${index}::\n`;
116120

117121
transpileClauseBody(clause);
118-
119-
if (tsHelper.containsStatement(clause.statements, ts.SyntaxKind.BreakStatement)) {
120-
result += this.indent + `goto ${switchVarName}_end\n`;
121-
}
122122
} else if (ts.isDefaultClause(clause)) {
123123
result += this.indent + `::${switchVarName}_default::\n`;
124124

@@ -129,6 +129,8 @@ export class LuaTranspiler52 extends LuaTranspiler51 {
129129
result += this.indent + `::${switchVarName}_end::\n`;
130130
result += this.indent + "-------Switch statement end-------\n";
131131

132+
this.popSpecialScope();
133+
132134
return result;
133135
}
134136

test/unit/conditionals.spec.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,117 @@ export class LuaConditionalsTests {
313313
Expect(result).toBe(expected);
314314
}
315315

316+
@TestCase(0, 0)
317+
@TestCase(1, 1)
318+
@TestCase(2, 2)
319+
@TestCase(3, -1)
320+
@Test("switchWithBrackets")
321+
public switchWithBrackets(inp: number, expected: number): void {
322+
// Transpile
323+
const lua = util.transpileString(
324+
`let result = -1;
325+
326+
switch (${inp}) {
327+
case 0: {
328+
result = 0;
329+
break;
330+
}
331+
case 1: {
332+
result = 1;
333+
break;
334+
}
335+
case 2: {
336+
result = 2;
337+
break;
338+
}
339+
}
340+
return result;`
341+
);
342+
343+
// Execute
344+
const result = util.executeLua(lua);
345+
346+
// Assert
347+
Expect(result).toBe(expected);
348+
}
349+
350+
351+
@TestCase(0, 0)
352+
@TestCase(1, 1)
353+
@TestCase(2, 2)
354+
@TestCase(3, -1)
355+
@Test("switchWithBracketsBreakInConditional")
356+
public switchWithBracketsBreakInConditional(inp: number, expected: number): void {
357+
// Transpile
358+
const lua = util.transpileString(
359+
`let result = -1;
360+
361+
switch (${inp}) {
362+
case 0: {
363+
result = 0;
364+
break;
365+
}
366+
case 1: {
367+
result = 1;
368+
369+
if (result == 1) break;
370+
}
371+
case 2: {
372+
result = 2;
373+
break;
374+
}
375+
}
376+
return result;`
377+
);
378+
379+
// Execute
380+
const result = util.executeLua(lua);
381+
382+
// Assert
383+
Expect(result).toBe(expected);
384+
}
385+
386+
@TestCase(0, 4)
387+
@TestCase(1, 0)
388+
@TestCase(2, 2)
389+
@TestCase(3, -1)
390+
@Test("switchWithBracketsBreakInInternalLoop")
391+
public switchWithBracketsBreakInInternalLoop(inp: number, expected: number): void {
392+
// Transpile
393+
const lua = util.transpileString(
394+
`let result = -1;
395+
396+
switch (${inp}) {
397+
case 0: {
398+
result = 0;
399+
400+
for (let i = 0; i < 5; i++) {
401+
result++;
402+
403+
if (i >= 2) {
404+
break;
405+
}
406+
}
407+
}
408+
case 1: {
409+
result++;
410+
break;
411+
}
412+
case 2: {
413+
result = 2;
414+
break;
415+
}
416+
}
417+
return result;`
418+
);
419+
420+
// Execute
421+
const result = util.executeLua(lua);
422+
423+
// Assert
424+
Expect(result).toBe(expected);
425+
}
426+
316427
@Test("If dead code after return")
317428
public ifDeadCodeAfterReturn(): void {
318429
const result = util.transpileAndExecute(

0 commit comments

Comments
 (0)
X Tutup