public virtual Differences VisitCatchList(CatchList list1, CatchList list2, out CatchList changes, out CatchList deletions, out CatchList insertions){ changes = list1 == null ? null : list1.Clone(); deletions = list1 == null ? null : list1.Clone(); insertions = list1 == null ? new CatchList() : list1.Clone(); //^ assert insertions != null; Differences differences = new Differences(); for (int j = 0, n = list2 == null ? 0 : list2.Count; j < n; j++){ //^ assert list2 != null; Catch nd2 = list2[j]; if (nd2 == null) continue; insertions.Add(null); } TrivialHashtable savedDifferencesMapFor = this.differencesMapFor; this.differencesMapFor = null; TrivialHashtable matchedNodes = new TrivialHashtable(); for (int i = 0, k = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; Catch nd1 = list1[i]; if (nd1 == null) continue; Differences diff; int j; Catch nd2 = this.GetClosestMatch(nd1, list1, list2, i, ref k, matchedNodes, out diff, out j); if (nd2 == null || diff == null){Debug.Assert(nd2 == null && diff == null); continue;} matchedNodes[nd1.UniqueKey] = nd1; matchedNodes[nd2.UniqueKey] = nd2; changes[i] = diff.Changes as Catch; deletions[i] = diff.Deletions as Catch; insertions[i] = diff.Insertions as Catch; insertions[n+j] = nd1; //Records the position of nd2 in list2 in case the change involved a permutation Debug.Assert(diff.Changes == changes[i] && diff.Deletions == deletions[i] && diff.Insertions == insertions[i]); differences.NumberOfDifferences += diff.NumberOfDifferences; differences.NumberOfSimilarities += diff.NumberOfSimilarities; } //Find deletions for (int i = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; Catch nd1 = list1[i]; if (nd1 == null) continue; if (matchedNodes[nd1.UniqueKey] != null) continue; changes[i] = null; deletions[i] = nd1; insertions[i] = null; differences.NumberOfDifferences += 1; } //Find insertions for (int j = 0, n = list1 == null ? 0 : list1.Count, m = list2 == null ? 0 : list2.Count; j < m; j++){ //^ assert list2 != null; Catch nd2 = list2[j]; if (nd2 == null) continue; if (matchedNodes[nd2.UniqueKey] != null) continue; insertions[n+j] = nd2; //Records nd2 as an insertion into list1, along with its position in list2 differences.NumberOfDifferences += 1; //REVIEW: put the size of the tree here? } if (differences.NumberOfDifferences == 0){ changes = null; deletions = null; insertions = null; } this.differencesMapFor = savedDifferencesMapFor; return differences; }
public virtual CatchList VisitCatchList(CatchList catchers, CatchList changes, CatchList deletions, CatchList insertions){ if (changes == null || deletions == null || insertions == null) return catchers; int n = catchers == null ? 0 : catchers.Count; if (n > changes.Count){Debug.Assert(false); n = changes.Count;} if (n > deletions.Count){Debug.Assert(false); n = deletions.Count;} if (n > insertions.Count){Debug.Assert(false); n = insertions.Count;} if (catchers != null) for (int i = 0; i < n; i++) catchers[i] = this.VisitCatch(catchers[i], changes[i], deletions[i], insertions[i]); CatchList result = new CatchList(insertions.Count-n); for (int i = n, m = insertions.Count; i < m; i++) result.Add(insertions[i]); return result; }
private Try ParseTry(TokenSet followers){ object catchContext = null; object finallyContext = null; bool savedUnmatchedTry = this.unmatchedTry; Try Try = new Try(); Try.SourceContext = this.scanner.CurrentSourceContext; Debug.Assert(this.currentToken == Token.Try || this.currentToken == Token.Catch || this.currentToken == Token.Finally); TokenSet tryBlockFollowers = followers|Parser.CatchOrFinally; if (this.currentToken == Token.Try){ this.unmatchedTry = true; this.GetNextToken(); if (this.currentToken == Token.LeftBrace) Try.TryBlock = this.ParseBlock(tryBlockFollowers); else{ this.HandleError(Error.ExpectedLeftBrace); if (Parser.StatementStart[this.currentToken]){ Block block = new Block(); block.Checked = this.insideCheckedBlock; block.IsUnsafe = this.inUnsafeCode; block.SuppressCheck = this.insideUncheckedBlock; SourceContext ctx = this.scanner.CurrentSourceContext; block.SourceContext = this.scanner.CurrentSourceContext; block.Statements = this.ParseStatements(tryBlockFollowers|Token.RightBrace); block.SourceContext.EndPos = this.scanner.CurrentSourceContext.StartPos; Try.TryBlock = block; this.Skip(Token.RightBrace); } } }else{ if (savedUnmatchedTry && ((this.currentToken == Token.Catch && followers[Token.Catch]) || (this.currentToken == Token.Finally && followers[Token.Finally]))) return null; else this.HandleError(Error.SyntaxError, "try"); } CatchList catchers = new CatchList(); bool seenEmptyCatch = false; while (this.currentToken == Token.Catch){ if (seenEmptyCatch) this.HandleError(Error.TooManyCatches); catchContext = this.scanner.CurrentSourceContext; Catch c = this.ParseCatch(tryBlockFollowers); if (c == null) continue; if (c.TypeExpression == null) seenEmptyCatch = true; catchers.Add(c); } Try.Catchers = catchers; if (this.currentToken == Token.Finally){ finallyContext = this.scanner.CurrentSourceContext; this.GetNextToken(); Try.Finally = new Finally(this.ParseBlock(followers)); }else if (catchers.Count == 0) this.SkipTo(followers, Error.ExpectedEndTry); if (this.sink != null){ if (finallyContext != null) if (catchContext != null) this.sink.MatchTriple(Try.SourceContext, (SourceContext)catchContext, (SourceContext)finallyContext); else this.sink.MatchPair(Try.SourceContext, (SourceContext)finallyContext); else if (catchContext != null) this.sink.MatchPair(Try.SourceContext, (SourceContext)catchContext); } this.unmatchedTry = savedUnmatchedTry; return Try; }
public override Node VisitQueryTransact(QueryTransact qt) { if (qt == null || qt.Source == null || qt.Source.Type == null) return null; Block block = new Block(new StatementList(10)); qt.Transaction = this.NewClosureLocal(SystemTypes.IDbTransaction, this.currentMethod.Body.Scope); Expression locCommit = this.NewClosureLocal(SystemTypes.Boolean, this.currentMethod.Body.Scope); TypeNode txType = null; if (this.GetTypeView(qt.Source.Type).IsAssignableTo(SystemTypes.IDbConnection)) { txType = SystemTypes.IDbConnection; } else if (this.GetTypeView(qt.Source.Type).IsAssignableTo(SystemTypes.IDbTransactable)) { txType = SystemTypes.IDbTransactable; } Expression source = this.typeSystem.ExplicitCoercion(qt.Source, txType, this.TypeViewer); if (qt.Isolation != null) { Method mBegin = this.GetTypeView(txType).GetMethod(idBeginTransaction, SystemTypes.IsolationLevel); MethodCall mcBegin = new MethodCall(new MemberBinding(source, mBegin), new ExpressionList(qt.Isolation)); mcBegin.Type = mBegin.ReturnType; mcBegin.NodeType = NodeType.Callvirt; block.Statements.Add(new AssignmentStatement(qt.Transaction, mcBegin)); } else { Method mBegin = this.GetTypeView(txType).GetMethod(idBeginTransaction); MethodCall mcBegin = new MethodCall(new MemberBinding(source, mBegin), null); mcBegin.Type = mBegin.ReturnType; mcBegin.NodeType = NodeType.Callvirt; block.Statements.Add(new AssignmentStatement(qt.Transaction, mcBegin)); } block.Statements.Add(new AssignmentStatement(locCommit, Literal.True)); // prepare finally block Block finBlock = new Block(new StatementList(10)); Method mRollback = SystemTypes.IDbTransaction.GetMethod(idRollback); MethodCall mcRollback = new MethodCall(new MemberBinding(qt.Transaction, mRollback), null); mcRollback.Type = mRollback.ReturnType; mcRollback.NodeType = NodeType.Callvirt; Method mCommit = SystemTypes.IDbTransaction.GetMethod(idCommit); MethodCall mcCommit = new MethodCall(new MemberBinding(qt.Transaction, mCommit), null); mcCommit.Type = mCommit.ReturnType; mcCommit.NodeType = NodeType.Callvirt; Method mDispose = SystemTypes.IDisposable.GetMethod(StandardIds.Dispose); MethodCall mcDispose = new MethodCall(new MemberBinding(qt.Transaction, mDispose), null); mcDispose.Type = mDispose.ReturnType; mcDispose.NodeType = NodeType.Callvirt; Block bCommitStart = new Block(); Block bCommitBody = new Block(qt.CommitBody.Statements); Block bRollbackBody = new Block(qt.RollbackBody.Statements); Block finExit = new Block(); finBlock.Statements.Add(new Branch(locCommit, bCommitStart)); finBlock.Statements.Add(new ExpressionStatement(mcRollback)); finBlock.Statements.Add(bRollbackBody); finBlock.Statements.Add(new Branch(null, finExit)); finBlock.Statements.Add(bCommitStart); finBlock.Statements.Add(new ExpressionStatement(mcCommit)); finBlock.Statements.Add(bCommitBody); finBlock.Statements.Add(finExit); finBlock.Statements.Add(new ExpressionStatement(mcDispose)); finBlock.Statements.Add(new AssignmentStatement(qt.Transaction, Literal.Null)); // prepare catcher Local locEx = new Local(SystemTypes.Object); Block catchBlock = new Block(new StatementList(2)); catchBlock.Statements.Add(new AssignmentStatement(locCommit, Literal.False)); Throw _throw = new Throw(locEx); _throw.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(_throw); CatchList catchers = new CatchList(1); catchers.Add(new Catch(catchBlock, locEx, SystemTypes.Object)); // prepare try block Block tryBlock = new Block(new StatementList(4)); qt.CommitBody.Statements = null;; qt.RollbackBody.Statements = null; tryBlock.Statements.Add(qt.Body); tryBlock.Statements.Add(new Branch(null, qt.CommitBody)); tryBlock.Statements.Add(qt.RollbackBody); tryBlock.Statements.Add(new AssignmentStatement(locCommit, Literal.False)); tryBlock.Statements.Add(qt.CommitBody); this.exceptionBlockFor[qt.CommitBody.UniqueKey] = tryBlock; this.exceptionBlockFor[qt.RollbackBody.UniqueKey] = tryBlock; // add try-finally to block block.Statements.Add(new Try(tryBlock, catchers, null, null, new Finally(finBlock))); this.currentTransaction = qt; Node result = this.VisitBlock(block); this.currentTransaction = null; return result; }
public virtual Statement MarkAsInstrumentationCode(Block block){ Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; Catch catchClause = new Catch(new Block(new StatementList(rethrow)), new Local(SystemTypes.ContractMarkerException), SystemTypes.ContractMarkerException); CatchList catchers = new CatchList(1); catchers.Add(catchClause); return new Try(block, catchers, null, null, null); }
public override Statement VisitExpose(Expose Expose){ if (Expose == null) return null; if (Expose.Instance == null) return this.VisitBlock(Expose.Body); TypeNode exposeInstanceType = TypeNode.StripModifiers(Expose.Instance.Type); if (exposeInstanceType == null) return this.VisitBlock(Expose.Body); SourceContext endContext = new SourceContext(Expose.SourceContext.Document, Expose.SourceContext.EndPos - 1, Expose.SourceContext.EndPos); string startMethodName = null; string endMethodName = null; Method startMethod = null; Method endMethod = null; InvariantList justToForceDeserialization = exposeInstanceType.Contract != null ? exposeInstanceType.Contract.Invariants : null; if (exposeInstanceType.Contract == null || exposeInstanceType.Contract.FramePropertyGetter == null ) { // If we're exposing an expression E of type T where T is not a guarded class, // then for the sake of downstream analysis tools (such as the Spec# Program Verifier) we emit the following code: // // write|expose (E) S [alternatively, "write|expose (E at T) S"] // // is translated into // // T target = E; // Guard.StartWritingFrame(target, typeof(T)); [alternatively, Guard.StartWritingAtNop] // try{ // S // }finally{ // Guard.EndWritingFrame(target, typeof(T)); [alternatively, Guard.EndWritingAtNop] // } // // These methods are no-ops. For this reason, // combined with the fact that Boogie considers unchecked exceptions to be the end of the world, // we don't need to distinguish between checked and unchecked exceptions here. Block block = new Block(new StatementList()); Local target = new Local(Identifier.Empty, exposeInstanceType, block); Literal typeArgument = null; if (Expose.IsLocal) { startMethodName = "StartWritingAtNop"; endMethodName = "EndWritingAtNop"; } else { startMethodName = "StartWritingFrame"; endMethodName = "EndWritingFrame"; } typeArgument = new Literal(exposeInstanceType, SystemTypes.Type); startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Object), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Object), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); block.Statements.Add(new AssignmentStatement(target, Expose.Instance, Expose.Instance.SourceContext)); block.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, startMethod), new ExpressionList(target, new UnaryExpression(typeArgument, NodeType.Typeof)), NodeType.Call, SystemTypes.Void), Expose.Instance.SourceContext)); block.Statements.Add(new Try( Expose.Body, null, null, null, new Finally(new Block(new StatementList(new ExpressionStatement(new MethodCall( new MemberBinding(null, endMethod), new ExpressionList(target, new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)), NodeType.Call, SystemTypes.Void), endContext)))) )); return (Statement) this.Visit(block); } // write|additive expose (E) S [alternatively: expose (E) S] // // is translated into // // Guard! rootFrame = E.FrameGuard.StartWritingTransitively(); [alternatively "StartWritingAtTransitively"] // Exception exception = null; // try { // S // } catch (Exception e) { // exception = e; // throw; // } finally { // if (exception == null || exception is ICheckedException) // rootFrame.EndWritingTransitively(); [alternatively "EndWritingAtTransitively"] // } // // This is a hack; it would be better to statically have different code paths for // the normal completion case and the exceptional completion case. // However, that requires transforming returns, gotos, continues, breaks, etc. // Of course, all of the above can first be transformed into gotos. // // The "throw" in the catch clause is needed to allow the definite assignment // analysis to know that things assigned to in S are really assigned to // in the code following the finally block. // More importantly, who are we to eat up an exception, unless the exception // is checked and the object invariant doesn't hold. TypeNode staticInstanceType = exposeInstanceType; if (Expose.IsLocal) { startMethodName = "StartWritingAtTransitively"; endMethodName = "EndWritingAtTransitively"; startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); } else { if (Expose.NodeType == NodeType.Read) { startMethodName = "StartReadingTransitively"; endMethodName = "EndReadingTransitively"; } else { startMethodName = "StartWritingTransitively"; endMethodName = "EndWritingTransitively"; } startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName)); } TypeNode guardType = OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Guard); Method frameGetter = staticInstanceType.Contract.FramePropertyGetter; Block newBody = new Block(); Local rootFrame = new Local(Identifier.For("SS$rootFrame"), guardType, newBody); Expression frameGetterCall = new MethodCall(new MemberBinding(Expose.Instance, frameGetter), null); // Need two independent argument lists. Otherwise, the processing of the first one disrupts the // second one. ExpressionList startFrameGetterExprArgs; ExpressionList endFrameGetterExprArgs; if (Expose.IsLocal) { startFrameGetterExprArgs = new ExpressionList(new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)); endFrameGetterExprArgs = new ExpressionList(new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)); } else { startFrameGetterExprArgs = null; endFrameGetterExprArgs = null; } Expression frameGetterExpr = new MethodCall(new MemberBinding(frameGetterCall, startMethod), startFrameGetterExprArgs, NodeType.Call, startMethod.ReturnType); Statement startCall = new AssignmentStatement(rootFrame, frameGetterExpr, Expose.Instance.SourceContext); // rootFrame.End(Reading|Writing)Transitively(); Statement endCall = new ExpressionStatement(new MethodCall(new MemberBinding(rootFrame, endMethod), endFrameGetterExprArgs, NodeType.Call, SystemTypes.Void), endContext); Local exception = new Local(SystemTypes.Exception); CatchList catchList = new CatchList(1); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; Local e = new Local(SystemTypes.Exception); catchList.Add(new Catch(new Block(new StatementList(new AssignmentStatement(exception, e), rethrow)), e, SystemTypes.Exception)); newBody.Statements = new StatementList( startCall, new AssignmentStatement(exception, new Literal(null, SystemTypes.Exception)), new Try( Expose.Body, catchList, null, null, new Finally(new Block(new StatementList( new If( new BinaryExpression( new BinaryExpression(exception, new Literal(null, SystemTypes.Exception), NodeType.Eq, SystemTypes.Boolean), new BinaryExpression(exception, new Literal(SystemTypes.ICheckedException, SystemTypes.Type), NodeType.Is, SystemTypes.Boolean), NodeType.LogicalOr, SystemTypes.Boolean), new Block(new StatementList(endCall)), null)))))); return this.VisitBlock(newBody); }
private CatchList Translate(CodeCatchClauseCollection catchers){ if (catchers == null) return null; int n = catchers.Count; CatchList catchList = new CatchList(n); for (int i = 0; i < n; i++) catchList.Add(this.Translate(catchers[i])); return catchList; }