@@ -151,7 +151,9 @@ export const transformTryStatement: FunctionVisitor<ts.TryStatement> = (statemen
151151 return transformAsyncTry ( statement , context ) ;
152152 }
153153
154- const [ tryBlock , tryScope ] = transformScopeBlock ( context , statement . tryBlock , ScopeType . Try ) ;
154+ const tsTryBlock = statement . tryBlock ;
155+ const tsCatchClause = statement . catchClause ;
156+ const [ tryBlock ] = transformScopeBlock ( context , tsTryBlock , ScopeType . Try ) ;
155157
156158 if (
157159 ( context . options . luaTarget === LuaTarget . Lua50 || context . options . luaTarget === LuaTarget . Lua51 ) &&
@@ -163,104 +165,142 @@ export const transformTryStatement: FunctionVisitor<ts.TryStatement> = (statemen
163165 return tryBlock . statements ;
164166 }
165167
166- const tryResultIdentifier = lua . createIdentifier ( "____try" ) ;
167- const returnValueIdentifier = lua . createIdentifier ( "____returnValue" ) ;
168+ const trySuccessIdentifier = lua . createIdentifier ( "____trySuccess" , tsTryBlock ) ;
169+ const catchSuccessIdentifier = lua . createIdentifier ( "____catchSuccess" , tsCatchClause ) ;
170+ const hasReturnOrErrorIdentifier = lua . createIdentifier ( "____hasReturnOrError" , tsTryBlock ) ;
171+ const returnValueIdentifier = lua . createIdentifier ( "____returnValue" , tsTryBlock ) ;
168172
169173 const result : lua . Statement [ ] = [ ] ;
170174
171- const returnedIdentifier = lua . createIdentifier ( "____hasReturned" ) ;
172- let returnCondition : lua . Expression | undefined ;
173-
174- const pCall = lua . createIdentifier ( "pcall" ) ;
175- const tryCall = lua . createCallExpression ( pCall , [ lua . createFunctionExpression ( tryBlock ) ] ) ;
176-
177- if ( statement . catchClause && statement . catchClause . block . statements . length > 0 ) {
178- // try with catch
179- const [ catchFunction , catchScope ] = transformCatchClause ( context , statement . catchClause ) ;
180- const catchIdentifier = lua . createIdentifier ( "____catch" ) ;
181- result . push ( lua . createVariableDeclarationStatement ( catchIdentifier , catchFunction ) ) ;
182-
183- const hasReturn = tryScope . functionReturned ?? catchScope . functionReturned ;
184-
185- const tryReturnIdentifiers = [ tryResultIdentifier ] ; // ____try
186- if ( hasReturn || statement . catchClause . variableDeclaration ) {
187- tryReturnIdentifiers . push ( returnedIdentifier ) ; // ____returned
188- if ( hasReturn ) {
189- tryReturnIdentifiers . push ( returnValueIdentifier ) ; // ____returnValue
190- returnCondition = lua . cloneIdentifier ( returnedIdentifier ) ;
191- }
192- }
193- result . push ( lua . createVariableDeclarationStatement ( tryReturnIdentifiers , tryCall ) ) ;
175+ // pcall(function() ... end)
176+ const tryPCall = lua . createIdentifier ( "pcall" , tsTryBlock ) ;
177+ const tryCall = lua . createCallExpression ( tryPCall , [ lua . createFunctionExpression ( tryBlock ) ] , tsTryBlock ) ;
178+ // ____trySuccess, ____hasReturnOrError, ____returnValue
179+ const tryReturnIdentifiers = [ trySuccessIdentifier , hasReturnOrErrorIdentifier , returnValueIdentifier ] ;
180+ result . push ( lua . createVariableDeclarationStatement ( tryReturnIdentifiers , tryCall , tsTryBlock ) ) ;
181+
182+ const hasCatch = tsCatchClause && tsCatchClause . block . statements . length > 0 ;
183+ if ( hasCatch ) {
184+ // local ____catchSuccess
185+ result . push ( lua . createVariableDeclarationStatement ( catchSuccessIdentifier , undefined , tsCatchClause ) ) ;
186+
187+ const [ catchFunction ] = transformCatchClause ( context , tsCatchClause ) ;
188+
189+ const catchIdentifier = lua . createIdentifier ( "____catch" , tsCatchClause ) ;
190+ result . push ( lua . createVariableDeclarationStatement ( catchIdentifier , catchFunction , tsCatchClause ) ) ;
191+
192+ // pcall(____catch, ____hasReturnOrError)
193+ const catchPCall = lua . createIdentifier ( "pcall" , tsCatchClause ) ;
194+ const catchPcall = lua . createCallExpression (
195+ catchPCall ,
196+ [ catchIdentifier , lua . cloneIdentifier ( hasReturnOrErrorIdentifier , tsCatchClause ) ] ,
197+ tsTryBlock
198+ ) ;
194199
195- const catchCall = lua . createCallExpression (
196- catchIdentifier ,
197- statement . catchClause . variableDeclaration ? [ lua . cloneIdentifier ( returnedIdentifier ) ] : [ ]
200+ // ____catchSuccess, ____hasReturnOrError, ____returnValue
201+ // = pcall(____catch, ____hasReturnOrError)
202+ const catchAssign = lua . createAssignmentStatement (
203+ [
204+ lua . cloneIdentifier ( catchSuccessIdentifier , tsCatchClause ) ,
205+ lua . cloneIdentifier ( hasReturnOrErrorIdentifier , tsCatchClause ) ,
206+ lua . cloneIdentifier ( returnValueIdentifier , tsCatchClause ) ,
207+ ] ,
208+ catchPcall ,
209+ tsCatchClause
198210 ) ;
199- const catchCallStatement = hasReturn
200- ? lua . createAssignmentStatement (
201- [ lua . cloneIdentifier ( returnedIdentifier ) , lua . cloneIdentifier ( returnValueIdentifier ) ] ,
202- catchCall
203- )
204- : lua . createExpressionStatement ( catchCall ) ;
205-
206- const notTryCondition = lua . createUnaryExpression ( tryResultIdentifier , lua . SyntaxKind . NotOperator ) ;
207- result . push ( lua . createIfStatement ( notTryCondition , lua . createBlock ( [ catchCallStatement ] ) ) ) ;
208- } else if ( tryScope . functionReturned ) {
209- // try with return, but no catch
210- // returnedIdentifier = lua.createIdentifier("____returned");
211- const returnedVariables = [ tryResultIdentifier , returnedIdentifier , returnValueIdentifier ] ;
212- result . push ( lua . createVariableDeclarationStatement ( returnedVariables , tryCall ) ) ;
213-
214- // change return condition from '____returned' to '____try and ____returned'
215- returnCondition = lua . createBinaryExpression (
216- lua . cloneIdentifier ( tryResultIdentifier ) ,
217- returnedIdentifier ,
218- lua . SyntaxKind . AndOperator
211+
212+ // if not ____trySuccess then
213+ // ____catchSuccess, ____hasReturnOrError, ____returnValue
214+ // = pcall(____catch, ____hasReturnOrError)
215+ // end
216+ const notTryCondition = lua . createUnaryExpression ( trySuccessIdentifier , lua . SyntaxKind . NotOperator , tsTryBlock ) ;
217+ result . push (
218+ lua . createIfStatement ( notTryCondition , lua . createBlock ( [ catchAssign ] , tsCatchClause ) , undefined , tsTryBlock )
219219 ) ;
220- } else if ( statement . finallyBlock ) {
221- // try without catch, but with finally — need to capture error for re-throw
222- const errorIdentifier = lua . createIdentifier ( "____error" ) ;
223- result . push ( lua . createVariableDeclarationStatement ( [ tryResultIdentifier , errorIdentifier ] , tryCall ) ) ;
224- } else {
225- // try without return or catch
226- result . push ( lua . createExpressionStatement ( tryCall ) ) ;
227220 }
228221
229222 if ( statement . finallyBlock && statement . finallyBlock . statements . length > 0 ) {
230223 result . push ( ...context . transformStatements ( statement . finallyBlock ) ) ;
231224 }
232225
233- // Re-throw error if try had no catch but had a finally.
234- // On pcall failure the error is the second return value, which lands in
235- // ____hasReturned (when functionReturned) or ____error (otherwise).
236- if ( ! statement . catchClause && statement . finallyBlock ) {
237- const notTryCondition = lua . createUnaryExpression (
238- lua . cloneIdentifier ( tryResultIdentifier ) ,
239- lua . SyntaxKind . NotOperator
240- ) ;
241- const errorIdentifier = tryScope . functionReturned
242- ? lua . cloneIdentifier ( returnedIdentifier )
243- : lua . createIdentifier ( "____error" ) ;
244- const rethrow = lua . createExpressionStatement (
245- lua . createCallExpression ( lua . createIdentifier ( "error" ) , [ errorIdentifier , lua . createNumericLiteral ( 0 ) ] )
246- ) ;
247- result . push ( lua . createIfStatement ( notTryCondition , lua . createBlock ( [ rethrow ] ) ) ) ;
226+ // if ____hasReturnOrError then
227+ // return ____returnValue
228+ // end
229+ const tryReturnValues : lua . Expression [ ] = [ ] ;
230+ if ( isInMultiReturnFunction ( context , statement ) ) {
231+ tryReturnValues . push ( createUnpackCall ( context , lua . cloneIdentifier ( returnValueIdentifier , statement ) ) ) ;
232+ } else {
233+ tryReturnValues . push ( lua . cloneIdentifier ( returnValueIdentifier , statement ) ) ;
248234 }
249235
250- if ( returnCondition && returnedIdentifier ) {
251- const returnValues : lua . Expression [ ] = [ ] ;
252-
236+ const returnStatement = createReturnStatement ( context , tryReturnValues , statement ) ;
237+ const ifTryReturnStatement = lua . createIfStatement (
238+ lua . cloneIdentifier ( hasReturnOrErrorIdentifier , statement ) ,
239+ lua . createBlock ( [ returnStatement ] , statement ) ,
240+ undefined ,
241+ statement
242+ ) ;
243+ const trySuccessBlock = lua . createBlock ( [ ifTryReturnStatement ] , statement ) ;
244+
245+ // error(____hasReturnOrError, 0)
246+ const rethrow = lua . createExpressionStatement (
247+ lua . createCallExpression (
248+ lua . createIdentifier ( "error" ) ,
249+ [ lua . cloneIdentifier ( hasReturnOrErrorIdentifier , statement ) , lua . createNumericLiteral ( 0 ) ] ,
250+ statement . catchClause ?? statement . tryBlock
251+ ) ,
252+ statement . tryBlock
253+ ) ;
254+ const throwBlock = lua . createBlock ( [ rethrow ] , statement ) ;
255+
256+ let ifCatchSuccessStatement : lua . IfStatement | undefined ;
257+ if ( hasCatch ) {
258+ // if ____hasReturnOrError then
259+ // return ____returnValue
260+ // end
261+ const catchReturnValues : lua . Expression [ ] = [ ] ;
253262 if ( isInMultiReturnFunction ( context , statement ) ) {
254- returnValues . push ( createUnpackCall ( context , lua . cloneIdentifier ( returnValueIdentifier ) ) ) ;
263+ catchReturnValues . push ( createUnpackCall ( context , lua . cloneIdentifier ( returnValueIdentifier , statement ) ) ) ;
255264 } else {
256- returnValues . push ( lua . cloneIdentifier ( returnValueIdentifier ) ) ;
265+ catchReturnValues . push ( lua . cloneIdentifier ( returnValueIdentifier , statement ) ) ;
257266 }
258267
259- const returnStatement = createReturnStatement ( context , returnValues , statement ) ;
260- const ifReturnedStatement = lua . createIfStatement ( returnCondition , lua . createBlock ( [ returnStatement ] ) ) ;
261- result . push ( ifReturnedStatement ) ;
268+ const catchReturnStatement = createReturnStatement ( context , catchReturnValues , statement ) ;
269+ const ifCatchReturnStatement = lua . createIfStatement (
270+ lua . cloneIdentifier ( hasReturnOrErrorIdentifier , statement ) ,
271+ lua . createBlock ( [ catchReturnStatement ] , statement ) ,
272+ undefined ,
273+ statement
274+ ) ;
275+ const catchSuccessBlock = lua . createBlock ( [ ifCatchReturnStatement ] , statement ) ;
276+
277+ ifCatchSuccessStatement = lua . createIfStatement (
278+ lua . cloneIdentifier ( catchSuccessIdentifier , statement ) ,
279+ catchSuccessBlock ,
280+ throwBlock ,
281+ statement
282+ ) ;
262283 }
263284
285+ // if ____trySuccess then
286+ // if ____hasReturnOrError then
287+ // return ____returnValue
288+ // end
289+ // elseif ____catchSuccess then
290+ // if ____hasReturnOrError then
291+ // return ____returnValue
292+ // end
293+ // else
294+ // error(____hasReturnOrError, 0)
295+ // end
296+ const ifTrySuccessStatement = lua . createIfStatement (
297+ lua . cloneIdentifier ( trySuccessIdentifier , statement ) ,
298+ trySuccessBlock ,
299+ ifCatchSuccessStatement ?? ( tsCatchClause ? undefined : throwBlock ) ,
300+ statement
301+ ) ;
302+ result . push ( ifTrySuccessStatement ) ;
303+
264304 return lua . createDoStatement ( result , statement ) ;
265305} ;
266306
0 commit comments