protected override ICode VisitTry(StmtTry s) { this.NewLine(); this.js.Append("try {"); this.indent++; this.Visit(s.Try); this.indent--; foreach (var @catch in s.Catches.EmptyIfNull()) { // TODO: Implement full exception processing (need some runtime type information to be able to do this) if (!(@catch.ExceptionVar.Type.IsObject() || @catch.ExceptionVar.Type.IsException())) { throw new NotImplementedException("Cannot yet handle 'catch' of type: " + @catch.ExceptionVar.Type.Name); } this.NewLine(); this.js.Append("} catch("); this.Visit(@catch.ExceptionVar); this.js.Append(") {"); this.indent++; this.Visit(@catch.Stmt); this.indent--; } if (s.Finally != null) { this.NewLine(); this.js.Append("} finally {"); this.indent++; this.Visit(s.Finally); this.indent--; } this.NewLine(); this.js.Append("}"); return(s); }
protected virtual ICode VisitTry(StmtTry s) { this.ThrowOnNoOverride(); var @try = this.Visit(s.Try); List <StmtTry.Catch> catches = null; if (s.Catches != null) { foreach (var @catch in s.Catches) { var stmt = (Stmt)this.Visit(@catch.Stmt); var exObj = (ExprVar)this.Visit(@catch.ExceptionVar); if ((stmt != @catch.Stmt || exObj != @catch.ExceptionVar) && catches == null) { catches = new List <StmtTry.Catch>(s.Catches.TakeWhile(x => x != @catch)); } if (catches != null) { catches.Add(new StmtTry.Catch(stmt, exObj)); } } } var @finally = this.Visit(s.Finally); if (@try != s.Try || catches != null || @finally != s.Finally) { return(new StmtTry(s.Ctx, (Stmt)@try, catches ?? s.Catches, (Stmt)@finally)); } else { return(s); } }
protected override ICode VisitTry(StmtTry s) { this.NewLine(); this.code.Append("try {"); this.indent++; this.Visit(s.Try); this.indent--; foreach (var @catch in s.Catches.EmptyIfNull()) { this.NewLine(); this.code.Append("} catch ("); this.Visit(@catch.ExceptionVar); this.code.Append(") {"); this.indent++; this.Visit(@catch.Stmt); this.indent--; } if (s.Finally != null) { this.NewLine(); this.code.Append("} finally {"); this.indent++; this.Visit(s.Finally); this.indent--; } this.NewLine(); this.code.Append("}"); return(s); }
protected override ICode VisitTry(StmtTry s) { // 'try' part ends unpredicably, so cannot use any information // 'catch' part is called unpredictably, so cannot use any information // 'finally' part is always run, so can use all information this.knownTrue.Push(new List <Expr>()); var @try = (Stmt)this.Visit(s.Try); this.knownTrue.Pop(); var catches = this.HandleList(s.Catches, x => { this.knownTrue.Push(new List <Expr>()); var @catch = (Stmt)this.Visit(x.Stmt); this.knownTrue.Pop(); if (@catch != x.Stmt) { return(new StmtTry.Catch(@catch, x.ExceptionVar)); } else { return(x); } }); var @finally = (Stmt)this.Visit(s.Finally); if (@try != s.Try || catches != null || @finally != s.Finally) { return(new StmtTry(s.Ctx, @try, catches ?? s.Catches, @finally)); } else { return(s); } }
protected override ICode VisitTry(StmtTry s) { return(this.Isolate(() => base.VisitTry(s))); }
private void CreatePart(IEnumerable <Instruction> insts, IEnumerable <ExceptionHandler> exs) { var stmtStart = insts.First(); var end = insts.Last(); var inst = insts.First(); for (; ;) { // Get the outermost 'try' statement starting on this instruction, if there is one var ex = exs.Where(x => x.TryStart == inst).OrderByDescending(x => x.HandlerEnd.Offset).FirstOrDefault(); if (ex != null) { if (inst != stmtStart) { // Build preceding code block up until this 'try' statement this.BuildBlock(stmtStart.GetRange(inst.Previous), end.Next); } // Build this 'try' statement var tryExs = exs.Where(x => x.TryStart.Offset >= ex.TryStart.Offset && x.TryEnd.Offset < ex.TryEnd.Offset).ToArray(); this.CreatePart(ex.TryStart.GetRange(ex.TryEnd.Previous), tryExs); // Build the 'catch' or 'finally' handler statement var handlerExs = exs.Where(x => x.TryStart.Offset >= ex.HandlerStart.Offset && x.TryEnd.Offset < ex.HandlerEnd.Offset).ToArray(); this.CreatePart(ex.HandlerStart.GetRange(ex.HandlerEnd.Previous), handlerExs); StmtTry tryStmt; switch (ex.HandlerType) { case ExceptionHandlerType.Catch: tryStmt = new StmtTry(this.ctx, ex.TryStart, ex.HandlerStart, null, ex.CatchType); break; case ExceptionHandlerType.Finally: tryStmt = new StmtTry(this.ctx, ex.TryStart, null, ex.HandlerStart, null); break; case ExceptionHandlerType.Fault: // TODO: Handle this properly, can emulate with 2 try statements tryStmt = new StmtTry(this.ctx, ex.TryStart, null, null, null); // INCORRECT break; default: throw new NotImplementedException("Cannot handle handler-type: " + ex.HandlerType); } if (tryStmt != null) { this.mappable.Add(tryStmt); // Put all 'try' statements in outer-first order. CIL will be at the end of the list this.blockMap[inst].Insert(0, tryStmt); } stmtStart = ex.HandlerEnd; inst = ex.HandlerEnd.Previous; } if (inst == null || inst == end) { break; } inst = inst.Next; } if (stmtStart.Offset <= end.Offset) { // Build the final statement this.BuildBlock(stmtStart.GetRange(end), end.Next); } }
protected override ICode VisitTry(StmtTry s) { var @try = this.RemoveContinuation(s.Try); if (@try != null) { if (s.Catches != null) { if (s.Catches.Count() != 1) { throw new InvalidOperationException("Should only ever see 1 catch here"); } var sCatch = s.Catches.First(); var @catch = this.RemoveContinuation(sCatch.Stmt); if (@catch != null) { if ((@try.Item2 == null || @catch.Item2 == null || @try.Item2 == @catch.Item2) && (@try.Item2 != null || @catch.Item2 != null)) { var newTry = new StmtTry(s.Ctx, @try.Item1, new[] { new StmtTry.Catch(@catch.Item1, sCatch.ExceptionVar) }, null); var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @catch.Item2, false); return(new StmtBlock(s.Ctx, newTry, newCont)); } } // Special case // When 'leave' CIL branch to different instructions, allow specific code to be // moved inside the 'try' or 'catch' block. It should be impossible for this code to throw an exception var tryTos = VisitorFindContinuations.Get(@try.Item2); if (tryTos.Count() == 1 && tryTos.First().To == @catch.Item2 && @try.Item2.StmtType == Stmt.NodeType.Block) { var try2Stmts = ((StmtBlock)@try.Item2).Statements.ToArray(); var s0 = try2Stmts.Take(try2Stmts.Length - 1); if (s0.All(x => x.StmtType == Stmt.NodeType.Assignment)) { var sN = try2Stmts.Last(); if (sN.StmtType == Stmt.NodeType.Continuation) { var newTry = new StmtTry(s.Ctx, new StmtBlock(s.Ctx, @try.Item1, new StmtBlock(s.Ctx, s0), new StmtContinuation(s.Ctx, ((StmtContinuation)sN).To, true)), s.Catches, null); return(newTry); } } } } if (s.Finally != null) { var @finally = this.RemoveContinuation(s.Finally); if (@finally != null) { if ((@try.Item2 == null || @finally.Item2 == null || @try.Item2 == @finally.Item2) && (@try.Item2 != null || @finally.Item2 != null)) { var newTry = new StmtTry(s.Ctx, @try.Item1, null, @finally.Item1); var newCont = new StmtContinuation(s.Ctx, @try.Item2 ?? @finally.Item2, false); return(new StmtBlock(s.Ctx, newTry, newCont)); } } } // TODO: This is a hack for badly handling fault handlers. They are ignored at the moment if (s.Catches == null && s.Finally == null) { var cont = @try.Item2 == null ? null : new StmtContinuation(s.Ctx, @try.Item2, false); return(new StmtBlock(s.Ctx, @try.Item1, cont)); } } return(base.VisitTry(s)); }