From 15bf5194b9337ee760e037979286e9ede7d66af1 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 18 Oct 2018 16:52:40 -0600 Subject: [PATCH 1/2] refactored try block to allow rethrow --- src/Transpiler.ts | 40 +++++++++++++++++------ test/translation/lua/tryCatch.lua | 14 ++++---- test/translation/lua/tryCatchFinally.lua | 18 +++++++---- test/translation/lua/tryFinally.lua | 14 ++++---- test/unit/error.spec.ts | 41 ++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 29 deletions(-) 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..b9e942547 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -24,4 +24,45 @@ export class LuaErrorTests { ); }).toThrowError(TranspileError, "Invalid throw expression, only strings can be thrown."); } + + @TestCase(1, "ad") + @TestCase(2, "bcd") + @TestCase(3, "e") + @TestCase(4, "g") + @TestCase(5, "h") + @TestCase(6, "i") + @Test("re-throw") + public reThrow(count: number, expected: any): void { + const source = + `declare namespace string { export function match(s: string, p: string): string | null; } + let i = ${count}; + function foo(s: string) { if (--i <= 0) { throw s; } } + try { + try { + foo("a"); + try { + foo("b"); + } catch (e) { + foo(e + "c"); + } + } catch (e) { + foo(e + "d"); + } finally { + foo("e"); + } + try { + foo("f"); + } catch { + foo("g"); + } finally { + foo("h"); + } + } catch (e) { + return string.match(e, "[a-h]+$"); + } finally { + return "i"; + }`; + const result = util.transpileAndExecute(source); + Expect(result).toBe(expected); + } } From 4af136d984b18c4cb023aa3a8aaced355c75a2ce Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 19 Oct 2018 07:38:14 -0600 Subject: [PATCH 2/2] updated rethrow test with something less convoluted --- test/unit/error.spec.ts | 60 ++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index b9e942547..da0e59473 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -25,44 +25,54 @@ export class LuaErrorTests { }).toThrowError(TranspileError, "Invalid throw expression, only strings can be thrown."); } - @TestCase(1, "ad") - @TestCase(2, "bcd") - @TestCase(3, "e") - @TestCase(4, "g") - @TestCase(5, "h") - @TestCase(6, "i") + @TestCase(0, "A") + @TestCase(1, "B") + @TestCase(2, "C") @Test("re-throw") - public reThrow(count: number, expected: any): void { + public reThrow(i: number, expected: any): void { const source = - `declare namespace string { export function match(s: string, p: string): string | null; } - let i = ${count}; - function foo(s: string) { if (--i <= 0) { throw s; } } - try { + `const i = ${i}; + function foo() { try { - foo("a"); try { - foo("b"); + if (i === 0) { throw "z"; } } catch (e) { - foo(e + "c"); + throw "a"; + } finally { + if (i === 1) { throw "b"; } } } catch (e) { - foo(e + "d"); + throw (e as string).toUpperCase(); } finally { - foo("e"); + 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 { - foo("f"); + throw "y"; } catch { - foo("g"); - } finally { - foo("h"); + throw "z"; } } catch (e) { - return string.match(e, "[a-h]+$"); - } finally { - return "i"; - }`; + result = (e as string)[(e as string).length - 1]; + } + return result;`; const result = util.transpileAndExecute(source); - Expect(result).toBe(expected); + Expect(result).toBe("z"); } }