public override AstNode Visit(TryStatement node) { // Begin the node. builder.BeginNode(node); // Read the substatements. AstNode tryNode = node.GetTryStatement(); AstNode catchList = node.GetCatchList(); AstNode finalNode = node.GetFinallyStatement(); // Read the exception context. ExceptionContext context = node.GetContext(); // Create the finally block. BasicBlock finalBlock = null; if(finalNode != null) { finalBlock = CreateBasicBlock(); finalBlock.SetName("finally"); context.SetCleanup(finalBlock); } // Create the merge block. BasicBlock merge = finalBlock; if(merge == null) { merge = CreateBasicBlock(); merge.SetName("trymerge"); } // Store the old context. ExceptionContext oldContext = currentExceptionContext; currentExceptionContext = context; // Create the try block. BasicBlock tryBlock = CreateBasicBlock(); tryBlock.SetName("try"); builder.CreateJmp(tryBlock); builder.SetBlock(tryBlock); // Process the try statement. tryNode.Accept(this); // Jump to finally/merge. bool tryReturn = builder.IsLastTerminator(); if(!builder.IsLastTerminator()) builder.CreateJmp(merge); // Restore the context, visit the catch list. currentExceptionContext = oldContext; AstNode catchNode = catchList; while(catchNode != null) { // Visit it. catchNode.Accept(this); // Jump to finally/merge. if(!builder.IsLastTerminator()) builder.CreateJmp(merge); // TODO: Avoid "duplicated" catches. catchNode = catchNode.GetNext(); } // Visit the finally statement if(finalNode != null) { // Generate the finally block. builder.SetBlock(finalBlock); // Visit it. finalNode.Accept(this); // Jump/resume to merge. if(builder.IsLastTerminator()) Error(finalNode, "finally cannot return."); // Create propagate return block. BasicBlock propRet = CreateBasicBlock(); propRet.SetName("propRet"); builder.CreateJumpResume(propRet); builder.SetBlock(propRet); // Find the parent return. BasicBlock parentRetBlock = null; ExceptionContext parentContext = context.GetParentContext(); while(parentContext != null) { parentRetBlock = parentContext.GetCleanup(); if(parentRetBlock != null) break; parentContext = parentContext.GetParentContext(); } // Couldn't find a parent cleanup, return. if(parentRetBlock == null) parentRetBlock = currentFunction.ReturnBlock; // If try returns and theres not catch, just return. if(tryReturn && catchNode == null) { builder.CreateJmp(parentRetBlock); AstNode next = node.GetNext(); if(next != null) Warning(next, "unreachable code detected."); node.SetNext(null); } else { // Merge with the other blocks. merge = CreateBasicBlock(); merge.SetName("trymerge"); // Return/finally or merge. builder.CreateLoadLocal(currentFunction.ReturningVar); builder.CreateBr(parentRetBlock, merge); } } // Remove unused code. if(merge.GetPredsCount() == 0) { if(node.GetNext() != null) Warning(node, "detected unreachable code at {0}", node.GetNext().GetPosition()); node.SetNext(null); merge.Destroy(); } else { // Continue without try. builder.SetBlock(merge); } return builder.EndNode(); }
public override AstNode Visit(TryStatement node) { // Visit the try clause. AstNode tryStatement = node.GetTryStatement(); tryStatement.Accept(this); // Visit the catch clause. VisitList(node.GetCatchList()); // Visit the finally clause. AstNode finallyStament = node.GetFinallyStatement(); if(finallyStament != null) finallyStament.Accept(this); return node; }
public override AstNode Visit(TryStatement node) { // Read the substatements. AstNode tryNode = node.GetTryStatement(); AstNode catchList = node.GetCatchList(); AstNode finalNode = node.GetFinallyStatement(); // Create the exception context. ExceptionContext context; if(currentExceptionContext != null) context = new ExceptionContext(currentExceptionContext); else context = new ExceptionContext(currentFunction); node.SetContext(context); // Store the old context and process the try statement. ExceptionContext oldContext = currentExceptionContext; currentExceptionContext = context; tryNode.Accept(this); // Restore the context, visit the catch list. currentExceptionContext = oldContext; AstNode catchNode = catchList; while(catchNode != null) { // Set the exception context. CatchStatement catchStmnt = (CatchStatement)catchNode; catchStmnt.SetContext(context); // Visit it. catchStmnt.Accept(this); // TODO: Avoid "duplicated" catches. catchNode = catchNode.GetNext(); } // Visit the finally statement if(finalNode != null) { // Set the exception context. FinallyStatement finalStmnt = (FinallyStatement)finalNode; finalStmnt.SetContext(context); // Visit it. finalStmnt.Accept(this); } return node; }