public DebugView(StmtTry s) { this.@try = s.@try; this.@catch = s.@catch; this.@finally = s.@finally; this.catchType = s.catchType; this.Try = s.Try; this.Catches = s.Catches; this.Finally = s.Finally; }
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); }
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 override ICode VisitTry(StmtTry s) { return this.Isolate(() => base.VisitTry(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; }
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); } }