//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- // BoogiePL - Duplicator.cs //--------------------------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; namespace Microsoft.Boogie { public class Duplicator : StandardVisitor { // This is used to ensure that Procedures get duplicated only once // and that Implementation.Proc is resolved to the correct duplicated // Procedure. private Dictionary OldToNewProcedureMap = null; public override Absy Visit(Absy node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); node = base.Visit(node); return node; } public override Cmd VisitAssertCmd(AssertCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAssertCmd((AssertCmd)node.Clone()); } public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAssertEnsuresCmd((AssertEnsuresCmd)node.Clone()); } public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAssertRequiresCmd((AssertRequiresCmd)node.Clone()); } public override Cmd VisitAssignCmd(AssignCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); AssignCmd clone = (AssignCmd)node.Clone(); clone.Lhss = new List(clone.Lhss); clone.Rhss = new List(clone.Rhss); return base.VisitAssignCmd(clone); } public override Cmd VisitAssumeCmd(AssumeCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAssumeCmd((AssumeCmd)node.Clone()); } public override AtomicRE VisitAtomicRE(AtomicRE node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAtomicRE((AtomicRE)node.Clone()); } public override Axiom VisitAxiom(Axiom node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitAxiom((Axiom)node.Clone()); } public override Type VisitBasicType(BasicType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // do /not/ clone the type recursively return (BasicType)node.Clone(); } public override Block VisitBlock(Block node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitBlock((Block) node.Clone()); } public override Expr VisitBvConcatExpr (BvConcatExpr node) { Contract.Ensures(Contract.Result() != null); return base.VisitBvConcatExpr((BvConcatExpr) node.Clone()); } public override Expr VisitBvExtractExpr(BvExtractExpr node) { Contract.Ensures(Contract.Result() != null); return base.VisitBvExtractExpr((BvExtractExpr) node.Clone()); } public override Expr VisitCodeExpr(CodeExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); CodeExpr clone = (CodeExpr)base.VisitCodeExpr((CodeExpr)node.Clone()); // Before returning, fix up the resolved goto targets Contract.Assert(node.Blocks.Count == clone.Blocks.Count); Dictionary subst = new Dictionary(); for (int i = 0; i < node.Blocks.Count; i++) { subst.Add(node.Blocks[i], clone.Blocks[i]); } foreach (Block/*!*/ b in clone.Blocks) { Contract.Assert(b != null); GotoCmd g = b.TransferCmd as GotoCmd; if (g != null) { List targets = new List(); foreach (Block t in cce.NonNull(g.labelTargets)) { Block nt = subst[t]; targets.Add(nt); } g.labelTargets = targets; } } return clone; } public override List VisitBlockSeq(List blockSeq) { //Contract.Requires(blockSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitBlockSeq(new List(blockSeq)); } public override List/*!*/ VisitBlockList(List/*!*/ blocks) { //Contract.Requires(cce.NonNullElements(blocks)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); return base.VisitBlockList(new List(blocks)); } public override BoundVariable VisitBoundVariable(BoundVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitBoundVariable((BoundVariable)node.Clone()); } public override Type VisitBvType(BvType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // do /not/ clone the type recursively return (BvType)node.Clone(); } public override Cmd VisitCallCmd(CallCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); CallCmd clone = (CallCmd)node.Clone(); Contract.Assert(clone != null); clone.Ins = new List(clone.Ins); clone.Outs = new List(clone.Outs); return base.VisitCallCmd(clone); } public override Choice VisitChoice(Choice node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitChoice((Choice)node.Clone()); } public override List VisitCmdSeq(List cmdSeq) { //Contract.Requires(cmdSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitCmdSeq(new List(cmdSeq)); } public override Constant VisitConstant(Constant node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitConstant((Constant)node.Clone()); } public override CtorType VisitCtorType(CtorType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // do /not/ clone the type recursively return (CtorType)node.Clone(); } public override Declaration VisitDeclaration(Declaration node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitDeclaration((Declaration)node.Clone()); } public override List/*!*/ VisitDeclarationList(List/*!*/ declarationList) { //Contract.Requires(cce.NonNullElements(declarationList)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); // For Implementation.Proc to resolve correctly to duplicated Procedures // we need to visit the procedures first for (int i = 0, n = declarationList.Count; i < n; i++) { if (!( declarationList[i] is Procedure )) continue; declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i])); } // Now visit everything else for (int i = 0, n = declarationList.Count; i < n; i++) { if (declarationList[i] is Procedure) continue; declarationList[i] = cce.NonNull((Declaration) this.Visit(declarationList[i])); } return declarationList; } public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitDeclWithFormals((DeclWithFormals)node.Clone()); } public override Ensures VisitEnsures(Ensures node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitEnsures((Ensures)node.Clone()); } public override List VisitEnsuresSeq(List ensuresSeq) { //Contract.Requires(ensuresSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitEnsuresSeq(new List(ensuresSeq)); } public override Expr VisitExistsExpr(ExistsExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitExistsExpr((ExistsExpr)node.Clone()); } public override Expr VisitExpr(Expr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitExpr((Expr)node.Clone()); } public override IList VisitExprSeq(IList list) { //Contract.Requires(list != null); Contract.Ensures(Contract.Result>() != null); return base.VisitExprSeq(new List(list)); } public override Expr VisitForallExpr(ForallExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitForallExpr((ForallExpr)node.Clone()); } public override Formal VisitFormal(Formal node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitFormal((Formal)node.Clone()); } public override Function VisitFunction(Function node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitFunction((Function)node.Clone()); } public override GlobalVariable VisitGlobalVariable(GlobalVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitGlobalVariable((GlobalVariable)node.Clone()); } public override GotoCmd VisitGotoCmd(GotoCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // NOTE: This doesn't duplicate the labelTarget basic blocks // or resolve them to the new blocks // VisitImplementation() and VisitBlock() handle this return base.VisitGotoCmd( (GotoCmd)node.Clone()); } public override Cmd VisitHavocCmd(HavocCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitHavocCmd((HavocCmd)node.Clone()); } public override Expr VisitIdentifierExpr(IdentifierExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitIdentifierExpr((IdentifierExpr)node.Clone()); } public override List VisitIdentifierExprSeq(List identifierExprSeq) { //Contract.Requires(identifierExprSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitIdentifierExprSeq(new List(identifierExprSeq)); } public override Implementation VisitImplementation(Implementation node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); var impl = base.VisitImplementation((Implementation)node.Clone()); var blockDuplicationMapping = new Dictionary(); // Compute the mapping between the blocks of the old implementation (node) // and the new implementation (impl). foreach (var blockPair in node.Blocks.Zip(impl.Blocks)) { blockDuplicationMapping.Add(blockPair.Item1, blockPair.Item2); } // The GotoCmds and blocks have now been duplicated. // Resolve GotoCmd targets to the duplicated blocks foreach (GotoCmd gotoCmd in impl.Blocks.Select( bb => bb.TransferCmd).OfType()) { var newLabelTargets = new List(); var newLabelNames = new List(); for (int index = 0; index < gotoCmd.labelTargets.Count; ++index) { var newBlock = blockDuplicationMapping[gotoCmd.labelTargets[index]]; newLabelTargets.Add(newBlock); newLabelNames.Add(newBlock.Label); } gotoCmd.labelTargets = newLabelTargets; gotoCmd.labelNames = newLabelNames; } return impl; } public override Expr VisitLiteralExpr(LiteralExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitLiteralExpr((LiteralExpr)node.Clone()); } public override LocalVariable VisitLocalVariable(LocalVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitLocalVariable((LocalVariable)node.Clone()); } public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); MapAssignLhs clone = (MapAssignLhs)node.Clone(); clone.Indexes = new List(clone.Indexes); return base.VisitMapAssignLhs(clone); } public override MapType VisitMapType(MapType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // do /not/ clone the type recursively return (MapType)node.Clone(); } public override Expr VisitNAryExpr(NAryExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitNAryExpr((NAryExpr)node.Clone()); } public override Expr VisitOldExpr(OldExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitOldExpr((OldExpr)node.Clone()); } public override Cmd VisitParCallCmd(ParCallCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); ParCallCmd clone = (ParCallCmd)node.Clone(); Contract.Assert(clone != null); clone.CallCmds = new List(node.CallCmds); return base.VisitParCallCmd(clone); } public override Procedure VisitProcedure(Procedure node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Procedure newProcedure = null; if (OldToNewProcedureMap != null && OldToNewProcedureMap.ContainsKey(node)) { newProcedure = OldToNewProcedureMap[node]; } else { newProcedure = base.VisitProcedure((Procedure) node.Clone()); if (OldToNewProcedureMap != null) OldToNewProcedureMap[node] = newProcedure; } return newProcedure; } public override Program VisitProgram(Program node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // If cloning an entire program we need to ensure that // Implementation.Proc gets resolved to the right Procedure // (i.e. we don't duplicate Procedure twice) and CallCmds // call the right Procedure. // The map below is used to achieve this. OldToNewProcedureMap = new Dictionary(); var newProgram = base.VisitProgram((Program)node.Clone()); // We need to make sure that CallCmds get resolved to call Procedures we duplicated // instead of pointing to procedures in the old program var callCmds = newProgram.Blocks().SelectMany(b => b.Cmds).OfType(); foreach (var callCmd in callCmds) { callCmd.Proc = OldToNewProcedureMap[callCmd.Proc]; } OldToNewProcedureMap = null; // This Visitor could be used for other things later so remove the map. return newProgram; } public override QKeyValue VisitQKeyValue(QKeyValue node) { //Contract.Requires(node != null); var newParams = new List(); foreach (var o in node.Params) { var e = o as Expr; if (e == null) { newParams.Add(o); } else { newParams.Add((Expr)this.Visit(e)); } } QKeyValue next = node.Next == null ? null : (QKeyValue)this.Visit(node.Next); return new QKeyValue(node.tok, node.Key, newParams, next); } public override BinderExpr VisitBinderExpr(BinderExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitBinderExpr((BinderExpr)node.Clone()); } public override Requires VisitRequires(Requires node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitRequires((Requires)node.Clone()); } public override List VisitRequiresSeq(List requiresSeq) { //Contract.Requires(requiresSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitRequiresSeq(new List(requiresSeq)); } public override Cmd VisitRE(RE node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitRE((RE)node.Clone()); } public override List VisitRESeq(List reSeq) { //Contract.Requires(reSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitRESeq(new List(reSeq)); } public override ReturnCmd VisitReturnCmd(ReturnCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitReturnCmd((ReturnCmd)node.Clone()); } public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitReturnExprCmd((ReturnExprCmd)node.Clone()); } public override Sequential VisitSequential(Sequential node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitSequential((Sequential)node.Clone()); } public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitSimpleAssignLhs((SimpleAssignLhs)node.Clone()); } public override Cmd VisitStateCmd(StateCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitStateCmd((StateCmd)node.Clone()); } public override TransferCmd VisitTransferCmd(TransferCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitTransferCmd((TransferCmd)node.Clone()); } public override Trigger VisitTrigger(Trigger node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitTrigger((Trigger)node.Clone()); } public override Type VisitType(Type node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); // do /not/ clone the type recursively return (Type)node.Clone(); } public override TypedIdent VisitTypedIdent(TypedIdent node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitTypedIdent((TypedIdent)node.Clone()); } public override Variable VisitVariable(Variable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return node; } public override List VisitVariableSeq(List variableSeq) { //Contract.Requires(variableSeq != null); Contract.Ensures(Contract.Result>() != null); return base.VisitVariableSeq(new List(variableSeq)); } public override YieldCmd VisitYieldCmd(YieldCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); return base.VisitYieldCmd((YieldCmd)node.Clone()); } } #region A duplicator that also does substitutions for a set of variables /// /// A substitution is a partial mapping from Variables to Exprs. /// public delegate Expr/*?*/ Substitution(Variable/*!*/ v); public static class Substituter { public static Substitution SubstitutionFromHashtable(Dictionary map, bool fallBackOnName = false, Procedure proc = null) { Contract.Requires(map != null); Contract.Ensures(Contract.Result() != null); // TODO: With Whidbey, could use anonymous functions. return new Substitution(new CreateSubstitutionClosure(map, fallBackOnName, proc).Method); } private sealed class CreateSubstitutionClosure { Dictionary/*!*/ map; Dictionary/*!*/ nameMap; Procedure proc; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(map != null); } static string UniqueName(Variable variable, Procedure proc) { // TODO(wuestholz): Maybe we should define structural equality for variables instead. var scope = "#global_scope#"; if (proc != null && !(variable is GlobalVariable || variable is Constant)) { scope = proc.Name; } return string.Format("{0}.{1}", scope, variable.Name); } public CreateSubstitutionClosure(Dictionary map, bool fallBackOnName = false, Procedure proc = null) : base() { Contract.Requires(map != null); this.map = map; this.proc = proc; if (fallBackOnName && proc != null) { this.nameMap = map.ToDictionary(kv => UniqueName(kv.Key, proc), kv => kv.Value); } } public Expr/*?*/ Method(Variable v) { Contract.Requires(v != null); if(map.ContainsKey(v)) { return map[v]; } Expr e; if (nameMap != null && proc != null && nameMap.TryGetValue(UniqueName(v, proc), out e)) { return e; } return null; } } // ----------------------------- Substitutions for Expr ------------------------------- /// /// Apply a substitution to an expression. Any variables not in domain(subst) /// is not changed. The substitutions apply within the "old", but the "old" /// expression remains. /// public static Expr Apply(Substitution subst, Expr expr) { Contract.Requires(subst != null); Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); return (Expr)new NormalSubstituter(subst).Visit(expr); } /// /// Apply a substitution to an expression. /// Outside "old" expressions, the substitution "always" is applied; any variable not in /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to /// variables in domain(forOld), apply map "always" to variables in /// domain(always)-domain(forOld), and leave variable unchanged otherwise. /// public static Expr Apply(Substitution always, Substitution forold, Expr expr) { Contract.Requires(always != null); Contract.Requires(forold != null); Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); return (Expr)new NormalSubstituter(always, forold).Visit(expr); } /// /// Apply a substitution to an expression replacing "old" expressions. /// Outside "old" expressions, the substitution "always" is applied; any variable not in /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to /// variables in domain(forOld), apply map "always" to variables in /// domain(always)-domain(forOld), and leave variable unchanged otherwise. /// public static Expr ApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr) { Contract.Requires(always != null); Contract.Requires(forOld != null); Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); return (Expr)new ReplacingOldSubstituter(always, forOld).Visit(expr); } public static Expr FunctionCallReresolvingApplyReplacingOldExprs(Substitution always, Substitution forOld, Expr expr, Program program) { Contract.Requires(always != null); Contract.Requires(forOld != null); Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); return (Expr)new FunctionCallReresolvingReplacingOldSubstituter(program, always, forOld).Visit(expr); } // ----------------------------- Substitutions for Cmd ------------------------------- /// /// Apply a substitution to a command. Any variables not in domain(subst) /// is not changed. The substitutions apply within the "old", but the "old" /// expression remains. /// public static Cmd Apply(Substitution subst, Cmd cmd) { Contract.Requires(subst != null); Contract.Requires(cmd != null); Contract.Ensures(Contract.Result() != null); return (Cmd)new NormalSubstituter(subst).Visit(cmd); } /// /// Apply a substitution to a command. /// Outside "old" expressions, the substitution "always" is applied; any variable not in /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to /// variables in domain(forOld), apply map "always" to variables in /// domain(always)-domain(forOld), and leave variable unchanged otherwise. /// public static Cmd Apply(Substitution always, Substitution forOld, Cmd cmd) { Contract.Requires(always != null); Contract.Requires(forOld != null); Contract.Requires(cmd != null); Contract.Ensures(Contract.Result() != null); return (Cmd)new NormalSubstituter(always, forOld).Visit(cmd); } /// /// Apply a substitution to a command replacing "old" expressions. /// Outside "old" expressions, the substitution "always" is applied; any variable not in /// domain(always) is not changed. Inside "old" expressions, apply map "forOld" to /// variables in domain(forOld), apply map "always" to variables in /// domain(always)-domain(forOld), and leave variable unchanged otherwise. /// public static Cmd ApplyReplacingOldExprs(Substitution always, Substitution forOld, Cmd cmd) { Contract.Requires(always != null); Contract.Requires(forOld != null); Contract.Requires(cmd != null); Contract.Ensures(Contract.Result() != null); return (Cmd)new ReplacingOldSubstituter(always, forOld).Visit(cmd); } // ----------------------------- Substitutions for QKeyValue ------------------------------- /// /// Apply a substitution to a list of attributes. Any variables not in domain(subst) /// is not changed. The substitutions apply within the "old", but the "old" /// expression remains. /// public static QKeyValue Apply(Substitution subst, QKeyValue kv) { Contract.Requires(subst != null); if (kv == null) { return null; } else { return (QKeyValue)new NormalSubstituter(subst).Visit(kv); } } /// /// Apply a substitution to a list of attributes replacing "old" expressions. /// For a further description, see "ApplyReplacingOldExprs" above for Expr. /// public static QKeyValue ApplyReplacingOldExprs(Substitution always, Substitution forOld, QKeyValue kv) { Contract.Requires(always != null); Contract.Requires(forOld != null); if (kv == null) { return null; } else { return (QKeyValue)new ReplacingOldSubstituter(always, forOld).Visit(kv); } } // ------------------------------------------------------------ private sealed class NormalSubstituter : Duplicator { private readonly Substitution/*!*/ always; private readonly Substitution/*!*/ forold; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(always != null); Contract.Invariant(forold != null); } public NormalSubstituter(Substitution subst) : base() { Contract.Requires(subst != null); this.always = subst; this.forold = Substituter.SubstitutionFromHashtable(new Dictionary()); } public NormalSubstituter(Substitution subst, Substitution forold) : base() { Contract.Requires(subst != null); this.always = subst; this.forold = forold; } private bool insideOldExpr = false; public override Expr VisitIdentifierExpr(IdentifierExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Expr/*?*/ e = null; if (insideOldExpr) { e = forold(cce.NonNull(node.Decl)); } if (e == null) { e = always(cce.NonNull(node.Decl)); } return e == null ? base.VisitIdentifierExpr(node) : e; } public override Expr VisitOldExpr(OldExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); bool previouslyInOld = insideOldExpr; insideOldExpr = true; Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr)); insideOldExpr = previouslyInOld; return new OldExpr(node.tok, e); } } private sealed class FunctionCallReresolvingReplacingOldSubstituter : ReplacingOldSubstituter { readonly Program Program; public FunctionCallReresolvingReplacingOldSubstituter(Program program, Substitution always, Substitution forold) : base(always, forold) { Program = program; } public override Expr VisitNAryExpr(NAryExpr node) { var result = base.VisitNAryExpr(node); var nAryExpr = result as NAryExpr; if (nAryExpr != null) { var funCall = nAryExpr.Fun as FunctionCall; if (funCall != null) { funCall.Func = Program.FindFunction(funCall.FunctionName); } } return result; } } private class ReplacingOldSubstituter : Duplicator { private readonly Substitution/*!*/ always; private readonly Substitution/*!*/ forold; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(always != null); Contract.Invariant(forold != null); } public ReplacingOldSubstituter(Substitution always, Substitution forold) : base() { Contract.Requires(forold != null); Contract.Requires(always != null); this.always = always; this.forold = forold; } private bool insideOldExpr = false; public override Expr VisitIdentifierExpr(IdentifierExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Expr/*?*/ e = null; if (insideOldExpr) { e = forold(cce.NonNull(node.Decl)); } if (e == null) { e = always(cce.NonNull(node.Decl)); } return e == null ? base.VisitIdentifierExpr(node) : e; } public override Expr VisitOldExpr(OldExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); bool previouslyInOld = insideOldExpr; insideOldExpr = true; Expr/*!*/ e = (Expr/*!*/)cce.NonNull(this.Visit(node.Expr)); insideOldExpr = previouslyInOld; return e; } } } #endregion }