//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.Text; using System.IO; using System.Linq; using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; using Microsoft.Basetypes; // A translator from the Boogie AST to the VCExpr AST. // This was previously realised in the methods AbsyExpr.VCView namespace Microsoft.Boogie.VCExprAST { using Microsoft.Boogie; // TODO: in future we might use that for defining symbols for Boogie's conditional compilation public class VCGenerationOptions { private readonly List/*!*/ SupportedProverCommands; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(SupportedProverCommands)); } public bool IsProverCommandSupported(string kind) { Contract.Requires(kind != null); return SupportedProverCommands.Contains(kind); } public bool IsAnyProverCommandSupported(string kinds) { Contract.Requires(kinds != null); if (kinds.IndexOf(',') < 0) { return IsProverCommandSupported(kinds); } else { return kinds.Split(',', ' ').Any(k => IsProverCommandSupported(k)); } } public VCGenerationOptions(List/*!*/ supportedProverCommands) { Contract.Requires(cce.NonNullElements(supportedProverCommands)); this.SupportedProverCommands = supportedProverCommands; } } public delegate VCExpr/*!*/ CodeExprConverter(CodeExpr/*!*/ codeExpr, Hashtable/**//*!*/ blockVariables, List bindings, bool isPositiveContext); public class Boogie2VCExprTranslator : ReadOnlyVisitor, ICloneable { // Stack on which the various Visit-methods put the result of the translation private readonly Stack/*!*/ SubExpressions = new Stack(); [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(SubExpressions)); Contract.Invariant(Gen != null); } private void Push(VCExpr expr) { Contract.Requires(expr != null); SubExpressions.Push(expr); } private VCExpr Pop() { Contract.Ensures(Contract.Result() != null); return SubExpressions.Pop(); } public VCExpr Translate(Expr expr) { Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); this.Visit(expr); return Pop(); } public List/*!*/ Translate(IList exprs) { Contract.Requires(exprs != null); Contract.Ensures(cce.NonNullElements(Contract.Result>())); List/*!*/ res = new List(); foreach (Expr e in exprs) res.Add(Translate(cce.NonNull(e))); return res; } /////////////////////////////////////////////////////////////////////////////// internal readonly VCExpressionGenerator/*!*/ Gen; public Boogie2VCExprTranslator(VCExpressionGenerator gen, VCGenerationOptions genOptions) { Contract.Requires(gen != null); Contract.Requires(genOptions != null); this.Gen = gen; this.GenerationOptions = genOptions; UnboundVariables = new VariableMapping(); BoundVariables = new VariableMapping(); Formals = new VariableMapping(); } private Boogie2VCExprTranslator(Boogie2VCExprTranslator tl) { Contract.Requires(tl != null); this.Gen = tl.Gen; this.GenerationOptions = tl.GenerationOptions; UnboundVariables = (VariableMapping)tl.UnboundVariables.Clone(); BoundVariables = new VariableMapping(); Formals = new VariableMapping(); } public object Clone() { Contract.Ensures(Contract.Result() != null); return new Boogie2VCExprTranslator(this); } private IAppliableTranslator IAppTranslatorAttr = null; private IAppliableTranslator IAppTranslator { get { Contract.Ensures(Contract.Result() != null); if (IAppTranslatorAttr == null) IAppTranslatorAttr = new IAppliableTranslator(this); return IAppTranslatorAttr; } } /////////////////////////////////////////////////////////////////////////////// // Class for handling occurring variables private class VariableMapping : ICloneable { private readonly List/*!*/>/*!*/ Mapping; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Mapping != null && Contract.ForAll(Mapping, i => cce.NonNullDictionaryAndValues(i))); } public VariableMapping() { List/*!*/>/*!*/ mapping = new List/*!*/>(); mapping.Add(new Dictionary()); this.Mapping = mapping; } private VariableMapping(VariableMapping vm) { Contract.Requires(vm != null); List/*!*/>/*!*/ mapping = new List/*!*/>(); foreach (Dictionary/*!*/ d in vm.Mapping) { Contract.Assert(cce.NonNullDictionaryAndValues(d)); mapping.Add(new Dictionary(d)); } this.Mapping = mapping; } public object Clone() { Contract.Ensures(Contract.Result() != null); return new VariableMapping(this); } public void PushScope() { Mapping.Add(new Dictionary()); } public void PopScope() { Contract.Assume(Mapping.Count > 0); Mapping.RemoveAt(Mapping.Count - 1); } public void Bind(VarKind boogieVar, VCExprVar/*!*/ vcExprVar) { Contract.Requires(vcExprVar != null); Contract.Requires(boogieVar != null); Contract.Requires(!Contains(boogieVar)); Mapping[Mapping.Count - 1].Add(boogieVar, vcExprVar); } public VCExprVar Lookup(VarKind boogieVar) { Contract.Requires(boogieVar != null); Contract.Ensures(Contract.Result() != null); VCExprVar res = LookupHelp(boogieVar); Contract.Assume(res != null); return res; } [Pure] public bool Contains(VarKind boogieVar) { Contract.Requires(boogieVar != null); return LookupHelp(boogieVar) != null; } public bool TryGetValue(VarKind boogieVar, out VCExprVar res) { Contract.Requires(boogieVar != null); res = LookupHelp(boogieVar); return res != null; } [Pure] private VCExprVar LookupHelp(VarKind boogieVar) { Contract.Requires(boogieVar != null); VCExprVar res; foreach (Dictionary/*!*/ d in Mapping) { //Contract.Assert(cce.NonNullElements(d)); if (d.TryGetValue(boogieVar, out res)) { Contract.Assert(res != null); return res; } } return null; } } ////////////////////////////////////////////////////////////////////////////////// private readonly VariableMapping/*!*/ UnboundVariables; private readonly VariableMapping/*!*/ BoundVariables; // used when translating the bodies of function expansions private readonly VariableMapping/*!*/ Formals; [ContractInvariantMethod] void ObjectInvairant() { Contract.Invariant(UnboundVariables != null); Contract.Invariant(BoundVariables != null); Contract.Invariant(Formals != null); } internal void PushBoundVariableScope() { BoundVariables.PushScope(); } internal void PopBoundVariableScope() { BoundVariables.PopScope(); } internal void PushFormalsScope() { Formals.PushScope(); } internal void PopFormalsScope() { Formals.PopScope(); } public VCExprVar BindVariable(Variable boogieVar) { Contract.Requires(boogieVar != null); Contract.Ensures(Contract.Result() != null); if (boogieVar is BoundVariable) { VCExprVar/*!*/ newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); BoundVariables.Bind((BoundVariable)boogieVar, newVar); return newVar; } else if (boogieVar is Formal) { VCExprVar/*!*/ newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); Formals.Bind((Formal)boogieVar, newVar); return newVar; } else { // only bound variables and formals are declared explicitly Contract.Assert(false); throw new cce.UnreachableException(); } } public VCExprVar LookupVariable(Variable boogieVar) { Contract.Requires(boogieVar != null); Contract.Ensures(Contract.Result() != null); BoundVariable bv = boogieVar as BoundVariable; if (bv != null) { return BoundVariables.Lookup(bv); } VCExprVar res; Formal fml = boogieVar as Formal; if (fml != null && Formals.TryGetValue(fml, out res)) return cce.NonNull(res); // global variables, local variables, incarnations, etc. are // bound the first time they occur if (!UnboundVariables.TryGetValue(boogieVar, out res)) { if (boogieVar is Constant) res = new VCExprConstant(boogieVar.Name, boogieVar.TypedIdent.Type); else res = new VCExprVar(boogieVar.Name, boogieVar.TypedIdent.Type); UnboundVariables.Bind(boogieVar, res); } return cce.NonNull(res); } /// /// Unlike LookupVariable, this method does not create a new variable mapping if none is /// found. Instead, this method returns null in such cases. Also, this method does not /// look for bound variables. /// /// /// public VCExprVar TryLookupVariable(Variable boogieVar) { Contract.Requires(boogieVar != null); VCExprVar res; Formal fml = boogieVar as Formal; if (fml != null && Formals.TryGetValue(fml, out res)) return cce.NonNull(res); if (UnboundVariables.TryGetValue(boogieVar, out res)) { return cce.NonNull(res); } return null; // not present } /////////////////////////////////////////////////////////////////////////////////// internal readonly VCGenerationOptions/*!*/ GenerationOptions; [ContractInvariantMethod] void ObjectInvarian() { Contract.Invariant(GenerationOptions != null); } /////////////////////////////////////////////////////////////////////////////////// public override Expr VisitLiteralExpr(LiteralExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Push(TranslateLiteralExpr(node)); return node; } private VCExpr TranslateLiteralExpr(LiteralExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); if (node.Val is bool) { bool b = (bool)node.Val; if (b) { return VCExpressionGenerator.True; } else { return VCExpressionGenerator.False; } } else if (node.Val is BigNum) { return Gen.Integer(node.asBigNum); } else if (node.Val is BigDec) { return Gen.Real(node.asBigDec); } else if (node.Val is BigFloat) { return Gen.Float(node.asBigFloat); } else if (node.Val is BvConst) { return Gen.Bitvector((BvConst)node.Val); } else { System.Diagnostics.Debug.Assert(false, "unknown kind of literal " + node.tok.ToString()); Contract.Assert(false); throw new cce.UnreachableException(); } } /////////////////////////////////////////////////////////////////////////////////// public override Expr VisitIdentifierExpr(IdentifierExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assume(node.Decl != null); // the expression has to be resolved Push(LookupVariable(node.Decl)); return node; } /////////////////////////////////////////////////////////////////////////////////// // Because of our scheme for numbering incarnations of variables, the pre-state // value of a variable x is always just "x". (The first update to it in a method // causes it to become "x0". So we just remove old expressions with a visitor // before transforming it into a VCExpr. public override Expr VisitOldExpr(OldExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } /////////////////////////////////////////////////////////////////////////////////// public override Expr VisitNAryExpr(NAryExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Push(TranslateNAryExpr(node)); return node; } public bool isPositiveContext = true; private VCExpr TranslateNAryExpr(NAryExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); bool flipContextForArg0 = false; if (node.Fun is UnaryOperator) { UnaryOperator oper = (UnaryOperator)node.Fun; if (oper.Op == UnaryOperator.Opcode.Not) flipContextForArg0 = true; } else if (node.Fun is BinaryOperator) { BinaryOperator oper = (BinaryOperator)node.Fun; if (oper.Op == BinaryOperator.Opcode.Imp) flipContextForArg0 = true; else if (oper.Op == BinaryOperator.Opcode.Iff) { Expr one = new NAryExpr(node.tok, new BinaryOperator(node.tok, BinaryOperator.Opcode.Imp), new List { node.Args[0], node.Args[1] }); Expr two = new NAryExpr(node.tok, new BinaryOperator(node.tok, BinaryOperator.Opcode.Imp), new List { node.Args[1], node.Args[0] }); NAryExpr cmpd = new NAryExpr(node.tok, new BinaryOperator(node.tok, BinaryOperator.Opcode.And), new List { one, two }); TypecheckingContext tc = new TypecheckingContext(null); cmpd.Typecheck(tc); return TranslateNAryExpr(cmpd); } } int n = node.Args.Count; List/*!*/ vcs = new List(n); for (int i = 0; i < n; i++) { if (i == 0 && flipContextForArg0) isPositiveContext = !isPositiveContext; vcs.Add(Translate(cce.NonNull(node.Args)[i])); if (i == 0 && flipContextForArg0) isPositiveContext = !isPositiveContext; } if (node.Type == null) { System.Console.WriteLine("*** type is null for {0}", node); Contract.Assert(false); throw new cce.UnreachableException(); } return IAppTranslator.Translate(node.Fun, node.Type, vcs, ToList(cce.NonNull(node.TypeParameters))); } private static List/*!*/ EMPTY_TYPE_LIST = new List(); [ContractInvariantMethod] void ObjectInvirant() { Contract.Invariant(EMPTY_TYPE_LIST != null); } private List/*!*/ ToList(TypeParamInstantiation insts) { Contract.Requires(insts != null); Contract.Ensures(cce.NonNullElements(Contract.Result>())); if (insts.FormalTypeParams.Count == 0) return EMPTY_TYPE_LIST; List/*!*/ typeArgs = new List(); foreach (TypeVariable/*!*/ var in insts.FormalTypeParams) { Contract.Assert(var != null); typeArgs.Add(insts[var]); } return typeArgs; } /////////////////////////////////////////////////////////////////////////////////// public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Push(TranslateQuantifierExpr(node)); return node; } public override Expr VisitExistsExpr(ExistsExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); node = (ExistsExpr)this.VisitQuantifierExpr(node); return node; } public override Expr VisitForallExpr(ForallExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); node = (ForallExpr)this.VisitQuantifierExpr(node); return node; } private VCExpr TranslateQuantifierExpr(QuantifierExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); List/*!*/ typeParams = new List(); foreach (TypeVariable/*!*/ v in node.TypeParameters) { Contract.Assert(v != null); typeParams.Add(v); } PushBoundVariableScope(); List/*!*/ boundVars = new List(); foreach (Variable/*!*/ v in node.Dummies) boundVars.Add(BindVariable(v)); try { List/*!*/ triggers = TranslateTriggers(node.Triggers); VCExpr/*!*/ body = Translate(node.Body); VCQuantifierInfos/*!*/ infos = GenerateQuantifierInfos(node); Quantifier quan; if (node is ForallExpr) quan = Quantifier.ALL; else if (node is ExistsExpr) quan = Quantifier.EX; else { Contract.Assert(false); throw new cce.UnreachableException(); } return Gen.Quantify(quan, typeParams, boundVars, triggers, infos, body); } finally { PopBoundVariableScope(); } } private List/*!*/ TranslateTriggers(Trigger node) { Contract.Ensures(cce.NonNullElements(Contract.Result>())); List/*!*/ res = new List(); Trigger curTrigger = node; while (curTrigger != null) { res.Add(Gen.Trigger(curTrigger.Pos, Translate(curTrigger.Tr))); curTrigger = curTrigger.Next; } return res; } private VCQuantifierInfos GenerateQuantifierInfos(QuantifierExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); string qid = getQidNameFromQKeyValue(node.Dummies, node.Attributes); return new VCQuantifierInfos(qid, node.SkolemId, false, node.Attributes); } private string getQidNameFromQKeyValue(List vars, QKeyValue attributes) { Contract.Requires(vars != null); // Check for a 'qid, name' pair in keyvalues string qid = QKeyValue.FindStringAttribute(attributes, "qid"); if (qid == null && vars.Count != 0) { // generate default name (line:column position in .bpl file) Variable v = vars[0]; Contract.Assert(v != null); // Rustan's claim! // Include the first 8 characters of the filename in QID (helpful in case we use /concat) // We limit it to 8, so the SX file doesn't grow too big, and who on earth would need // more than 8 characters in a filename anyways. int max = 8; StringBuilder buf = new StringBuilder(max + 20); string filename = v.tok.filename; if (filename == null) filename = "unknown"; for (int i = 0; i < filename.Length; ++i) { if (filename[i] == '/' || filename[i] == '\\') buf.Length = 0; if (buf.Length < max && char.IsLetterOrDigit(filename[i])) { if (buf.Length == 0 && char.IsDigit(filename[i])) { // Z3 does not like QID's to start with a digit, so we prepend another character buf.Append('_'); } buf.Append(filename[i]); } } buf.Append('.').Append(v.Line).Append(':').Append(v.Col); qid = buf.ToString(); } return qid; } /////////////////////////////////////////////////////////////////////////////////// public override Expr VisitBvExtractExpr(BvExtractExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Push(TranslateBvExtractExpr(node)); return node; } private VCExpr TranslateBvExtractExpr(BvExtractExpr node) { Contract.Requires(node != null); Contract.Requires((node.Start <= node.End)); Contract.Ensures(Contract.Result() != null); VCExpr/*!*/ bv = Translate(node.Bitvector); return Gen.BvExtract(bv, cce.NonNull(node.Bitvector.Type).BvBits, node.Start, node.End); } /////////////////////////////////////////////////////////////////////////////////// public override Expr VisitBvConcatExpr(BvConcatExpr node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Push(TranslateBvConcatExpr(node)); return node; } private VCExpr TranslateBvConcatExpr(BvConcatExpr node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); VCExpr/*!*/ bv0 = Translate(node.E0); VCExpr/*!*/ bv1 = Translate(node.E1); return Gen.BvConcat(bv0, bv1); } /////////////////////////////////////////////////////////////////////////////////// // all the other cases should never happen public override Cmd VisitAssertCmd(AssertCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitAssignCmd(AssignCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitAssumeCmd(AssumeCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override AtomicRE VisitAtomicRE(AtomicRE node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Axiom VisitAxiom(Axiom node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Type VisitBasicType(BasicType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Type VisitBvType(BvType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Block VisitBlock(Block node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public CodeExprConverter codeExprConverter = null; public void SetCodeExprConverter(CodeExprConverter f) { this.codeExprConverter = f; } public override Expr/*!*/ VisitCodeExpr(CodeExpr/*!*/ codeExpr) { //Contract.Requires(codeExpr != null); Contract.Ensures(Contract.Result() != null); Contract.Assume(codeExprConverter != null); Hashtable/**/ blockVariables = new Hashtable/**/(); List bindings = new List(); VCExpr e = codeExprConverter(codeExpr, blockVariables, bindings, isPositiveContext); Push(e); return codeExpr; } public override List VisitBlockSeq(List blockSeq) { //Contract.Requires(blockSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List/*!*/ VisitBlockList(List/*!*/ blocks) { //Contract.Requires(cce.NonNullElements(blocks)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); Contract.Assert(false); throw new cce.UnreachableException(); } public override BoundVariable VisitBoundVariable(BoundVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitCallCmd(CallCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitParCallCmd(ParCallCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List VisitCmdSeq(List cmdSeq) { //Contract.Requires(cmdSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Choice VisitChoice(Choice node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitCommentCmd(CommentCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Constant VisitConstant(Constant node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override CtorType VisitCtorType(CtorType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Declaration VisitDeclaration(Declaration node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List/*!*/ VisitDeclarationList(List/*!*/ declarationList) { //Contract.Requires(cce.NonNullElements(declarationList)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); Contract.Assert(false); throw new cce.UnreachableException(); } public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Requires VisitRequires(Requires @requires) { //Contract.Requires(@requires != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List VisitRequiresSeq(List requiresSeq) { //Contract.Requires(requiresSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Ensures VisitEnsures(Ensures @ensures) { //Contract.Requires(@ensures != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List VisitEnsuresSeq(List ensuresSeq) { //Contract.Requires(ensuresSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Formal VisitFormal(Formal node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Function VisitFunction(Function node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override GlobalVariable VisitGlobalVariable(GlobalVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override GotoCmd VisitGotoCmd(GotoCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitHavocCmd(HavocCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Implementation VisitImplementation(Implementation node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override LocalVariable VisitLocalVariable(LocalVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override MapType VisitMapType(MapType node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Procedure VisitProcedure(Procedure node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Program VisitProgram(Program node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitRE(RE node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List VisitRESeq(List reSeq) { //Contract.Requires(reSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override ReturnCmd VisitReturnCmd(ReturnCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override ReturnExprCmd VisitReturnExprCmd(ReturnExprCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Sequential VisitSequential(Sequential node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitStateCmd(StateCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override TransferCmd VisitTransferCmd(TransferCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Trigger VisitTrigger(Trigger node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Type VisitType(Type node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override TypedIdent VisitTypedIdent(TypedIdent node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Type VisitTypeSynonymAnnotation(TypeSynonymAnnotation node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Type VisitTypeVariable(TypeVariable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Variable VisitVariable(Variable node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override List VisitVariableSeq(List variableSeq) { //Contract.Requires(variableSeq != null); Contract.Ensures(Contract.Result>() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(false); throw new cce.UnreachableException(); } } ///////////////////////////////////////////////////////////////////////////////// public class IAppliableTranslator : IAppliableVisitor { private readonly Boogie2VCExprTranslator/*!*/ BaseTranslator; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(BaseTranslator != null); } private VCExpressionGenerator/*!*/ Gen { get { Contract.Ensures(Contract.Result() != null); return BaseTranslator.Gen; } } private VCGenerationOptions GenerationOptions { get { Contract.Ensures(Contract.Result() != null); return BaseTranslator.GenerationOptions; } } public IAppliableTranslator(Boogie2VCExprTranslator baseTranslator) { Contract.Requires(baseTranslator != null); this.BaseTranslator = baseTranslator; } /////////////////////////////////////////////////////////////////////////////// private List/*!*/ args = new List(); private List/*!*/ typeArgs = new List(); [ContractInvariantMethod] void ObjectInvarianet() { Contract.Invariant(args != null); Contract.Invariant(typeArgs != null); } public VCExpr Translate(IAppliable app, Type ty, List/*!*/ args, List/*!*/ typeArgs) { Contract.Requires(ty != null); Contract.Requires(app != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(args)); Contract.Ensures(Contract.Result() != null); List/*!*/ oldArgs = this.args; List/*!*/ oldTypeArgs = this.typeArgs; this.args = args; this.typeArgs = typeArgs; VCExpr/*!*/ result = app.Dispatch(this); this.args = oldArgs; this.typeArgs = oldTypeArgs; return result; } /////////////////////////////////////////////////////////////////////////////// public VCExpr Visit(UnaryOperator unaryOperator) { //Contract.Requires(unaryOperator != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(unaryOperator.Op == UnaryOperator.Opcode.Neg || unaryOperator.Op == UnaryOperator.Opcode.Not); Contract.Assert(this.args.Count == 1); if (unaryOperator.Op == UnaryOperator.Opcode.Neg) { VCExpr e = cce.NonNull(this.args[0]); if (cce.NonNull(e.Type).IsInt) { return Gen.Function(VCExpressionGenerator.SubIOp, Gen.Integer(BigNum.ZERO), e); } else {// if (cce.NonNull(e.Type).IsReal) { return Gen.Function(VCExpressionGenerator.SubROp, Gen.Real(BigDec.ZERO), e); } //else {//is float //return Gen.Function(VCExpressionGenerator.SubFOp, Gen.Float(BigFloat.ZERO(8, 23)), e); //} } else { return Gen.Not(this.args); } } public VCExpr Visit(BinaryOperator binaryOperator) { //Contract.Requires(binaryOperator != null); Contract.Ensures(Contract.Result() != null); return TranslateBinaryOperator(binaryOperator, this.args); } public VCExpr Visit(FunctionCall functionCall) { //Contract.Requires(functionCall != null); Contract.Ensures(Contract.Result() != null); return TranslateFunctionCall(functionCall, this.args, this.typeArgs); } public VCExpr Visit(MapSelect mapSelect) { //Contract.Requires(mapSelect != null); Contract.Ensures(Contract.Result() != null); return Gen.Select(this.args, this.typeArgs); } public VCExpr Visit(MapStore mapStore) { //Contract.Requires(mapStore != null); Contract.Ensures(Contract.Result() != null); return Gen.Store(this.args, this.typeArgs); } public VCExpr Visit(TypeCoercion typeCoercion) { //Contract.Requires(typeCoercion != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(this.args.Count == 1); return this.args[0]; } public VCExpr Visit(ArithmeticCoercion arithCoercion) { //Contract.Requires(arithCoercion != null); Contract.Ensures(Contract.Result() != null); Contract.Assert(this.args.Count == 1); switch (arithCoercion.Coercion) { case ArithmeticCoercion.CoercionType.ToInt: return Gen.Function(VCExpressionGenerator.ToIntOp, this.args); case ArithmeticCoercion.CoercionType.ToReal: return Gen.Function(VCExpressionGenerator.ToRealOp, this.args); default: Contract.Assert(false); return null; } } public VCExpr Visit(IfThenElse ite) { //Contract.Requires(ite != null); Contract.Ensures(Contract.Result() != null); return Gen.Function(VCExpressionGenerator.IfThenElseOp, this.args); } /////////////////////////////////////////////////////////////////////////////// private VCExpr TranslateBinaryOperator(BinaryOperator app, List/*!*/ args) { Contract.Requires(app != null); Contract.Requires(cce.NonNullElements(args)); Contract.Ensures(Contract.Result() != null); Contract.Assert(args.Count == 2); Type t = cce.NonNull(cce.NonNull(args[0]).Type); switch (app.Op) { case BinaryOperator.Opcode.Add: if (t.IsInt) { return Gen.Function(VCExpressionGenerator.AddIOp, args); } else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.AddROp, args); } else { //t is float return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "+"), args); } case BinaryOperator.Opcode.Sub: if (t.IsInt) { return Gen.Function(VCExpressionGenerator.SubIOp, args); } else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.SubROp, args); } else { //t is float return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "-"), args); } case BinaryOperator.Opcode.Mul: if (t.IsInt) { return Gen.Function(VCExpressionGenerator.MulIOp, args); } else if (t.IsReal) { return Gen.Function(VCExpressionGenerator.MulROp, args); } else { //t is float return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "*"), args); } case BinaryOperator.Opcode.Div: return Gen.Function(VCExpressionGenerator.DivIOp, args); case BinaryOperator.Opcode.Mod: return Gen.Function(VCExpressionGenerator.ModOp, args); case BinaryOperator.Opcode.RealDiv: if (t.IsFloat) { return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "/"), args); } VCExpr arg0 = cce.NonNull(args[0]); VCExpr arg1 = cce.NonNull(args[1]); if (cce.NonNull(arg0.Type).IsInt) { arg0 = Gen.Function(VCExpressionGenerator.ToRealOp, arg0); } if (cce.NonNull(arg1.Type).IsInt) { arg1 = Gen.Function(VCExpressionGenerator.ToRealOp, arg1); } return Gen.Function(VCExpressionGenerator.DivROp, arg0, arg1); case BinaryOperator.Opcode.Pow: return Gen.Function(VCExpressionGenerator.PowOp, args); case BinaryOperator.Opcode.Eq: case BinaryOperator.Opcode.Iff: // we don't distinguish between equality and equivalence at this point if (t.IsFloat) return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "=="), args); return Gen.Function(VCExpressionGenerator.EqOp, args); case BinaryOperator.Opcode.Neq: return Gen.Function(VCExpressionGenerator.NeqOp, args); case BinaryOperator.Opcode.Lt: if (t.IsFloat) return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "<"), args); return Gen.Function(VCExpressionGenerator.LtOp, args); case BinaryOperator.Opcode.Le: if (t.IsFloat) return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, "<="), args); return Gen.Function(VCExpressionGenerator.LeOp, args); case BinaryOperator.Opcode.Ge: if (t.IsFloat) return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, ">="), args); return Gen.Function(VCExpressionGenerator.GeOp, args); case BinaryOperator.Opcode.Gt: if (t.IsFloat) return Gen.Function(Gen.BinaryFloatOp(t.FloatExponent, t.FloatSignificand, ">"), args); return Gen.Function(VCExpressionGenerator.GtOp, args); case BinaryOperator.Opcode.Imp: return Gen.Function(VCExpressionGenerator.ImpliesOp, args); case BinaryOperator.Opcode.And: return Gen.Function(VCExpressionGenerator.AndOp, args); case BinaryOperator.Opcode.Or: return Gen.Function(VCExpressionGenerator.OrOp, args); case BinaryOperator.Opcode.Subtype: return Gen.Function(VCExpressionGenerator.SubtypeOp, args); default: Contract.Assert(false); throw new cce.UnreachableException(); // unexpected binary operator } } /////////////////////////////////////////////////////////////////////////////// private VCExpr/*!*/ TranslateFunctionCall(FunctionCall app, List/*!*/ args, List/*!*/ typeArgs) { Contract.Requires(cce.NonNullElements(args)); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(app != null); Contract.Requires((app.Func != null)); Contract.Ensures(Contract.Result() != null); // resolution must have happened VCExpr res = ApplyExpansion(app, args, typeArgs); if (res != null) return res; VCExprOp/*!*/ functionOp = Gen.BoogieFunctionOp(app.Func); return Gen.Function(functionOp, args, typeArgs); } private VCExpr ApplyExpansion(FunctionCall app, List/*!*/ args, List/*!*/ typeArgs) { Contract.Requires(app != null); Contract.Requires(cce.NonNullElements(args)); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Assert(app.Func != null); // resolution must have happened lock (app.Func) { if (app.Func.doingExpansion) { System.Console.WriteLine("*** detected expansion loop on {0}", app.Func); return null; } var exp = app.Func.Body; if (exp == null) return null; VCExpr/*!*/ translatedBody; VCExprSubstitution/*!*/ subst = new VCExprSubstitution(); try { BaseTranslator.PushFormalsScope(); BaseTranslator.PushBoundVariableScope(); app.Func.doingExpansion = true; // first bind the formals to VCExpr variables, which are later // substituted with the actual parameters var inParams = app.Func.InParams; for (int i = 0; i < inParams.Count; ++i) subst[BaseTranslator.BindVariable(inParams[i])] = args[i]; // recursively translate the body of the expansion translatedBody = BaseTranslator.Translate(exp); } finally { BaseTranslator.PopFormalsScope(); BaseTranslator.PopBoundVariableScope(); app.Func.doingExpansion = false; } // substitute the formals with the actual parameters in the body var tparms = app.Func.TypeParameters; Contract.Assert(typeArgs.Count == tparms.Count); for (int i = 0; i < typeArgs.Count; ++i) subst[tparms[i]] = typeArgs[i]; SubstitutingVCExprVisitor/*!*/ substituter = new SubstitutingVCExprVisitor(Gen); return substituter.Mutate(translatedBody, subst); } } } }