public override Expr VisitForallExpr(ForallExpr node) { Contract.Requires(node != null); if (_templates.ContainsKey(node)) { return(node); } _nestedBoundVariables.AddRange(node.Dummies); base.VisitForallExpr(node); var body = node.Body; var bodyTemplate = _templates[body]; var trigger = node.Triggers; var triggerNoBounds = trigger == null || !_templates[trigger].ContainsBoundVariables(); if (bodyTemplate is TemplateNoBoundVariables bt && triggerNoBounds) { var newBody = bt.GetReplacement(); var newTrigger = ReplacementTrigger(trigger); _templates[node] = new TemplateNoBoundVariables( new ForallExpr(node.tok, node.TypeParameters, node.Dummies, node.Attributes, newTrigger, newBody, node.Immutable) { Type = node.Type }); }
public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q) { // rewrite quantifier to avoid mathing loops // before: // assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; // after: // assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; substMap = new Dictionary <Expression, IdentifierExpr>(); usedMap = new Dictionary <Expression, IdentifierExpr>(); foreach (var m in q.LoopingMatches) { var e = m.OriginalExpr; if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e)) { foreach (var sub in e.SubExpressions) { if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub))) { IdentifierExpr ie; if (!substMap.TryGetValue(sub, out ie)) { var newBv = new BoundVar(sub.tok, "_t#" + substMap.Count, sub.Type); ie = new IdentifierExpr(sub.tok, newBv.Name); ie.Var = newBv; ie.Type = newBv.Type; substMap[sub] = ie; } } } } } var expr = (QuantifierExpr)q.quantifier; if (substMap.Count > 0) { var s = new Translator.ExprSubstituter(substMap); expr = s.Substitute(q.quantifier) as QuantifierExpr; } else { // make a copy of the expr if (expr is ForallExpr) { expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type }; } else { expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type }; } } return(expr); }
public override Expr VisitForallExpr(ForallExpr node) { if (GetReplacementVariable(node, out var variable)) { return(new IdentifierExpr(variable.tok, variable)); } return(base.VisitForallExpr(node)); }
// To support forall and exists we need to keep to track of their quantified // variables so we don't try to substitute them in VisitIdentifierExpr() public override Expr VisitForallExpr(ForallExpr node) { BoundVariables.UnionWith(node.Dummies); var toReturn = base.VisitForallExpr(node); BoundVariables.RemoveWhere(e => node.Dummies.Contains(e)); return(toReturn); }
public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q) { // rewrite quantifier to avoid matching loops // before: // assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; // after: // assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[j]; substMap = new List <Tuple <Expression, IdentifierExpr> >(); foreach (var m in q.LoopingMatches) { var e = m.OriginalExpr; if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e)) { foreach (var sub in e.SubExpressions) { if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub))) { var entry = substMap.Find(x => ExprExtensions.ExpressionEq(sub, x.Item1)); if (entry == null) { var newBv = new BoundVar(sub.tok, "_t#" + substMap.Count, sub.Type); var ie = new IdentifierExpr(sub.tok, newBv.Name); ie.Var = newBv; ie.Type = newBv.Type; substMap.Add(new Tuple <Expression, IdentifierExpr>(sub, ie)); } } } } } var expr = (QuantifierExpr)q.quantifier; if (substMap.Count > 0) { var s = new ExprSubstituter(substMap); expr = s.Substitute(q.quantifier) as QuantifierExpr; } else { // make a copy of the expr if (expr is ForallExpr) { expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds }; } else { expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds }; } } return(expr); }
public void CachedHashCodeForAllExpr() { var x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", BasicType.Int)); var y = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", BasicType.Int)); var body = Expr.Gt(new IdentifierExpr(Token.NoToken, x, /*immutable=*/true), new IdentifierExpr(Token.NoToken, y, /*immutable=*/true)); var forAll = new ForallExpr(Token.NoToken, new List<Variable>() {x, y}, body, /*immutable=*/ true); Assert.AreEqual(forAll.ComputeHashCode(), forAll.GetHashCode()); }
public void ProtectedForAllExprBody() { var x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", BasicType.Int)); var y = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "x", BasicType.Int)); var xId = new IdentifierExpr(Token.NoToken, x, /*immutable=*/true); var yId = new IdentifierExpr(Token.NoToken, y, /*immutable=*/true); var body = Expr.Gt(xId, yId); var forAll = new ForallExpr(Token.NoToken, new List<Variable>() {x, y}, body, /*immutable=*/true); // Changing the body of an immutable ForAllExpr should fail Assert.Throws(typeof(InvalidOperationException), () => forAll.Body = Expr.Lt(xId, yId)); }
public static Expr GetChild(this ForallExpr e, int number) { switch (number) { case 0: return(e.Body); default: throw new InvalidOperationException("ForallExpr only has one child"); } }
public static void SetChild(this ForallExpr e, int number, Expr NewChild) { switch (number) { case 0: e.Body = NewChild; return; default: throw new InvalidOperationException("ForallExpr only has one child"); } }
public override Expr VisitForallExpr(ForallExpr node) { var bodyCopy = this.Visit(node.Body) as Expr; Debug.Assert(bodyCopy != null); var freeVars = new List <Variable>(node.Dummies); var newTriggers = this.VisitTrigger(node.Triggers); var newNode = Builder.ForAll(freeVars, bodyCopy, newTriggers); Debug.Assert(newNode != null); return(newNode); }
public string GenerateConditionString(ForallExpr expression, IDictionary <string, string> rename) { StringBuilder bob = new StringBuilder(); bob.Append(expression.tok.val); bob.Append(" "); var boundVars = expression.BoundVars.Select(v => v.tok.val); bob.Append(String.Join(", ", boundVars)); bob.Append(" :: "); bob.Append(GenerateConditionString(expression.Term, rename)); return(bob.ToString()); }
public string GenerateString(ForallExpr expression) { StringBuilder bob = new StringBuilder(); bob.Append(expression.tok.val); bob.Append(" "); var boundVars = expression.BoundVars.Select(v => v.tok.val); bob.Append(String.Join(", ", boundVars)); bob.Append(" :: "); bob.Append(GenerateString(expression.Term)); return(bob.ToString()); }
public void SimpleForAll() { var boundVar = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "foo", Microsoft.Boogie.Type.Bool)); var id = new IdentifierExpr(Token.NoToken, boundVar); var forall = new ForallExpr(Token.NoToken, new List <Variable>() { boundVar }, id); var id2 = new IdentifierExpr(Token.NoToken, boundVar); var forall2 = new ForallExpr(Token.NoToken, new List <Variable>() { boundVar }, id2); Assert.AreNotSame(forall, forall2); // These are different references Assert.IsTrue(forall.Equals(forall2)); // These are "structurally equal" Assert.AreEqual(forall.GetHashCode(), forall2.GetHashCode()); // If the .Equals() is true then hash codes must be the same }
public Expr ForAll(IList <Variable> freeVars, Expr body, Trigger triggers = null) { if (!body.Type.IsBool) { throw new ExprTypeCheckException("body must be of type bool"); } if (freeVars.Count < 1) { throw new ArgumentException("ForAllExpr must have at least one free variable"); } TypeCheckTriggers(freeVars, body, triggers); // Should we check the free variables are actually used? This could be quite expensive to do! var result = new ForallExpr(Token.NoToken, new List <Variable>(freeVars), triggers, body, Immutable); result.Type = BasicType.Bool; return(result); }
public override Expr VisitForallExpr(ForallExpr node) { return(node); }
public static Node CreateFromExpr(Expr expr) { if (expr is NAryExpr) { NAryExpr nary = expr as NAryExpr; if (nary.Fun is IfThenElse) { Node one = CreateFromExpr(nary.Args[0]); Node two = CreateFromExpr(nary.Args[1]); Node three = CreateFromExpr(nary.Args[2]); Node parent = new TernaryNode(nary.Fun.FunctionName, one, two, three); one.parent = parent; two.parent = parent; three.parent = parent; return(parent); } else if (nary.Fun is BinaryOperator) { Node one = CreateFromExpr(nary.Args[0]); Node two = CreateFromExpr(nary.Args[1]); Node parent = new BinaryNode(nary.Fun.FunctionName, one, two); one.parent = parent; two.parent = parent; return(parent); } else if (nary.Fun is UnaryOperator) { Node one = CreateFromExpr(nary.Args[0]); UnaryNode parent = new UnaryNode(nary.Fun.FunctionName, one); one.parent = parent; return(parent); } else if (nary.Fun is FunctionCall) { FunctionCall call = nary.Fun as FunctionCall; if (nary.Args.Count == 1) { Node one = CreateFromExpr(nary.Args[0]); UnaryNode parent = new UnaryNode(nary.Fun.FunctionName, one); one.parent = parent; return(parent); } else if (nary.Args.Count == 2) { Node one = CreateFromExpr(nary.Args[0]); Node two = CreateFromExpr(nary.Args[1]); Node parent = new BinaryNode(call.FunctionName, one, two); one.parent = parent; two.parent = parent; return(parent); } else { Print.ExitMessage("Unhandled number of arguments in Boogie function call with function: " + nary.Fun.FunctionName); } } else if (nary.Fun is MapSelect) { List <Expr> indices = new List <Expr>(); while (true) { NAryExpr nary2 = nary.Args[0] as NAryExpr; Print.ConditionalExitMessage(nary.Args.Count == 2, "Map select has more than two arguments"); indices.Insert(0, nary.Args[1]); if (nary2 == null) { break; } else { nary = nary2; } } IdentifierExpr identifier = nary.Args[0] as IdentifierExpr; Node parent = new MapSymbolNode(identifier.Name); foreach (Expr index in indices) { Node child = CreateFromExpr(index); parent.Children.Add(child); child.parent = parent; } return(parent); } else { Print.ExitMessage("Unhandled Nary expression: " + nary.Fun.GetType().ToString()); } } else if (expr is IdentifierExpr) { IdentifierExpr identifier = expr as IdentifierExpr; return(new ScalarSymbolNode(identifier.Name, identifier.Type)); } else if (expr is LiteralExpr) { LiteralExpr literal = expr as LiteralExpr; if (literal.Val is BvConst) { BvConst bv = (BvConst)literal.Val; return(new LiteralNode(new BitVector(bv))); } else if (literal.Val is BigNum) { BigNum num = (BigNum)literal.Val; return(new LiteralNode(new BitVector(num.ToInt))); } else if (literal.Val is bool) { bool boolean = (bool)literal.Val; if (boolean) { return(new LiteralNode(BitVector.True)); } else { return(new LiteralNode(BitVector.False)); } } else { Print.ExitMessage("Unhandled literal expression: " + literal.ToString()); } } else if (expr is BvExtractExpr) { BvExtractExpr bvExtract = expr as BvExtractExpr; Node child = CreateFromExpr(bvExtract.Bitvector); Node parent = new BVExtractNode(child, bvExtract.End, bvExtract.Start); child.parent = parent; return(parent); } else if (expr is BvConcatExpr) { BvConcatExpr bvConcat = expr as BvConcatExpr; Node one = CreateFromExpr(bvConcat.E0); Node two = CreateFromExpr(bvConcat.E1); Node parent = new BVConcatenationNode(one, two); one.parent = parent; two.parent = parent; return(parent); } else if (expr is ForallExpr) { ForallExpr forall = expr as ForallExpr; Node one = CreateFromExpr(forall._Body); Node parent = new ForAllNode(one); one.parent = parent; return(parent); } Print.ExitMessage("Unhandled expression tree: " + expr.ToString() + " " + expr.Type.ToString()); return(null); }
private static bool ShallowEq(ForallExpr expr1, ForallExpr expr2) { return(true); }
// group split quantifier by what triggers they got, and merged them back into one quantifier. private void CombineSplitQuantifier() { if (quantifiers.Count > 1) { List <QuantifierGroup> groups = new List <QuantifierGroup>(); groups.Add(new QuantifierGroup(quantifiers[0], new List <ComprehensionExpr> { quantifiers[0].quantifier })); for (int i = 1; i < quantifiers.Count; i++) { bool found = false; for (int j = 0; j < groups.Count; j++) { if (HasSameTriggers(quantifiers[i], groups[j].quantifier)) { // belong to the same group groups[j].expressions.Add(quantifiers[i].quantifier); found = true; break; } } if (!found) { // start a new group groups.Add(new QuantifierGroup(quantifiers[i], new List <ComprehensionExpr> { quantifiers[i].quantifier })); } } if (groups.Count == quantifiers.Count) { // have the same number of splits, so no splits are combined. return; } // merge expressions in each group back to one quantifier. List <QuantifierWithTriggers> list = new List <QuantifierWithTriggers>(); List <Expression> splits = new List <Expression>(); foreach (var group in groups) { QuantifierWithTriggers q = group.quantifier; if (q.quantifier is ForallExpr) { ForallExpr quantifier = (ForallExpr)q.quantifier; Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.And, group.expressions); q.quantifier = new ForallExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds }; } else if (q.quantifier is ExistsExpr) { ExistsExpr quantifier = (ExistsExpr)q.quantifier; Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.Or, group.expressions); q.quantifier = new ExistsExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds }; } list.Add(q); splits.Add(q.quantifier); } this.quantifiers = list; Contract.Assert(this.expr is QuantifierExpr); // only QuantifierExpr has SplitQuantifier ((QuantifierExpr)this.expr).SplitQuantifier = splits; } }
public override List <Cmd> VisitCmdSeq(List <Cmd> cmdSeq) { List <Cmd> newCmdSeq = new List <Cmd>(); foreach (Cmd c in cmdSeq) { switch (Utils.getSlashVerifyCmdType(c)) { case SlashVerifyCmdType.Store8: case SlashVerifyCmdType.Store16: case SlashVerifyCmdType.Store32: case SlashVerifyCmdType.Store64: //mem := store(mem, y, e) { Tuple <Variable, Expr, Expr> storeArgs = Utils.getStoreArgs(c as AssignCmd); Expr store_addr = storeArgs.Item2; Expr store_value = storeArgs.Item3; Expr old_RSP = new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)); AssertCmd assertion; Func <int, Expr> OffsetExpr = delegate(int n) { LiteralExpr x = new LiteralExpr(Token.NoToken, BigNum.FromInt(Math.Abs(n)), 64); return(new NAryExpr(Token.NoToken, (n >= 0) ? new FunctionCall(plus_64) : new FunctionCall(minus_64), new List <Expr>() { storeArgs.Item2, x })); }; //Console.WriteLine("store to {0} at addr {1} with value {2}", storeArgs.Item1, storeArgs.Item2, storeArgs.Item3); int iterations = Utils.getSlashVerifyCmdType(c) == SlashVerifyCmdType.Store8 ? 1 : Utils.getSlashVerifyCmdType(c) == SlashVerifyCmdType.Store16 ? 2 : Utils.getSlashVerifyCmdType(c) == SlashVerifyCmdType.Store32 ? 4 : 8; //instrument assert ((addrInStack(PLUS_64(t_a, 0bv64)) && GE_64(PLUS_64(t_a, 0bv64), old(RSP))) ==> // writable(mem,PLUS_64(t_a, 0bv64)) || writable(mem,MINUS_64(t_a, 8bv64))) && (addrInBitmap(PLUS_64(t_a, 0bv64)) ==> // LT_64(largestAddrAffected_8(mem, PLUS_64(t_a, 0bv64), t_v[8:0]), old(RSP - 8))); Expr is_checkworthy_store = Expr.False; foreach (int iter in new List <int>() { 0, iterations - 1 }.Distinct()) //disjunction over a, a+n-1 { Expr addr_in_stack = new NAryExpr(Token.NoToken, new FunctionCall(addrInStack), new List <Expr>() { OffsetExpr(iter) }); Expr addr_in_parent_frame = new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(iter), old_RSP }); Expr addr_not_in_backing_space = Expr.Not(Expr.And( new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(iter), new NAryExpr(Token.NoToken, new FunctionCall(plus_64), new List <Expr>() { old_RSP, new LiteralExpr(Token.NoToken, BigNum.FromInt(8), 64) }) }), new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { OffsetExpr(iter), new NAryExpr(Token.NoToken, new FunctionCall(plus_64), new List <Expr>() { old_RSP, new LiteralExpr(Token.NoToken, BigNum.FromInt(40), 64) }) }))); is_checkworthy_store = Expr.Or(is_checkworthy_store, Expr.And(addr_in_stack, Expr.And(addr_not_in_backing_space, addr_in_parent_frame))); } //Fix for the padding issue. Enough to check writability of (addr + 0). It's an invariant that /guard:cfw maintains Expr is_writable = new NAryExpr(Token.NoToken, new FunctionCall(writable), new List <Expr>() { new IdentifierExpr(Token.NoToken, mem_bitmap), OffsetExpr(0) }); Expr check_for_stack_store = Expr.Imp(is_checkworthy_store, is_writable); assertion = new AssertCmd(Token.NoToken, check_for_stack_store); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, Utils.getSlashVerifyCmdType(c)); for (int iter = 0; iter < iterations; iter++) { Expr addr_in_bitmap = new NAryExpr(Token.NoToken, new FunctionCall(addrInBitmap), new List <Expr>() { OffsetExpr(iter) }); Expr largest_addr_affected = new NAryExpr(Token.NoToken, new FunctionCall(largestAddrAffected_8), new List <Expr>() { new IdentifierExpr(Token.NoToken, mem_bitmap), OffsetExpr(iter), new BvExtractExpr(Token.NoToken, store_value, 8 * (iter + 1), 8 * iter) }); //Expr addr_in_own_frame = new NAryExpr(Token.NoToken, new FunctionCall(lt_64), // new List<Expr>() { largest_addr_affected, old_RSP }); //Not using this because of padding issue Expr largest_allowed_address = new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { old_RSP, new LiteralExpr(Token.NoToken, BigNum.FromInt(8), 64) }); Expr addr_in_own_frame = new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { largest_addr_affected, largest_allowed_address }); if (this.bound_stacksize_option) { Utils.Assert(this.bound_stacksize_offset % 8 == 0, "Need stack size estimate to be a multiple of 8"); Expr smallest_addr_affected = new NAryExpr(Token.NoToken, new FunctionCall(smallestAddrAffected_8), new List <Expr>() { new IdentifierExpr(Token.NoToken, mem_bitmap), OffsetExpr(iter), new BvExtractExpr(Token.NoToken, store_value, 8 * (iter + 1), 8 * iter) }); Expr smallest_allowed_address = new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { old_RSP, new LiteralExpr(Token.NoToken, BigNum.FromInt(this.bound_stacksize_offset), 64) }); addr_in_own_frame = Expr.And(addr_in_own_frame, new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { smallest_addr_affected, smallest_allowed_address })); } Expr any_addr_affected = new NAryExpr(Token.NoToken, new FunctionCall(anyAddrAffected_8), new List <Expr>() { new IdentifierExpr(Token.NoToken, mem_bitmap), OffsetExpr(iter), new BvExtractExpr(Token.NoToken, store_value, 8 * (iter + 1), 8 * iter) }); Expr value_not_zero = Expr.Neq(new BvExtractExpr(Token.NoToken, store_value, 8 * (iter + 1), 8 * iter), new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 8)); Expr check_for_bitmap_store = Expr.Imp(Expr.And(Expr.And(addr_in_bitmap, any_addr_affected), value_not_zero), addr_in_own_frame); assertion = new AssertCmd(Token.NoToken, check_for_bitmap_store); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, Utils.getSlashVerifyCmdType(c)); } if (Options.confidentiality) { Expr addr_in_U = Expr.And( Expr.And( new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(0), new IdentifierExpr(Token.NoToken, this.stack_low) }), new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { OffsetExpr(0), new IdentifierExpr(Token.NoToken, this.bitmap_high) })), Expr.And( new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(iterations - 1), new IdentifierExpr(Token.NoToken, this.stack_low) }), new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { OffsetExpr(iterations - 1), new IdentifierExpr(Token.NoToken, this.bitmap_high) })) ); Expr _data_low = new LiteralExpr(Token.NoToken, BigNum.FromInt(Int32.Parse(Options.dataLow.ToUpper(), System.Globalization.NumberStyles.HexNumber)), 64); Expr _data_high = new LiteralExpr(Token.NoToken, BigNum.FromInt(Int32.Parse(Options.dataHigh.ToUpper(), System.Globalization.NumberStyles.HexNumber)), 64); Expr addr_in_Data = Expr.And( Expr.And( new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(0), _data_low }), new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { OffsetExpr(0), _data_high })), Expr.And( new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { OffsetExpr(iterations - 1), _data_low }), new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { OffsetExpr(iterations - 1), _data_high })) ); assertion = new AssertCmd(Token.NoToken, Expr.Or(addr_in_U, addr_in_Data)); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, Utils.getSlashVerifyCmdType(c)); } break; } case SlashVerifyCmdType.RepStosB: //x := REP_STOSB(mem, e1, e2, e3) { //TODO: might want to assert that it writes to the bitmap //if its writing zeros to bitmap, we dont need to assert anything break; } case SlashVerifyCmdType.SetRSP: { Expr alignment = Expr.Eq(new BvExtractExpr(Token.NoToken, (c as AssignCmd).Rhss[0], 3, 0), new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 3)); Expr le_old_RSP = new NAryExpr(Token.NoToken, new FunctionCall(le_64), new List <Expr>() { (c as AssignCmd).Rhss[0], new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)) }); AssertCmd assertion = new AssertCmd(Token.NoToken, Expr.And(alignment, le_old_RSP)); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.SetRSP); break; } case SlashVerifyCmdType.Ret: { foreach (AssertCmd a in RemoteTransferAssertions()) { newCmdSeq.Add(a); VCSplitter.Instance.RecordAssertion(this.current_label, c, a, SlashVerifyCmdType.Ret); } break; } case SlashVerifyCmdType.Call: { AssertCmd assertion; string attribute_calltarget = QKeyValue.FindStringAttribute((c as AssertCmd).Attributes, "SlashVerifyCallTarget"); Utils.Assert(attribute_calltarget != null, "Expected SlashVerifyCallTarget attribute on call"); //assert policy(target); Expr is_policy; if (attribute_calltarget.Substring(0, 2).Equals("0x")) { int target = Int32.Parse(attribute_calltarget.ToUpper().Substring(2), System.Globalization.NumberStyles.HexNumber); is_policy = new NAryExpr(Token.NoToken, new FunctionCall(policy), new List <Expr>() { new LiteralExpr(Token.NoToken, BigNum.FromInt(target), 64) }); } else { //indirect call e.g. call rax //first find which register GlobalVariable target = this.globals.FirstOrDefault(v => v.Name.Equals(attribute_calltarget)); Utils.Assert(target != null, "Could not find " + attribute_calltarget); is_policy = new NAryExpr(Token.NoToken, new FunctionCall(policy), new List <Expr>() { new IdentifierExpr(Token.NoToken, target) }); } if (!Options.disablePolicyChecking) { assertion = new AssertCmd(Token.NoToken, is_policy); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.Call); } if (!this.bound_stacksize_option) { //forall i. i < (rsp - 8) ==> ¬writable(mem,i) //rsp - 8 holds return address, and everything below that must start off as non writable BoundVariable i = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "i", this.mem.TypedIdent.Type.AsMap.Arguments[0])); NAryExpr in_local_frame = new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, i), new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, RSP), new LiteralExpr(Token.NoToken, BigNum.FromInt(8), 64) }) }); NAryExpr in_stack = new NAryExpr(Token.NoToken, new FunctionCall(addrInStack), new List <Expr>() { new IdentifierExpr(Token.NoToken, i) }); Expr not_writable = Expr.Not(new NAryExpr(Token.NoToken, new FunctionCall(writable), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_bitmap), new IdentifierExpr(Token.NoToken, i) })); Expr assert_mem_false_expr = new ForallExpr(Token.NoToken, new List <Variable>() { i }, Expr.Imp(Expr.And(in_stack, in_local_frame), not_writable)); assertion = new AssertCmd(Token.NoToken, assert_mem_false_expr); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.Call); //assert !writable(mem, rsp-8) not_writable = Expr.Not(new NAryExpr(Token.NoToken, new FunctionCall(writable), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_bitmap), new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, RSP), new LiteralExpr(Token.NoToken, BigNum.FromInt(8), 64) }) })); assertion = new AssertCmd(Token.NoToken, not_writable); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.Call); } else { //assert that RSP is not lower than bound_stacksize_offset. if RSP has not gotten lower, than we know everything is writable below Expr smallest_allowed_address = new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)), new LiteralExpr(Token.NoToken, BigNum.FromInt(this.bound_stacksize_offset), 64) }); NAryExpr rsp_in_local_frame = new NAryExpr(Token.NoToken, new FunctionCall(le_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, RSP), smallest_allowed_address }); assertion = new AssertCmd(Token.NoToken, rsp_in_local_frame); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.Call); } //assert RSP <= (old(RSP) - 32) NAryExpr stack_backing_space = new NAryExpr(Token.NoToken, new FunctionCall(le_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, RSP), new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)), new LiteralExpr(Token.NoToken, BigNum.FromInt(32), 64) }) }); assertion = new AssertCmd(Token.NoToken, stack_backing_space); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.Call); break; } case SlashVerifyCmdType.RemoteJmp: case SlashVerifyCmdType.RemoteIndirectJmp: { //assert policy(target); Expr is_policy = Expr.False; if (Utils.getSlashVerifyCmdType(c) == SlashVerifyCmdType.RemoteJmp) { string attribute_jmptarget = QKeyValue.FindStringAttribute((c as AssertCmd).Attributes, "SlashVerifyJmpTarget"); Utils.Assert(attribute_jmptarget != null, "Expected SlashVerifyJmpTarget attribute on jmp"); int target = Int32.Parse(attribute_jmptarget.ToUpper().Substring(2), System.Globalization.NumberStyles.HexNumber); is_policy = new NAryExpr(Token.NoToken, new FunctionCall(policy), new List <Expr>() { new LiteralExpr(Token.NoToken, BigNum.FromInt(target), 64) }); } else if (Utils.getSlashVerifyCmdType(c) == SlashVerifyCmdType.RemoteIndirectJmp) { string attribute_jmpregister = QKeyValue.FindStringAttribute((c as AssertCmd).Attributes, "SlashVerifyJmpRegister"); Utils.Assert(attribute_jmpregister != null, "Exprected jmp register annotation on indirect jump"); GlobalVariable global_register = this.globals.FirstOrDefault(x => x.Name.Equals(attribute_jmpregister)); Utils.Assert(global_register != null, "Could not find global variable " + attribute_jmpregister); is_policy = new NAryExpr(Token.NoToken, new FunctionCall(policy), new List <Expr>() { new IdentifierExpr(Token.NoToken, global_register) }); } AssertCmd assertion = new AssertCmd(Token.NoToken, is_policy); newCmdSeq.Add(assertion); VCSplitter.Instance.RecordAssertion(this.current_label, c, assertion, SlashVerifyCmdType.RemoteJmp); foreach (AssertCmd a in RemoteTransferAssertions()) { newCmdSeq.Add(a); VCSplitter.Instance.RecordAssertion(this.current_label, c, a, SlashVerifyCmdType.RemoteJmp); } break; } } //The assert gets placed prior to the original command newCmdSeq.Add(c); } return(base.VisitCmdSeq(newCmdSeq)); }
public virtual void Visit(ForallExpr forAllExpression) { VisitNullableAttributes(forAllExpression.Attributes); VisitNullableExpression(forAllExpression.Range); Visit(forAllExpression.Term); }
//assertions for remote jumps and return instructions public List <AssertCmd> RemoteTransferAssertions() { List <AssertCmd> assertions = new List <AssertCmd>(); if (this.bound_stacksize_option && Options.instantiateQuantifiers) //can only instantiate quantifiers on bounded { Expr instantiation = Expr.True; int addr_offset = 8; while (addr_offset <= (this.bound_stacksize_offset)) { Expr addr = new NAryExpr(Token.NoToken, new FunctionCall(this.minus_64), new List <Expr>() { new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)), new LiteralExpr(Token.NoToken, BigNum.FromInt(addr_offset), 64) }); Expr addr_not_writable = Expr.Not(new NAryExpr(Token.NoToken, new FunctionCall(writable), new List <Expr>() { new IdentifierExpr(Token.NoToken, mem_bitmap), addr })); //instantiation = Expr.And(instantiation, addr_not_writable); Expr precondition = Expr.And(Expr.Eq(new BvExtractExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP), 3, 0), new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 3)), Expr.Eq(new IdentifierExpr(Token.NoToken, RSP), new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)))); assertions.Add(new AssertCmd(Token.NoToken, Expr.Imp(precondition, addr_not_writable), new QKeyValue(Token.NoToken, "return_instrumentation", new List <object> { addr }, null))); addr_offset += 8; } } else { //forall i. i < old(rsp) && i[3:0] == 0bv3 ==> ¬writable(mem,i) BoundVariable i = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "i", this.mem.TypedIdent.Type.AsMap.Arguments[0])); Expr in_local_frame = new NAryExpr(Token.NoToken, new FunctionCall(lt_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, i), new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)) }); if (this.bound_stacksize_option) { Expr smallest_allowed_address = new NAryExpr(Token.NoToken, new FunctionCall(minus_64), new List <Expr>() { new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP)), new LiteralExpr(Token.NoToken, BigNum.FromInt(this.bound_stacksize_offset), 64) }); in_local_frame = Expr.And(in_local_frame, new NAryExpr(Token.NoToken, new FunctionCall(ge_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, i), smallest_allowed_address })); } NAryExpr in_stack = new NAryExpr(Token.NoToken, new FunctionCall(addrInStack), new List <Expr>() { new IdentifierExpr(Token.NoToken, i) }); Expr aligned = Expr.Eq(new BvExtractExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, i), 3, 0), new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 3)); Expr not_writable = Expr.Not(new NAryExpr(Token.NoToken, new FunctionCall(writable), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_bitmap), new IdentifierExpr(Token.NoToken, i) })); Expr assert_mem_false_expr = new ForallExpr(Token.NoToken, new List <Variable>() { i }, Expr.Imp(Expr.And(Expr.And(in_local_frame, in_stack), aligned), not_writable)); assertions.Add(new AssertCmd(Token.NoToken, assert_mem_false_expr)); } //rsp == old(rsp) assertions.Add(new AssertCmd(Token.NoToken, Expr.Eq(new IdentifierExpr(Token.NoToken, RSP), new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, RSP))))); return(assertions); }
public Expr VisitForallExpr(ForallExpr e) { return(PrintQuantifierExpr(e)); }
public override Expr VisitForallExpr(ForallExpr node) { add(node); return(base.VisitForallExpr(node)); }
public static Expr EmitEq(IdentifierExpr leftVar, IdentifierExpr rightVar, HashSet <Variable> ignoreSet) { // just blocking poly map for now - hemr if (!(leftVar.Decl.TypedIdent.Type is MapType || leftVar.Decl.TypedIdent.Type is TypeSynonymAnnotation)) { return(Expr.Eq(leftVar, rightVar)); } if (leftVar.Decl.TypedIdent.Type is TypeSynonymAnnotation) { var l = leftVar.Decl.TypedIdent.Type as TypeSynonymAnnotation; System.Diagnostics.Debug.Assert(!l.IsMap, "only handle non map typesynonymAnnotations, found " + l); return(Expr.Eq(leftVar, rightVar)); } List <Variable> bound = null; BoundVariable[] bvs = new BoundVariable[leftVar.Decl.TypedIdent.Type.AsMap.Arguments.Count]; int i = 0; string polyMapName = ""; foreach (Microsoft.Boogie.Type ts in leftVar.Decl.TypedIdent.Type.AsMap.Arguments) { if (leftVar.Decl.TypedIdent.Type is TypeSynonymAnnotation) { int index = 0; index = ts.ToString().IndexOf(" "); if (index >= 0) { polyMapName = ts.ToString().Substring(index + 1); } } bound = new List <Variable>(); var x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "_x" + i, ts)); // bound.Add(x); bvs[i] = x; i++; } //var bound = new List<Variable>(); //var x = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "_x", leftVar.Decl.TypedIdent.Type.AsMap.Arguments[0])); //bound.Add(x); //var lhs = SelectExpr(leftVar, Expr.Ident(x).); //var rhs = SelectExpr(rightVar, Expr.Ident(x)); IdentifierExpr[] idenExprs = new IdentifierExpr[bvs.Length]; for (int j = 0; j < bvs.Length; j++) { BoundVariable bv = bvs[j]; idenExprs[j] = Expr.Ident(bv); } var lhs = SelectExpr(leftVar, idenExprs); var rhs = SelectExpr(rightVar, idenExprs); bound = new List <Variable>(bvs); if (!polyMapName.Equals("")) { var forall = new ForallExpr(Token.NoToken, new List <TypeVariable>(new TypeVariable[] { new TypeVariable(Token.NoToken, polyMapName) }), bound, Expr.Eq(lhs, rhs)); //var forall2 = new ForallExpr(Token.NoToken, new List<TypeVariable>(new TypeVariable(Token.NoToken, polyMapName)), bound, Expr.Eq(lhs, rhs)); //return Expr.Or(Expr.Eq(leftVar, rightVar), forall); // as mentioned... blocking poly maps for now - hemr return(Expr.Eq(leftVar, rightVar)); } else { return(Expr.Or(Expr.Eq(leftVar, rightVar), new ForallExpr(Token.NoToken, bound, Expr.Eq(lhs, rhs)))); } //bound = new List<Variable>(bvs); //return Expr.Or(Expr.Eq(leftVar, rightVar), new ForallExpr(Token.NoToken, bound, Expr.Eq(lhs, rhs))); //return Expr.True; }
public override List <Cmd> VisitCmdSeq(List <Cmd> cmdSeq) { List <Cmd> newCmdSeq = new List <Cmd>(); if (this.currentLabel == this.memCheckpointLabel) { //mem_oldbitmap := mem AssignCmd ac = new AssignCmd(Token.NoToken, new List <AssignLhs>() { new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, this.mem_oldbitmap)) }, new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_bitmap) }); newCmdSeq.Add(ac); } else if (this.loopHeaderLabels.Contains(this.currentLabel)) { //assert (forall i: bv64 :: addrInBitmap(i) ==> mem[i] == mem_oldbitmap[i]); BoundVariable i = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, "i", this.mem.TypedIdent.Type.AsMap.Arguments[0])); Expr in_bitmap = new NAryExpr(Token.NoToken, new FunctionCall(this.addrInBitmap), new List <Expr>() { new IdentifierExpr(Token.NoToken, i) }); Expr assert_expr; Expr mem_bitmap_of_i = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_bitmap), new IdentifierExpr(Token.NoToken, i) }); Expr mem_oldbitmap_of_i = new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem_oldbitmap), new IdentifierExpr(Token.NoToken, i) }); assert_expr = new ForallExpr(Token.NoToken, new List <Variable>() { i }, Expr.Imp(in_bitmap, Expr.Eq(mem_bitmap_of_i, mem_oldbitmap_of_i))); //for Houdini Constant existential = this.existentials.Dequeue(); assert_expr = Expr.Imp(new IdentifierExpr(Token.NoToken, existential), assert_expr); newCmdSeq.Add(new AssertCmd(Token.NoToken, assert_expr)); //assert (LOAD_LE_64(mem, _guard_writeTable_ptr) == _bitmap_low); Expr load_mem_guardptr = new NAryExpr(Token.NoToken, new FunctionCall(this.load_64), new List <Expr>() { new IdentifierExpr(Token.NoToken, this.mem), new IdentifierExpr(Token.NoToken, this._guard_writeTable_ptr) }); assert_expr = Expr.Eq(load_mem_guardptr, new IdentifierExpr(Token.NoToken, _bitmap_low)); //for Houdini existential = this.existentials.Dequeue(); assert_expr = Expr.Imp(new IdentifierExpr(Token.NoToken, existential), assert_expr); newCmdSeq.Add(new AssertCmd(Token.NoToken, assert_expr)); } newCmdSeq.AddRange(cmdSeq); return(base.VisitCmdSeq(newCmdSeq)); }
public override Expr VisitForallExpr(ForallExpr node) { return(base.VisitForallExpr((ForallExpr)node.Clone())); }
public override Expression Substitute(Expression expr) { if (TryGetExprSubst(expr, out var ie)) { Contract.Assert(ie != null); return(ie); } if (expr is QuantifierExpr e) { var newAttrs = SubstAttributes(e.Attributes); var newRange = e.Range == null ? null : Substitute(e.Range); var newTerm = Substitute(e.Term); var newBounds = SubstituteBoundedPoolList(e.Bounds); if (newAttrs == e.Attributes && newRange == e.Range && newTerm == e.Term && newBounds == e.Bounds) { return(e); } var newBoundVars = new List <BoundVar>(e.BoundVars); if (newBounds == null) { newBounds = new List <ComprehensionExpr.BoundedPool>(); } else if (newBounds == e.Bounds) { // create a new list with the same elements, since the .Add operations below would otherwise add elements to the original e.Bounds newBounds = new List <ComprehensionExpr.BoundedPool>(newBounds); } // conjoin all the new equalities to the range of the quantifier foreach (var entry in usedSubstMap) { var eq = new BinaryExpr(e.tok, BinaryExpr.ResolvedOpcode.EqCommon, entry.Item2, entry.Item1); newRange = newRange == null ? eq : new BinaryExpr(e.tok, BinaryExpr.ResolvedOpcode.And, eq, newRange); newBoundVars.Add((BoundVar)entry.Item2.Var); newBounds.Add(new ComprehensionExpr.ExactBoundedPool(entry.Item1)); } QuantifierExpr newExpr; if (expr is ForallExpr) { newExpr = new ForallExpr(e.tok, e.TypeArgs, newBoundVars, newRange, newTerm, newAttrs) { Bounds = newBounds }; } else { Contract.Assert(expr is ExistsExpr); newExpr = new ExistsExpr(e.tok, e.TypeArgs, newBoundVars, newRange, newTerm, newAttrs) { Bounds = newBounds }; } usedSubstMap.Clear(); newExpr.Type = expr.Type; return(newExpr); } return(base.Substitute(expr)); }
public RtlExp GhostExpressionRec(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false) { Util.Assert(!isPrinting); exp = GetExp(exp); StmtExpr stmtExpr = exp as StmtExpr; IdentifierExpr idExp = exp as IdentifierExpr; LiteralExpr literal = exp as LiteralExpr; BinaryExpr binary = exp as BinaryExpr; UnaryExpr unary = exp as UnaryExpr; ITEExpr ite = exp as ITEExpr; ExistsExpr existsExp = exp as ExistsExpr; ForallExpr forallExp = exp as ForallExpr; LetExpr letExp = exp as LetExpr; MatchExpr matchExp = exp as MatchExpr; OldExpr oldExp = exp as OldExpr; FreshExpr freshExp = exp as FreshExpr; FunctionCallExpr funCall = exp as FunctionCallExpr; DatatypeValue dataVal = exp as DatatypeValue; FieldSelectExpr fieldSelect = exp as FieldSelectExpr; SeqSelectExpr seqSelect = exp as SeqSelectExpr; SeqUpdateExpr seqUpdate = exp as SeqUpdateExpr; SeqDisplayExpr seqDisplay = exp as SeqDisplayExpr; Func <Expression, RtlExp> G = e => GhostExpression(e, inRecSpec, inRequiresOrOld); if (stmtExpr != null) { if (stmtExprEnabled) { if (ignoreStmtExpr == 0) { AddGhostStatement(stmtExpr.S); } return(G(stmtExpr.E)); } else { throw new Exception("not implemented: cannot handle statement expression here"); } } else if (idExp != null) { return(AsVar(idExp)); } else if (literal != null && literal.Value is BigInteger) { return(new RtlInt((BigInteger)(literal.Value))); } else if (literal != null && literal.Value is bool) { return(new RtlLiteral((bool)(literal.Value) ? "true" : "false")); } else if (literal != null && literal.Value == null) { return(new RtlLiteral("ArrayOfInt(0 - 1, NO_ABS)")); } else if (literal != null && literal.Value is Microsoft.Basetypes.BigDec) { return(new RtlLiteral(((Microsoft.Basetypes.BigDec)literal.Value).ToDecimalString())); } else if (binary != null) { string op = null; string internalOp = null; CompileFunction compileFunction = this as CompileFunction; string thisFuncName = (compileFunction == null) ? null : compileFunction.function.Name; switch (binary.ResolvedOp) { case BinaryExpr.ResolvedOpcode.SeqEq: return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"), new RtlExp[] { G(binary.E0), G(binary.E1) })); case BinaryExpr.ResolvedOpcode.SeqNeq: return(new RtlLiteral("(!" + new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"), new RtlExp[] { G(binary.E0), G(binary.E1) }) + ")")); case BinaryExpr.ResolvedOpcode.Concat: return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.Type), "Seq_Append"), new RtlExp[] { G(binary.E0), G(binary.E1) })); } if (binary.Op == BinaryExpr.Opcode.Exp) { binary = new BinaryExpr(binary.tok, BinaryExpr.Opcode.Imp, binary.E0, binary.E1); } switch (binary.Op) { case BinaryExpr.Opcode.Disjoint: case BinaryExpr.Opcode.In: case BinaryExpr.Opcode.NotIn: throw new Exception("not implemented: binary operator '" + BinaryExpr.OpcodeString(binary.Op) + "'"); } if (AppType(binary.E0.Type) is IntType && AppType(binary.E1.Type) is IntType) { switch (binary.Op) { case BinaryExpr.Opcode.Le: internalOp = "INTERNAL_le_boogie"; break; case BinaryExpr.Opcode.Lt: internalOp = "INTERNAL_lt_boogie"; break; case BinaryExpr.Opcode.Ge: internalOp = "INTERNAL_ge_boogie"; break; case BinaryExpr.Opcode.Gt: internalOp = "INTERNAL_gt_boogie"; break; case BinaryExpr.Opcode.Add: internalOp = "INTERNAL_add_boogie"; break; case BinaryExpr.Opcode.Sub: internalOp = "INTERNAL_sub_boogie"; break; case BinaryExpr.Opcode.Mul: op = "*"; if (thisFuncName != "INTERNAL_mul") { internalOp = FunName("INTERNAL__mul"); } break; case BinaryExpr.Opcode.Div: op = "div"; if (thisFuncName != "INTERNAL_div") { internalOp = FunName("INTERNAL__div"); } break; case BinaryExpr.Opcode.Mod: op = "mod"; if (thisFuncName != "INTERNAL_mod") { internalOp = FunName("INTERNAL__mod"); } break; default: op = BinaryExpr.OpcodeString(binary.Op); break; } } else { op = BinaryExpr.OpcodeString(binary.Op); } if (internalOp == null) { return(new RtlBinary(op, G(binary.E0), G(binary.E1))); } else { return(new RtlApply(internalOp, new RtlExp[] { G(binary.E0), G(binary.E1) })); } } else if (unary != null && unary.Op == UnaryExpr.Opcode.Not) { return(new RtlLiteral("(!(" + G(unary.E) + "))")); } else if (unary != null && unary.Op == UnaryExpr.Opcode.SeqLength) { return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(unary.E.Type), "Seq_Length"), new RtlExp[] { G(unary.E) })); } else if (ite != null) { return(GhostIfThenElse(G(ite.Test), () => G(ite.Thn), () => G(ite.Els))); } else if (funCall != null) { switch (funCall.Function.Name) { case "left": case "right": case "relation": case "public": Util.Assert(funCall.Args.Count == 1); return(new RtlApply(funCall.Function.Name, new RtlExp[] { G(funCall.Args[0]) })); case "sizeof": Util.Assert(funCall.Args.Count == 1); return(new RtlApply(funCall.Function.Name + "##" + TypeString(AppType(funCall.Args[0].Type)), new RtlExp[] { G(funCall.Args[0]) })); case "INTERNAL_add_raw": Util.Assert(funCall.Args.Count == 2); return(new RtlBinary("+", G(funCall.Args[0]), G(funCall.Args[1]))); case "INTERNAL_sub_raw": Util.Assert(funCall.Args.Count == 2); return(new RtlBinary("-", G(funCall.Args[0]), G(funCall.Args[1]))); case "IntToReal": Util.Assert(funCall.Args.Count == 1); return(new RtlApply("real", new RtlExp[] { G(funCall.Args[0]) })); case "RealToInt": Util.Assert(funCall.Args.Count == 1); return(new RtlApply("int", new RtlExp[] { G(funCall.Args[0]) })); } TypeApply app = dafnySpec.Compile_Function(funCall.Function, funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))); string name = FunName(SimpleName(app.AppName())); string fullName = FunName(SimpleName(app.AppFullName())); List <RtlExp> rtlArgs = funCall.Args.Select(G).ToList(); List <RtlExp> rtlReads = funCall.Function.Reads.Where(e => e.Field != null).ToList() .ConvertAll(e => (RtlExp) new RtlVar( GhostVar(e.FieldName), e.Field.IsGhost, AppType(e.Field.Type))); rtlArgs = rtlReads.Concat(rtlArgs).ToList(); if (name.EndsWith("__INTERNAL__HEAP")) { name = name.Substring(0, name.Length - "__INTERNAL__HEAP".Length); } else if (DafnySpec.IsHeapFunction(funCall.Function)) { rtlArgs.Insert(0, new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem")); } if (Attributes.Contains(funCall.Function.Attributes, "opaque") && funCall.Function.Formals.Count + rtlReads.Count == 0) { rtlArgs.Insert(0, new RtlLiteral("true")); } if (fullName == recFunName) { name = fullName; } if (name == recFunName) { recCalls.Add(new List <RtlExp>(rtlArgs)); rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List <RtlExp>(rtlArgs))); rtlArgs.Insert(1, new RtlLiteral(inRecSpec ? "__unroll" : "__unroll + 1")); name = "rec_" + name; } return(new RtlApply(name, rtlArgs)); } else if (dataVal != null) { bool isSeq = dataVal.Type.TypeName(null).StartsWith("Seq<"); return(new RtlApply((isSeq ? "_" : "") + dafnySpec.Compile_Constructor( dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(), dataVal.Arguments.Select(G))); } else if (existsExp != null || forallExp != null) { QuantifierExpr qExp = (QuantifierExpr)exp; bool isForall = forallExp != null; var varTuples = qExp.BoundVars.Select(v => Tuple.Create(GhostVar(v.Name), v.IsGhost, v.Type)); var oldRenamer = PushRename(qExp.BoundVars.Select(v => v.Name)); var oldStmtExprEnabled = stmtExprEnabled; stmtExprEnabled = false; RtlExp rExp = new RtlLiteral((isForall ? "(forall " : "(exists ") + string.Join(", ", qExp.BoundVars.Select(v => GhostVar(v.Name) + ":" + TypeString(AppType(v.Type)))) + " :: " + Triggers(qExp.Attributes, G) + " " + GetTypeWellFormedExp(varTuples.ToList(), isForall ? "==>" : "&&", G(qExp.Term)) + ")"); stmtExprEnabled = oldStmtExprEnabled; PopRename(oldRenamer); return(rExp); } else if (letExp != null) { List <RtlExp> rhss; if (letExp.Exact) { rhss = letExp.RHSs.ConvertAll(e => G(e)); } else if (letExp.LHSs.Count == 1 && LiteralExpr.IsTrue(letExp.RHSs[0]) && AppType(letExp.LHSs[0].Var.Type) is IntType) { rhss = new List <RtlExp> { new RtlLiteral("0") }; } else { throw new Exception("not implemented: LetExpr: " + letExp); } return(GhostLet(exp.tok, letExp.LHSs.ConvertAll(lhs => lhs.Var), rhss, () => G(letExp.Body))); } else if (matchExp != null) { if (matchExp.MissingCases.Count != 0) { throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp); } //- match src case c1(ps1) => e1 ... cn(psn) => en //- --> //- let x := src in //- if x is c1 then let ps1 := ...x.f1... in e1 else //- if x is c2 then let ps2 := ...x.f2... in e2 else //- let ps3 := ...x.f3... in e3 var src = G(matchExp.Source); var cases = matchExp.Cases; string x = TempName(); Func <RtlExp> body = null; for (int i = cases.Count; i > 0;) { i--; MatchCaseExpr c = cases[i]; Func <List <RtlExp> > cRhss = () => c.Ctor.Formals.ConvertAll(f => (RtlExp) new RtlLiteral("(" + f.Name + "#" + c.Ctor.Name + "(" + GhostVar(x) + "))")); Func <RtlExp> ec = () => GhostLet(exp.tok, c.Arguments, cRhss(), () => G(c.Body)); if (body == null) { body = ec; } else { var prevBody = body; body = () => GhostIfThenElse(new RtlLiteral("(" + GhostVar(x) + " is " + c.Ctor.Name + ")"), ec, prevBody); } } return(GhostLet(exp.tok, new List <BoundVar> { new BoundVar(exp.tok, x, matchExp.Source.Type) }, new List <RtlExp> { src }, body)); } else if (oldExp != null) { return(new RtlLiteral("old(" + GhostExpression(oldExp.E, inRecSpec, true) + ")")); } else if (freshExp != null) { Util.Assert(DafnySpec.IsArrayType(freshExp.E.Type)); string abs = G(freshExp.E) + ".arrAbs"; return(new RtlLiteral("(heap_old.absData[" + abs + "] is AbsNone)")); } else if (fieldSelect != null && fieldSelect.FieldName.EndsWith("?")) { string constructor = fieldSelect.FieldName.Substring(0, fieldSelect.FieldName.Length - 1); constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type, constructor, null, typeApply.typeArgs).AppName(); bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<"); return(isSeq ? new RtlLiteral("is_" + constructor + "(" + G(fieldSelect.Obj) + ")") : new RtlLiteral("((" + G(fieldSelect.Obj) + ") is " + constructor + ")")); } else if (fieldSelect != null && !fieldSelect.Field.IsStatic && AppType(fieldSelect.Obj.Type) is UserDefinedType && fieldSelect.Field is DatatypeDestructor) { DatatypeDestructor field = (DatatypeDestructor)fieldSelect.Field; string constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type, field.EnclosingCtor.Name, null, typeApply.typeArgs).AppName(); bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<"); return(new RtlLiteral("(" + fieldSelect.FieldName + (isSeq ? "_" : "#") + constructor + "(" + G(fieldSelect.Obj) + "))")); } else if (fieldSelect != null && DafnySpec.IsArrayType(AppType(fieldSelect.Obj.Type)) && fieldSelect.FieldName == "Length") { return(new RtlLiteral("(Arr_Length(" + G(fieldSelect.Obj) + "))")); } else if (fieldSelect != null && fieldSelect.Obj is ImplicitThisExpr) { //- we don't support objects yet, so interpret this as a global variable return(new RtlVar(GhostVar(fieldSelect.FieldName), true, fieldSelect.Type)); } else if (seqSelect != null) { if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { return(new RtlExpComputed(e => "fun_INTERNAL__array__elems__index(" + (inRequiresOrOld ? "$absMem_old" : "$absMem") + "[" + e.args[0] + ".arrAbs], (" + e.args[1] + "))", new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) })); } else if (seqSelect.SelectOne) { return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Seq.Type), "Seq_Index"), new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) })); } else { RtlExp seq = G(seqSelect.Seq); if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { seq = new RtlApply(FunName("Seq__FromArray"), new RtlExp[] { new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"), seq }); } if (seqSelect.E1 != null) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Take"), new RtlExp[] { seq, G(seqSelect.E1) }); } if (seqSelect.E0 != null) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Drop"), new RtlExp[] { seq, G(seqSelect.E0) }); } return(seq); } } else if (seqUpdate != null) { if (seqUpdate.ResolvedUpdateExpr != null) { return(GhostExpressionRec(seqUpdate.ResolvedUpdateExpr, inRecSpec, inRequiresOrOld)); } return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqUpdate.Seq.Type), "Seq_Update"), new RtlExp[] { G(seqUpdate.Seq), G(seqUpdate.Index), G(seqUpdate.Value) })); } else if (seqDisplay != null) { RtlExp seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Empty"), new RtlExp[0]); foreach (Expression ei in seqDisplay.Elements) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Build"), new RtlExp[] { seq, G(ei) }); } return(seq); } else { throw new Exception("not implemented: " + exp); } }
// ForallExpr public static int GetNumberOfChildren(this ForallExpr e) { return(1); }