diff --git a/src/Transpiler.ts b/src/Transpiler.ts index bfbd58a6e..107e4a203 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -661,24 +661,44 @@ export abstract class LuaTranspiler { } public transpileTry(node: ts.TryStatement): string { - let tryFunc = "function()\n"; + let result = this.indent + "do\n"; + this.pushIndent(); + + result += this.indent; + if (node.catchClause) { + result += "local __TS_try"; + if (node.catchClause.variableDeclaration) { + const variableName = this.transpileIdentifier( + node.catchClause.variableDeclaration.name as ts.Identifier); + result += ", " + variableName; + } + result += " = "; + } + + result += "pcall(function()\n"; this.pushIndent(); - tryFunc += this.transpileBlock(node.tryBlock); + result += this.transpileBlock(node.tryBlock); this.popIndent(); - tryFunc += "end"; - let catchFunc = "function(e)\nend"; - if (node.catchClause && node.catchClause.variableDeclaration) { - const variableName = this.transpileIdentifier(node.catchClause.variableDeclaration.name as ts.Identifier); - catchFunc = this.indent + `function(${variableName})\n`; + result += this.indent + "end);\n"; + + if (node.catchClause) { + result += this.indent + `if not __TS_try then\n`; this.pushIndent(); - catchFunc += this.transpileBlock(node.catchClause.block); + result += this.transpileBlock(node.catchClause.block); this.popIndent(); - catchFunc += "end"; + result += this.indent + "end\n"; } - let result = this.indent + `xpcall(${tryFunc},\n${catchFunc})\n`; + if (node.finallyBlock) { + result += this.indent + "do\n"; + this.pushIndent(); result += this.transpileBlock(node.finallyBlock); + this.popIndent(); + result += this.indent + "end\n"; } + + this.popIndent(); + result += this.indent + "end\n"; return result; } diff --git a/test/translation/lua/tryCatch.lua b/test/translation/lua/tryCatch.lua index 082aafc57..c5df1423b 100644 --- a/test/translation/lua/tryCatch.lua +++ b/test/translation/lua/tryCatch.lua @@ -1,6 +1,8 @@ -xpcall(function() - local a = 42; -end, -function(er) - local b = "fail"; -end) +do + local __TS_try, er = pcall(function() + local a = 42; + end); + if not __TS_try then + local b = "fail"; + end +end diff --git a/test/translation/lua/tryCatchFinally.lua b/test/translation/lua/tryCatchFinally.lua index c08fa2bc4..ac0269f8c 100644 --- a/test/translation/lua/tryCatchFinally.lua +++ b/test/translation/lua/tryCatchFinally.lua @@ -1,7 +1,11 @@ -xpcall(function() - local a = 42; -end, -function(er) - local b = "fail"; -end) -local c = "finally"; +do + local __TS_try, er = pcall(function() + local a = 42; + end); + if not __TS_try then + local b = "fail"; + end + do + local c = "finally"; + end +end diff --git a/test/translation/lua/tryFinally.lua b/test/translation/lua/tryFinally.lua index 4eb2f1c34..a117b8bb2 100644 --- a/test/translation/lua/tryFinally.lua +++ b/test/translation/lua/tryFinally.lua @@ -1,6 +1,8 @@ -xpcall(function() - local a = 42; -end, -function(e) -end) -local b = "finally"; +do + pcall(function() + local a = 42; + end); + do + local b = "finally"; + end +end diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index f3f737a09..da0e59473 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -24,4 +24,55 @@ export class LuaErrorTests { ); }).toThrowError(TranspileError, "Invalid throw expression, only strings can be thrown."); } + + @TestCase(0, "A") + @TestCase(1, "B") + @TestCase(2, "C") + @Test("re-throw") + public reThrow(i: number, expected: any): void { + const source = + `const i = ${i}; + function foo() { + try { + try { + if (i === 0) { throw "z"; } + } catch (e) { + throw "a"; + } finally { + if (i === 1) { throw "b"; } + } + } catch (e) { + throw (e as string).toUpperCase(); + } finally { + throw "C"; + } + } + let result = "x"; + try { + foo(); + } catch (e) { + result = (e as string)[(e as string).length - 1]; + } + return result;`; + const result = util.transpileAndExecute(source); + Expect(result).toBe(expected); + } + + @Test("re-throw (no catch var)") + public reThrowWithoutCatchVar(): void { + const source = + `let result = "x"; + try { + try { + throw "y"; + } catch { + throw "z"; + } + } catch (e) { + result = (e as string)[(e as string).length - 1]; + } + return result;`; + const result = util.transpileAndExecute(source); + Expect(result).toBe("z"); + } }