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 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 override BoundVar CloneBoundVar(BoundVar bv) { String nm; var name = _renames.TryGetValue(bv.Name, out nm) ? nm : bv.Name; var bvNew = new BoundVar(Tok(bv.tok), name, CloneType(bv.Type)) { IsGhost = bv.IsGhost }; return(bvNew); }
protected override List <BoundVar> CreateBoundVarSubstitutions(List <BoundVar> vars, bool forceSubstitutionOfBoundVars) { var newBoundVars = vars.Count == 0 ? vars : new List <BoundVar>(); foreach (var bv in vars) { var tt = Resolver.SubstType(bv.Type, typeMap); var newBv = new BoundVar(bv.tok, "_'" + bv.Name, tt); newBoundVars.Add(newBv); // update substMap to reflect the new BoundVar substitutions var ie = new IdentifierExpr(newBv.tok, newBv.Name); ie.Var = newBv; // resolve here ie.Type = newBv.Type; // resolve here substMap.Add(bv, ie); } return(newBoundVars); }
public string GenerateString(SetComprehension expression) { var bob = new StringBuilder(); bob.Append(expression.tok.val + " "); // appends "set " //string boundName = expression.BoundVars.First().Name; // Assume for now that only a single bound variable exists. //bob.Append(boundName + " | " + GenerateString(expression.Range)); BoundVar boundVar = expression.BoundVars.First(); bob.Append(boundVar.Name + ": " + boundVar.Type.ToString() + " | " + GenerateString(expression.Range)); // Not all set comprehension expressions contain a "Term" section. // For example: set x | x in {0,1,2,3,4,5} && x < 3; if (expression.Term.tok.val != "set") { bob.Append(" :: "); bob.Append(GenerateString(expression.Term)); } return(bob.ToString()); }
/// <summary> /// Before calling TrExpr(expr), the caller must have spilled the let variables declared in "expr". /// </summary> void TrExpr(Expression expr, TextWriter wr, bool inLetExprBody) { Contract.Requires(expr != null); if (expr is LiteralExpr) { LiteralExpr e = (LiteralExpr)expr; if (e is StaticReceiverExpr) { wr.Write(TypeName(e.Type, wr)); } else if (e.Value == null) { wr.Write("({0})null", TypeName(e.Type, wr)); } else if (e.Value is bool) { wr.Write((bool)e.Value ? "true" : "false"); } else if (e is CharLiteralExpr) { wr.Write("'{0}'", (string)e.Value); } else if (e is StringLiteralExpr) { var str = (StringLiteralExpr)e; wr.Write("{0}<char>.FromString({1}\"{2}\")", DafnySeqClass, str.IsVerbatim ? "@" : "", (string)e.Value); } else if (AsNativeType(e.Type) != null) { wr.Write((BigInteger)e.Value + AsNativeType(e.Type).Suffix); } else if (e.Value is BigInteger) { BigInteger i = (BigInteger)e.Value; if (new BigInteger(int.MinValue) <= i && i <= new BigInteger(int.MaxValue)) { wr.Write("new BigInteger({0})", i); } else { wr.Write("BigInteger.Parse(\"{0}\")", i); } } else if (e.Value is Basetypes.BigDec) { var n = (Basetypes.BigDec)e.Value; if (0 <= n.Exponent) { wr.Write("new Dafny.BigRational(new BigInteger({0}", n.Mantissa); for (int i = 0; i < n.Exponent; i++) { wr.Write("0"); } wr.Write("), BigInteger.One)"); } else { wr.Write("new Dafny.BigRational(new BigInteger({0}), new BigInteger(1", n.Mantissa); for (int i = n.Exponent; i < 0; i++) { wr.Write("0"); } wr.Write("))"); } } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected literal } } else if (expr is ThisExpr) { wr.Write(enclosingMethod != null && enclosingMethod.IsTailRecursive ? "_this" : "this"); } else if (expr is IdentifierExpr) { var e = (IdentifierExpr)expr; if (e.Var is Formal && inLetExprBody && !((Formal)e.Var).InParam) { // out param in letExpr body, need to copy it to a temp since // letExpr body is translated to an anonymous function that doesn't // allow out parameters var name = string.Format("_pat_let_tv{0}", GetUniqueAstNumber(e)); wr.Write("@" + name); copyInstrWriter.Append("var @" + name + "= @" + e.Var.CompileName + ";\n"); } else { wr.Write("@" + e.Var.CompileName); } } else if (expr is SetDisplayExpr) { var e = (SetDisplayExpr)expr; var elType = e.Type.AsSetType.Arg; wr.Write("{0}<{1}>.FromElements", DafnySetClass, TypeName(elType, wr)); TrExprList(e.Elements, wr, inLetExprBody); } else if (expr is MultiSetDisplayExpr) { var e = (MultiSetDisplayExpr)expr; var elType = e.Type.AsMultiSetType.Arg; wr.Write("{0}<{1}>.FromElements", DafnyMultiSetClass, TypeName(elType, wr)); TrExprList(e.Elements, wr, inLetExprBody); } else if (expr is SeqDisplayExpr) { var e = (SeqDisplayExpr)expr; var elType = e.Type.AsSeqType.Arg; wr.Write("{0}<{1}>.FromElements", DafnySeqClass, TypeName(elType, wr)); TrExprList(e.Elements, wr, inLetExprBody); } else if (expr is MapDisplayExpr) { MapDisplayExpr e = (MapDisplayExpr)expr; wr.Write("{0}.FromElements", TypeName(e.Type, wr)); TrExprPairList(e.Elements, wr, inLetExprBody); } else if (expr is MemberSelectExpr) { MemberSelectExpr e = (MemberSelectExpr)expr; SpecialField sf = e.Member as SpecialField; if (sf != null) { wr.Write(sf.PreString); TrParenExpr(e.Obj, wr, inLetExprBody); wr.Write(".@{0}", sf.CompiledName); wr.Write(sf.PostString); } else { TrExpr(e.Obj, wr, inLetExprBody); wr.Write(".@{0}", e.Member.CompileName); } } else if (expr is SeqSelectExpr) { SeqSelectExpr e = (SeqSelectExpr)expr; Contract.Assert(e.Seq.Type != null); if (e.Seq.Type.IsArrayType) { if (e.SelectOne) { Contract.Assert(e.E0 != null && e.E1 == null); TrParenExpr(e.Seq, wr, inLetExprBody); wr.Write("[(int)"); TrParenExpr(e.E0, wr, inLetExprBody); wr.Write("]"); } else { TrParenExpr("Dafny.Helpers.SeqFromArray", e.Seq, wr, inLetExprBody); if (e.E1 != null) { TrParenExpr(".Take", e.E1, wr, inLetExprBody); } if (e.E0 != null) { TrParenExpr(".Drop", e.E0, wr, inLetExprBody); } } } else if (e.SelectOne) { Contract.Assert(e.E0 != null && e.E1 == null); TrParenExpr(e.Seq, wr, inLetExprBody); TrParenExpr(".Select", e.E0, wr, inLetExprBody); } else { TrParenExpr(e.Seq, wr, inLetExprBody); if (e.E1 != null) { TrParenExpr(".Take", e.E1, wr, inLetExprBody); } if (e.E0 != null) { TrParenExpr(".Drop", e.E0, wr, inLetExprBody); } } } else if (expr is MultiSetFormingExpr) { var e = (MultiSetFormingExpr)expr; wr.Write("{0}<{1}>", DafnyMultiSetClass, TypeName(e.E.Type.AsCollectionType.Arg, wr)); var eeType = e.E.Type.NormalizeExpand(); if (eeType is SeqType) { TrParenExpr(".FromSeq", e.E, wr, inLetExprBody); } else if (eeType is SetType) { TrParenExpr(".FromSet", e.E, wr, inLetExprBody); } else { Contract.Assert(false); throw new cce.UnreachableException(); } } else if (expr is MultiSelectExpr) { MultiSelectExpr e = (MultiSelectExpr)expr; TrParenExpr(e.Array, wr, inLetExprBody); string prefix = "["; foreach (Expression idx in e.Indices) { wr.Write("{0}(int)", prefix); TrParenExpr(idx, wr, inLetExprBody); prefix = ", "; } wr.Write("]"); } else if (expr is SeqUpdateExpr) { SeqUpdateExpr e = (SeqUpdateExpr)expr; if (e.ResolvedUpdateExpr != null) { TrExpr(e.ResolvedUpdateExpr, wr, inLetExprBody); } else { TrParenExpr(e.Seq, wr, inLetExprBody); wr.Write(".Update("); TrExpr(e.Index, wr, inLetExprBody); wr.Write(", "); TrExpr(e.Value, wr, inLetExprBody); wr.Write(")"); } } else if (expr is FunctionCallExpr) { FunctionCallExpr e = (FunctionCallExpr)expr; CompileFunctionCallExpr(e, wr, wr, inLetExprBody, TrExpr); } else if (expr is ApplyExpr) { var e = expr as ApplyExpr; wr.Write("Dafny.Helpers.Id<"); wr.Write(TypeName(e.Function.Type, wr)); wr.Write(">("); TrExpr(e.Function, wr, inLetExprBody); wr.Write(")"); TrExprList(e.Args, wr, inLetExprBody); } else if (expr is DatatypeValue) { DatatypeValue dtv = (DatatypeValue)expr; Contract.Assert(dtv.Ctor != null); // since dtv has been successfully resolved var typeParams = dtv.InferredTypeArgs.Count == 0 ? "" : string.Format("<{0}>", TypeNames(dtv.InferredTypeArgs, wr)); wr.Write("new @{0}{1}(", DtName(dtv.Ctor.EnclosingDatatype), typeParams); if (!dtv.IsCoCall) { // For an ordinary constructor (that is, one that does not guard any co-recursive calls), generate: // new Dt_Cons<T>( args ) wr.Write("new {0}(", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs, wr)); string sep = ""; for (int i = 0; i < dtv.Arguments.Count; i++) { Formal formal = dtv.Ctor.Formals[i]; if (!formal.IsGhost) { wr.Write(sep); TrExpr(dtv.Arguments[i], wr, inLetExprBody); sep = ", "; } } wr.Write(")"); } else { // In the case of a co-recursive call, generate: // new Dt__Lazy<T>( new Dt__Lazy<T>.ComputerComputer( LAMBDA )() ) // where LAMBDA is: // () => { var someLocals = eagerlyEvaluatedArguments; // return () => { return Dt_Cons<T>( ...args...using someLocals and including function calls to be evaluated lazily... ); }; // } wr.Write("new {0}__Lazy{1}", dtv.DatatypeName, typeParams); wr.Write("(new {0}__Lazy{1}.ComputerComputer(() => {{ ", dtv.DatatypeName, typeParams); // locals string args = ""; string sep = ""; for (int i = 0; i < dtv.Arguments.Count; i++) { Formal formal = dtv.Ctor.Formals[i]; if (!formal.IsGhost) { Expression actual = dtv.Arguments[i].Resolved; string arg; var fce = actual as FunctionCallExpr; if (fce == null || fce.CoCall != FunctionCallExpr.CoCallResolution.Yes) { string varName = idGenerator.FreshId("_ac"); arg = varName; wr.Write("var {0} = ", varName); TrExpr(actual, wr, inLetExprBody); wr.Write("; "); } else { var sw = new StringWriter(); CompileFunctionCallExpr(fce, sw, wr, inLetExprBody, (exp, wrr, inLetExpr) => { string varName = idGenerator.FreshId("_ac"); sw.Write(varName); wrr.Write("var {0} = ", varName); TrExpr(exp, wrr, inLetExpr); wrr.Write("; "); }); arg = sw.ToString(); } args += sep + arg; sep = ", "; } } wr.Write("return () => { return "); wr.Write("new {0}({1}", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs, wr), args); wr.Write("); }; })())"); } wr.Write(")"); } else if (expr is OldExpr) { Contract.Assert(false); throw new cce.UnreachableException(); // 'old' is always a ghost (right?) } else if (expr is UnaryOpExpr) { var e = (UnaryOpExpr)expr; switch (e.Op) { case UnaryOpExpr.Opcode.Not: wr.Write("!"); TrParenExpr(e.E, wr, inLetExprBody); break; case UnaryOpExpr.Opcode.Cardinality: wr.Write("new BigInteger("); TrParenExpr(e.E, wr, inLetExprBody); wr.Write(".Length)"); break; default: Contract.Assert(false); throw new cce.UnreachableException(); // unexpected unary expression } } else if (expr is ConversionExpr) { var e = (ConversionExpr)expr; var fromInt = e.E.Type.IsNumericBased(Type.NumericPersuation.Int); Contract.Assert(fromInt || e.E.Type.IsNumericBased(Type.NumericPersuation.Real)); var toInt = e.ToType.IsNumericBased(Type.NumericPersuation.Int); Contract.Assert(toInt || e.ToType.IsNumericBased(Type.NumericPersuation.Real)); Action fromIntAsBigInteger = () => { Contract.Assert(fromInt); if (AsNativeType(e.E.Type) != null) { wr.Write("new BigInteger"); } TrParenExpr(e.E, wr, inLetExprBody); }; Action toIntCast = () => { Contract.Assert(toInt); if (AsNativeType(e.ToType) != null) { wr.Write("(" + AsNativeType(e.ToType).Name + ")"); } }; if (fromInt && !toInt) { // int -> real wr.Write("new Dafny.BigRational("); fromIntAsBigInteger(); wr.Write(", BigInteger.One)"); } else if (!fromInt && toInt) { // real -> int toIntCast(); TrParenExpr(e.E, wr, inLetExprBody); wr.Write(".ToBigInteger()"); } else if (AsNativeType(e.ToType) != null) { toIntCast(); LiteralExpr lit = e.E.Resolved as LiteralExpr; UnaryOpExpr u = e.E.Resolved as UnaryOpExpr; MemberSelectExpr m = e.E.Resolved as MemberSelectExpr; if (lit != null && lit.Value is BigInteger) { // Optimize constant to avoid intermediate BigInteger wr.Write("(" + (BigInteger)lit.Value + AsNativeType(e.ToType).Suffix + ")"); } else if ((u != null && u.Op == UnaryOpExpr.Opcode.Cardinality) || (m != null && m.MemberName == "Length" && m.Obj.Type.IsArrayType)) { // Optimize .Length to avoid intermediate BigInteger TrParenExpr((u != null) ? u.E : m.Obj, wr, inLetExprBody); if (AsNativeType(e.ToType).UpperBound <= new BigInteger(0x80000000U)) { wr.Write(".Length"); } else { wr.Write(".LongLength"); } } else { TrParenExpr(e.E, wr, inLetExprBody); } } else if (e.ToType.IsIntegerType && AsNativeType(e.E.Type) != null) { fromIntAsBigInteger(); } else { Contract.Assert(fromInt == toInt); Contract.Assert(AsNativeType(e.ToType) == null); Contract.Assert(AsNativeType(e.E.Type) == null); TrParenExpr(e.E, wr, inLetExprBody); } } else if (expr is BinaryExpr) { BinaryExpr e = (BinaryExpr)expr; string opString = null; string preOpString = ""; string callString = null; switch (e.ResolvedOp) { case BinaryExpr.ResolvedOpcode.Iff: opString = "=="; break; case BinaryExpr.ResolvedOpcode.Imp: preOpString = "!"; opString = "||"; break; case BinaryExpr.ResolvedOpcode.Or: opString = "||"; break; case BinaryExpr.ResolvedOpcode.And: opString = "&&"; break; case BinaryExpr.ResolvedOpcode.EqCommon: { if (e.E0.Type.IsRefType) { // Dafny's type rules are slightly different C#, so we may need a cast here. // For example, Dafny allows x==y if x:array<T> and y:array<int> and T is some // type parameter. opString = "== (object)"; } else if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) { callString = "Equals"; } else { opString = "=="; } break; } case BinaryExpr.ResolvedOpcode.NeqCommon: { if (e.E0.Type.IsRefType) { // Dafny's type rules are slightly different C#, so we may need a cast here. // For example, Dafny allows x==y if x:array<T> and y:array<int> and T is some // type parameter. opString = "!= (object)"; } else if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) { preOpString = "!"; callString = "Equals"; } else { opString = "!="; } break; } case BinaryExpr.ResolvedOpcode.Lt: case BinaryExpr.ResolvedOpcode.LtChar: opString = "<"; break; case BinaryExpr.ResolvedOpcode.Le: case BinaryExpr.ResolvedOpcode.LeChar: opString = "<="; break; case BinaryExpr.ResolvedOpcode.Ge: case BinaryExpr.ResolvedOpcode.GeChar: opString = ">="; break; case BinaryExpr.ResolvedOpcode.Gt: case BinaryExpr.ResolvedOpcode.GtChar: opString = ">"; break; case BinaryExpr.ResolvedOpcode.Add: opString = "+"; break; case BinaryExpr.ResolvedOpcode.Sub: opString = "-"; break; case BinaryExpr.ResolvedOpcode.Mul: opString = "*"; break; case BinaryExpr.ResolvedOpcode.Div: if (expr.Type.IsIntegerType || (AsNativeType(expr.Type) != null && AsNativeType(expr.Type).LowerBound < BigInteger.Zero)) { string suffix = AsNativeType(expr.Type) != null ? ("_" + AsNativeType(expr.Type).Name) : ""; wr.Write("Dafny.Helpers.EuclideanDivision" + suffix + "("); TrParenExpr(e.E0, wr, inLetExprBody); wr.Write(", "); TrExpr(e.E1, wr, inLetExprBody); wr.Write(")"); } else { opString = "/"; // for reals } break; case BinaryExpr.ResolvedOpcode.Mod: if (expr.Type.IsIntegerType || (AsNativeType(expr.Type) != null && AsNativeType(expr.Type).LowerBound < BigInteger.Zero)) { string suffix = AsNativeType(expr.Type) != null ? ("_" + AsNativeType(expr.Type).Name) : ""; wr.Write("Dafny.Helpers.EuclideanModulus" + suffix + "("); TrParenExpr(e.E0, wr, inLetExprBody); wr.Write(", "); TrExpr(e.E1, wr, inLetExprBody); wr.Write(")"); } else { opString = "%"; // for reals } break; case BinaryExpr.ResolvedOpcode.SetEq: case BinaryExpr.ResolvedOpcode.MultiSetEq: case BinaryExpr.ResolvedOpcode.SeqEq: case BinaryExpr.ResolvedOpcode.MapEq: callString = "Equals"; break; case BinaryExpr.ResolvedOpcode.SetNeq: case BinaryExpr.ResolvedOpcode.MultiSetNeq: case BinaryExpr.ResolvedOpcode.SeqNeq: case BinaryExpr.ResolvedOpcode.MapNeq: preOpString = "!"; callString = "Equals"; break; case BinaryExpr.ResolvedOpcode.ProperSubset: case BinaryExpr.ResolvedOpcode.ProperMultiSubset: callString = "IsProperSubsetOf"; break; case BinaryExpr.ResolvedOpcode.Subset: case BinaryExpr.ResolvedOpcode.MultiSubset: callString = "IsSubsetOf"; break; case BinaryExpr.ResolvedOpcode.Superset: case BinaryExpr.ResolvedOpcode.MultiSuperset: callString = "IsSupersetOf"; break; case BinaryExpr.ResolvedOpcode.ProperSuperset: case BinaryExpr.ResolvedOpcode.ProperMultiSuperset: callString = "IsProperSupersetOf"; break; case BinaryExpr.ResolvedOpcode.Disjoint: case BinaryExpr.ResolvedOpcode.MultiSetDisjoint: case BinaryExpr.ResolvedOpcode.MapDisjoint: callString = "IsDisjointFrom"; break; case BinaryExpr.ResolvedOpcode.InSet: case BinaryExpr.ResolvedOpcode.InMultiSet: case BinaryExpr.ResolvedOpcode.InMap: TrParenExpr(e.E1, wr, inLetExprBody); wr.Write(".Contains("); TrExpr(e.E0, wr, inLetExprBody); wr.Write(")"); break; case BinaryExpr.ResolvedOpcode.NotInSet: case BinaryExpr.ResolvedOpcode.NotInMultiSet: case BinaryExpr.ResolvedOpcode.NotInMap: wr.Write("!"); TrParenExpr(e.E1, wr, inLetExprBody); wr.Write(".Contains("); TrExpr(e.E0, wr, inLetExprBody); wr.Write(")"); break; case BinaryExpr.ResolvedOpcode.Union: case BinaryExpr.ResolvedOpcode.MultiSetUnion: callString = "Union"; break; case BinaryExpr.ResolvedOpcode.Intersection: case BinaryExpr.ResolvedOpcode.MultiSetIntersection: callString = "Intersect"; break; case BinaryExpr.ResolvedOpcode.SetDifference: case BinaryExpr.ResolvedOpcode.MultiSetDifference: callString = "Difference"; break; case BinaryExpr.ResolvedOpcode.ProperPrefix: callString = "IsProperPrefixOf"; break; case BinaryExpr.ResolvedOpcode.Prefix: callString = "IsPrefixOf"; break; case BinaryExpr.ResolvedOpcode.Concat: callString = "Concat"; break; case BinaryExpr.ResolvedOpcode.InSeq: TrParenExpr(e.E1, wr, inLetExprBody); wr.Write(".Contains("); TrExpr(e.E0, wr, inLetExprBody); wr.Write(")"); break; case BinaryExpr.ResolvedOpcode.NotInSeq: wr.Write("!"); TrParenExpr(e.E1, wr, inLetExprBody); wr.Write(".Contains("); TrExpr(e.E0, wr, inLetExprBody); wr.Write(")"); break; default: Contract.Assert(false); throw new cce.UnreachableException(); // unexpected binary expression } if (opString != null) { NativeType nativeType = AsNativeType(e.Type); bool needsCast = nativeType != null && nativeType.NeedsCastAfterArithmetic; if (needsCast) { wr.Write("(" + nativeType.Name + ")("); } wr.Write(preOpString); TrParenExpr(e.E0, wr, inLetExprBody); wr.Write(" {0} ", opString); TrParenExpr(e.E1, wr, inLetExprBody); if (needsCast) { wr.Write(")"); } } else if (callString != null) { wr.Write(preOpString); TrParenExpr(e.E0, wr, inLetExprBody); wr.Write(".@{0}(", callString); TrExpr(e.E1, wr, inLetExprBody); wr.Write(")"); } } else if (expr is TernaryExpr) { Contract.Assume(false); // currently, none of the ternary expressions is compilable } else if (expr is LetExpr) { var e = (LetExpr)expr; if (e.Exact) { // The Dafny "let" expression // var Pattern(x,y) := G; E // is translated into C# as: // LamLet(G, tmp => // LamLet(dtorX(tmp), x => // LamLet(dtorY(tmp), y => E))) Contract.Assert(e.LHSs.Count == e.RHSs.Count); // checked by resolution var neededCloseParens = 0; for (int i = 0; i < e.LHSs.Count; i++) { var lhs = e.LHSs[i]; if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) { var rhsName = string.Format("_pat_let{0}_{1}", GetUniqueAstNumber(e), i); wr.Write("Dafny.Helpers.Let<"); wr.Write(TypeName(e.RHSs[i].Type, wr) + "," + TypeName(e.Body.Type, wr)); wr.Write(">("); TrExpr(e.RHSs[i], wr, inLetExprBody); wr.Write(", " + rhsName + " => "); neededCloseParens++; var c = TrCasePattern(lhs, rhsName, e.Body.Type, wr); Contract.Assert(c != 0); // we already checked that there's at least one non-ghost neededCloseParens += c; } } TrExpr(e.Body, wr, true); for (int i = 0; i < neededCloseParens; i++) { wr.Write(")"); } } else if (e.BoundVars.All(bv => bv.IsGhost)) { // The Dafny "let" expression // ghost var x,y :| Constraint; E // is compiled just like E is, because the resolver has already checked that x,y (or other ghost variables, for that matter) don't // occur in E (moreover, the verifier has checked that values for x,y satisfying Constraint exist). TrExpr(e.Body, wr, inLetExprBody); } else { // The Dafny "let" expression // var x,y :| Constraint; E // is translated into C# as: // LamLet(0, dummy => { // the only purpose of this construction here is to allow us to add some code inside an expression in C# // var x,y; // // Embark on computation that fills in x,y according to Constraint; the computation stops when the first // // such value is found, but since the verifier checks that x,y follows uniquely from Constraint, this is // // not a source of nondeterminancy. // return E; // }) Contract.Assert(e.RHSs.Count == 1); // checked by resolution if (e.Constraint_MissingBounds != null) { foreach (var bv in e.Constraint_MissingBounds) { Error("this let-such-that expression is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", wr, bv.Name, e.tok.line); } } else { wr.Write("Dafny.Helpers.Let<int," + TypeName(e.Body.Type, wr) + ">(0, _let_dummy_" + GetUniqueAstNumber(e) + " => {"); foreach (var bv in e.BoundVars) { wr.Write("{0} @{1}", TypeName(bv.Type, wr), bv.CompileName); wr.WriteLine(" = {0};", DefaultValue(bv.Type, wr)); } TrAssignSuchThat(0, new List<IVariable>(e.BoundVars).ConvertAll(bv => (IVariable)bv), e.RHSs[0], e.Constraint_Bounds, e.tok.line, wr, inLetExprBody); wr.Write(" return "); TrExpr(e.Body, wr, true); wr.Write("; })"); } } } else if (expr is MatchExpr) { var e = (MatchExpr)expr; // new Dafny.Helpers.Function<SourceType, TargetType>(delegate (SourceType _source) { // if (source.is_Ctor0) { // FormalType f0 = ((Dt_Ctor0)source._D).a0; // ... // return Body0; // } else if (...) { // ... // } else if (true) { // ... // } // }(src) string source = idGenerator.FreshId("_source"); wr.Write("new Dafny.Helpers.Function<{0}, {1}>(delegate ({0} {2}) {{ ", TypeName(e.Source.Type, wr), TypeName(e.Type, wr), source); if (e.Cases.Count == 0) { // the verifier would have proved we never get here; still, we need some code that will compile wr.Write("throw new System.Exception();"); } else { int i = 0; var sourceType = (UserDefinedType)e.Source.Type.NormalizeExpand(); foreach (MatchCaseExpr mc in e.Cases) { MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, e.Cases.Count, 0, wr); wr.Write("return "); TrExpr(mc.Body, wr, inLetExprBody); wr.Write("; "); i++; } wr.Write("}"); } // We end with applying the source expression to the delegate we just built wr.Write("})("); TrExpr(e.Source, wr, inLetExprBody); wr.Write(")"); } else if (expr is QuantifierExpr) { var e = (QuantifierExpr)expr; // Compilation does not check whether a quantifier was split. Contract.Assert(e.Bounds != null); // for non-ghost quantifiers, the resolver would have insisted on finding bounds var n = e.BoundVars.Count; Contract.Assert(e.Bounds.Count == n); for (int i = 0; i < n; i++) { var bound = e.Bounds[i]; var bv = e.BoundVars[i]; // emit: Dafny.Helpers.QuantX(boundsInformation, isForall, bv => body) if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("Dafny.Helpers.QuantBool("); } else if (bound is ComprehensionExpr.CharBoundedPool) { wr.Write("Dafny.Helpers.QuantChar("); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; wr.Write("Dafny.Helpers.QuantInt("); TrExpr(b.LowerBound, wr, inLetExprBody); wr.Write(", "); TrExpr(b.UpperBound, wr, inLetExprBody); wr.Write(", "); } else if (bound is ComprehensionExpr.SetBoundedPool) { var b = (ComprehensionExpr.SetBoundedPool)bound; wr.Write("Dafny.Helpers.QuantSet("); TrExpr(b.Set, wr, inLetExprBody); wr.Write(", "); } else if (bound is ComprehensionExpr.MapBoundedPool) { var b = (ComprehensionExpr.MapBoundedPool)bound; wr.Write("Dafny.Helpers.QuantMap("); TrExpr(b.Map, wr, inLetExprBody); wr.Write(", "); } else if (bound is ComprehensionExpr.SeqBoundedPool) { var b = (ComprehensionExpr.SeqBoundedPool)bound; wr.Write("Dafny.Helpers.QuantSeq("); TrExpr(b.Seq, wr, inLetExprBody); wr.Write(", "); } else if (bound is ComprehensionExpr.DatatypeBoundedPool) { var b = (ComprehensionExpr.DatatypeBoundedPool)bound; wr.Write("Dafny.Helpers.QuantDatatype("); wr.Write("{0}.AllSingletonConstructors, ", DtName(b.Decl)); } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type } wr.Write("{0}, ", expr is ForallExpr ? "true" : "false"); wr.Write("@{0} => ", bv.CompileName); } TrExpr(e.LogicalBody(true), wr, inLetExprBody); for (int i = 0; i < n; i++) { wr.Write(")"); } } else if (expr is SetComprehension) { var e = (SetComprehension)expr; // For "set i,j,k,l | R(i,j,k,l) :: Term(i,j,k,l)" where the term has type "G", emit something like: // ((ComprehensionDelegate<G>)delegate() { // var _coll = new List<G>(); // foreach (L l in sq.Elements) { // foreach (K k in st.Elements) { // for (BigInteger j = Lo; j < Hi; j++) { // for (bool i in Helper.AllBooleans) { // if (R(i,j,k,l)) { // _coll.Add(Term(i,j,k,l)); // } // } // } // } // } // return Dafny.Set<G>.FromCollection(_coll); // })() Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds var typeName = TypeName(e.Type.AsSetType.Arg, wr); var collection_name = idGenerator.FreshId("_coll"); wr.Write("((Dafny.Helpers.ComprehensionDelegate<{0}>)delegate() {{ ", typeName); wr.Write("var {0} = new System.Collections.Generic.List<{1}>(); ", collection_name, typeName); var n = e.BoundVars.Count; Contract.Assert(e.Bounds.Count == n); for (int i = 0; i < n; i++) { var bound = e.Bounds[i]; var bv = e.BoundVars[i]; if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.CharBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; if (AsNativeType(bv.Type) != null) { wr.Write("foreach (var @{0} in @{1}.IntegerRange(", bv.CompileName, bv.Type.AsNewtype.FullCompileName); } else { wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", bv.CompileName); } TrExpr(b.LowerBound, wr, inLetExprBody); wr.Write(", "); TrExpr(b.UpperBound, wr, inLetExprBody); wr.Write(")) { "); } else if (bound is ComprehensionExpr.SetBoundedPool) { var b = (ComprehensionExpr.SetBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Set, wr, inLetExprBody); wr.Write(").Elements) { "); } else if (bound is ComprehensionExpr.MapBoundedPool) { var b = (ComprehensionExpr.MapBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Map, wr, inLetExprBody); wr.Write(").Domain) { "); } else if (bound is ComprehensionExpr.SeqBoundedPool) { var b = (ComprehensionExpr.SeqBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Seq, wr, inLetExprBody); wr.Write(").Elements) { "); } else if (bound is ComprehensionExpr.DatatypeBoundedPool) { var b = (ComprehensionExpr.DatatypeBoundedPool)bound; wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type, wr)); } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type } } wr.Write("if ("); TrExpr(e.Range, wr, inLetExprBody); wr.Write(") {"); wr.Write("{0}.Add(", collection_name); TrExpr(e.Term, wr, inLetExprBody); wr.Write("); }"); for (int i = 0; i < n; i++) { wr.Write("}"); } wr.Write("return Dafny.Set<{0}>.FromCollection({1}); ", typeName, collection_name); wr.Write("})()"); } else if (expr is MapComprehension) { var e = (MapComprehension)expr; // For "map i | R(i) :: Term(i)" where the term has type "V" and i has type "U", emit something like: // ((MapComprehensionDelegate<U, V>)delegate() { // var _coll = new List<Pair<U,V>>(); // foreach (L l in sq.Elements) { // foreach (K k in st.Elements) { // for (BigInteger j = Lo; j < Hi; j++) { // for (bool i in Helper.AllBooleans) { // if (R(i,j,k,l)) { // _coll.Add(new Pair(i, Term(i)); // } // } // } // } // } // return Dafny.Map<U, V>.FromElements(_coll); // })() Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds var domtypeName = TypeName(e.Type.AsMapType.Domain, wr); var rantypeName = TypeName(e.Type.AsMapType.Range, wr); var collection_name = idGenerator.FreshId("_coll"); wr.Write("((Dafny.Helpers.MapComprehensionDelegate<{0},{1}>)delegate() {{ ", domtypeName, rantypeName); wr.Write("var {0} = new System.Collections.Generic.List<Dafny.Pair<{1},{2}>>(); ", collection_name, domtypeName, rantypeName); var n = e.BoundVars.Count; Contract.Assert(e.Bounds.Count == n && n == 1); var bound = e.Bounds[0]; var bv = e.BoundVars[0]; if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.CharBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; if (AsNativeType(bv.Type) != null) { wr.Write("foreach (var @{0} in @{1}.IntegerRange(", bv.CompileName, bv.Type.AsNewtype.FullCompileName); } else { wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", bv.CompileName); } TrExpr(b.LowerBound, wr, inLetExprBody); wr.Write(", "); TrExpr(b.UpperBound, wr, inLetExprBody); wr.Write(")) { "); } else if (bound is ComprehensionExpr.SetBoundedPool) { var b = (ComprehensionExpr.SetBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Set, wr, inLetExprBody); wr.Write(").Elements) { "); } else if (bound is ComprehensionExpr.MapBoundedPool) { var b = (ComprehensionExpr.MapBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Map, wr, inLetExprBody); wr.Write(").Domain) { "); } else if (bound is ComprehensionExpr.SeqBoundedPool) { var b = (ComprehensionExpr.SeqBoundedPool)bound; wr.Write("foreach (var @{0} in (", bv.CompileName); TrExpr(b.Seq, wr, inLetExprBody); wr.Write(").Elements) { "); } else { // TODO: handle ComprehensionExpr.SubSetBoundedPool Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type } wr.Write("if ("); TrExpr(e.Range, wr, inLetExprBody); wr.Write(") { "); wr.Write("{0}.Add(new Dafny.Pair<{1},{2}>(@{3},", collection_name, domtypeName, rantypeName, bv.CompileName); TrExpr(e.Term, wr, inLetExprBody); wr.Write(")); }"); wr.Write("}"); wr.Write("return Dafny.Map<{0},{1}>.FromCollection({2}); ", domtypeName, rantypeName, collection_name); wr.Write("})()"); } else if (expr is LambdaExpr) { LambdaExpr e = (LambdaExpr)expr; var fvs = Translator.ComputeFreeVariables(expr); var sm = new Dictionary<IVariable, Expression>(); var bvars = new List<BoundVar>(); var fexprs = new List<Expression>(); foreach(var fv in fvs) { fexprs.Add(new IdentifierExpr(fv.Tok, fv.Name) { Var = fv, // resolved here! Type = fv.Type }); var bv = new BoundVar(fv.Tok, fv.Name, fv.Type); bvars.Add(bv); sm[fv] = new IdentifierExpr(bv.Tok, bv.Name) { Var = bv, // resolved here! Type = bv.Type }; } var su = new Translator.Substituter(null, sm, new Dictionary<TypeParameter, Type>(), null); BetaRedex(bvars, fexprs, expr.Type, wr, inLetExprBody, () => { wr.Write("("); wr.Write(Util.Comma(e.BoundVars, bv => "@" + bv.CompileName)); wr.Write(") => "); TrExpr(su.Substitute(e.Body), wr, inLetExprBody); }); } else if (expr is StmtExpr) { var e = (StmtExpr)expr; TrExpr(e.E, wr, inLetExprBody); } else if (expr is ITEExpr) { ITEExpr e = (ITEExpr)expr; wr.Write("("); TrExpr(e.Test, wr, inLetExprBody); wr.Write(") ? ("); TrExpr(e.Thn, wr, inLetExprBody); wr.Write(") : ("); TrExpr(e.Els, wr, inLetExprBody); wr.Write(")"); } else if (expr is ConcreteSyntaxExpression) { var e = (ConcreteSyntaxExpression)expr; TrExpr(e.ResolvedExpression, wr, inLetExprBody); } else if (expr is NamedExpr) { TrExpr(((NamedExpr)expr).Body, wr, inLetExprBody); } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression } }
void CompileDatatypeConstructors(DatatypeDecl dt) { Contract.Requires(dt != null); if (dt is CoDatatypeDecl) { WriteEAbort("BUGBUG: CoDatatypeDecl not supported"); // bugbug: implement } // For Kremlin, generate a constructor only: There are no .NET base // object methods such as Equals() or GetHashCode() so no code-gen is // needed here, to support them. // public Dt_Ctor(arguments) { // Fields = arguments; // } UserDefinedType thisType = UserDefinedType.FromTopLevelDecl(dt.tok, dt); foreach (DatatypeCtor ctor in dt.Ctors) { VarTracker.Clear(); var pThis = new BoundVar(ctor.tok, ThisName, thisType); using (WriteArray()) { j.WriteValue(KremlinAst.DFunction); using (WriteArray()) { // of (CallingConvention.t option * flag list * typ * lident * binder list * expr) WriteDefaultCallingConvention(); using (WriteArray()) { } WriteTypeName(thisType); // returns type of 'this' WriteLident(ctor.FullName); using (WriteArray()) { // start of binder list WriteFormals(ctor.Formals); } using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); // Do not emit EPushFrame/EPopFrame, as we want the allocation // of pThis to be inlined into the calling function. using (WriteArray()) { // ELet pThis = DefaultValueOfType in ESequence... using (WriteArray()) { j.WriteValue(KremlinAst.ELet); using (WriteArray()) { // of (binder * expr * expr) WriteBinder(pThis, ThisName, true); VarTracker.Push(pThis); WriteDefaultValue(thisType); using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { // of expr list foreach (Formal arg in ctor.Formals) { if (arg.IsGhost) { continue; } // EAssign (EField of (EBufRead this.arg 0)) = EBound of Formal using (WriteArray()) { Formatting old = j.Formatting; j.Formatting = Formatting.None; j.WriteValue(KremlinAst.EAssign); using (WriteArray()) { // of (expr * expr) // First expr: EField of EBufRead('this',0) to write into using (WriteArray()) { j.WriteValue(KremlinAst.EField); using (WriteArray()) { // of (lident * expr * ident) WriteLident(pThis.Type); // lident using (WriteArray()) { j.WriteValue(KremlinAst.EBufRead); using (WriteArray()) { WriteEBound(pThis); WriteConstant(0u); } } j.WriteValue(arg.Name); } } // Second expr: // EBound of formal WriteEBound(arg); } j.Formatting = old; } } WriteEBound(pThis); // and return the pThis expression from the constructor } } VarTracker.Pop(pThis); } } } } } } enclosingThis = null; } }
void CompileClassMembers(ClassDecl c) { Contract.Requires(c != null); // For C#, Dafny generates a C# class containing base members, class // fields, methods, and functions all together. // // For Kremlin, a class will generate a struct (a Kremlin DTypeFlat) // followed by functions (Kremlin DFunction), with explicit "this" // parameters. bool forCompanionClass = false; // bugbug: implement // Generate the DTypeFlat struct representing the class if (!WriteClassStruct(c, forCompanionClass)) { // No class struct was written because it has no non-ghost members foreach (var member in c.InheritedMembers) { Contract.Assert(!member.IsGhost && !member.IsStatic); // only non-ghost instance members should ever be added to .InheritedMembers } bool HasNoMembers = true; foreach (MemberDecl member in c.Members) { if (!(member is Field) && !member.IsGhost) { HasNoMembers = false; break; } } if (HasNoMembers) { // Skip the class if it is entirely ghost return; } } UserDefinedType thisType = UserDefinedType.FromTopLevelDecl(c.tok, c); foreach (var member in c.InheritedMembers) { Contract.Assert(!member.IsGhost && !member.IsStatic); // only non-ghost instance members should ever be added to .InheritedMembers using (WriteArray()) { if (member is Field) { // Do nothing - WriteClassStruct already handled this case } else if (member is Function) { var f = (Function)member; Contract.Assert(f.Body != null); WriteToken(member.tok); j.WriteComment("BUGBUG Function unsupported: " + f.CompileName); // bugbug: implement } else if (member is Method) { var method = (Method)member; Contract.Assert(method.Body != null); WriteToken(member.tok); j.WriteComment("BUGBUG Method unsupported: " + method.CompileName); // bugbug: implement } else { Contract.Assert(false); // unexpected member } } } foreach (MemberDecl member in c.Members) { if (member is Field) { // Do nothing - WriteClassStruct already handled this case } else if (member is Function) { var f = (Function)member; if (f.Body == null && !(c is TraitDecl && !f.IsStatic)) { // A (ghost or non-ghost) function must always have a body, except if it's an instance function in a trait. if (forCompanionClass /* || Attributes.Contains(f.Attributes, "axiom") */) { // suppress error message (in the case of "forCompanionClass", the non-forCompanionClass call will produce the error message) } else { // The C# backend ignores functions that are axioms. But for // the Spartan scenario, treat these as extern functions. WriteToken(member.tok); CompileExternalFunction(f); } } else if (f.IsGhost) { // nothing to compile, but we do check for assumes if (f.Body == null) { Contract.Assert(c is TraitDecl && !f.IsStatic); } else { var v = new CheckHasNoAssumes_VisitorJ(this, j); v.Visit(f.Body); } } else if (c is TraitDecl && !forCompanionClass) { // include it, unless it's static if (!f.IsStatic) { WriteToken(member.tok); j.WriteComment("BUGBUG TraitDecl in function is unsupported: " + f.FullName); // bugbug: implement } } else if (forCompanionClass && !f.IsStatic) { // companion classes only has static members } else { WriteToken(member.tok); enclosingThis = (f.IsStatic) ? null : new BoundVar(c.tok, ThisName, thisType); CompileFunction(f); enclosingThis = null; } } else if (member is Method) { var m = (Method)member; if (m.Body == null && !(c is TraitDecl && !m.IsStatic)) { // A (ghost or non-ghost) method must always have a body, except if it's an instance method in a trait. if (forCompanionClass /* || Attributes.Contains(m.Attributes, "axiom") */ ) { // suppress error message (in the case of "forCompanionClass", the non-forCompanionClass call will produce the error message) } else { // The C# backend ignores functions that are axioms. But for // the Spartan scenario, treat these as extern functions. WriteToken(member.tok); CompileExternalMethod(c, m); } } else if (m.IsGhost) { // nothing to compile, but we do check for assumes if (m.Body == null) { Contract.Assert(c is TraitDecl && !m.IsStatic); } else { var v = new CheckHasNoAssumes_VisitorJ(this, j); v.Visit(m.Body); } } else if (c is TraitDecl && !forCompanionClass) { // include it, unless it's static if (!m.IsStatic) { j.WriteComment("BUGBUG TraitDecl not supported: " + m.CompileName); // bugbug: implement } } else if (forCompanionClass && !m.IsStatic) { // companion classes only has static members } else { WriteToken(member.tok); enclosingThis = (m.IsStatic) ? null : new BoundVar(c.tok, ThisName, thisType); CompileMethod(c, m); enclosingThis = null; } } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member } } }
void TrStmt(Statement stmt) { Contract.Requires(stmt != null); TextWriter wr = new StringWriter(); if (stmt.IsGhost) { var v = new CheckHasNoAssumes_Visitor(this, wr); v.Visit(stmt); return; } if (stmt is PrintStmt) { WriteToken(stmt.Tok); PrintStmt s = (PrintStmt)stmt; using (WriteArray()) { j.WriteValue(KremlinAst.EApp); j.WriteValue("IO.debug_print_string"); // bugbug: is this the correct way to form the function name? using (WriteArray()) { foreach (var arg in s.Args) { TrExpr(arg, false); // bugbug: each argument needs to be converted to a string and concatenated } } } } else if (stmt is BreakStmt) { WriteToken(stmt.Tok); var s = (BreakStmt)stmt; WriteEAbort("BUGBUG BreakStmt is unsupported"); // bugbug: implement } else if (stmt is ProduceStmt) { WriteToken(stmt.Tok); var s = (ProduceStmt)stmt; if (s is YieldStmt) { WriteEAbort("BUGBUG ProduceStmt Yield unsupported"); // bugbug: implement. } else { using (WriteArray()) { j.WriteValue(KremlinAst.EReturn); // Dafny C# generates "return;" because methods are void. But // for Kremlin, if there is one [out] parameter it is translated // as a single return value. if (enclosingMethod.Outs.Count == 0) { WriteEUnit(); // No return value } else { var ReturnValue = enclosingMethod.Outs[0]; WriteEBound(ReturnValue); } } } } else if (stmt is UpdateStmt) { WriteToken(stmt.Tok); var s = (UpdateStmt)stmt; var resolved = s.ResolvedStatements; if (resolved.Count == 1) { TrStmt(resolved[0]); } else { Contract.Assert(s.Lhss.Count == resolved.Count); Contract.Assert(s.Rhss.Count == resolved.Count); // For each LHSS/RHSS pair, generate: // tmpN = rhsN // ... // lhssN = tmpN // so side effects to the LHSS's don't take place until after all // RHSS's have been evaluated. The complication is that the LHSS // may be an EBufWrite to an array element, or an EAssign to // a variable. // In Kremlin, this is: // let tmp0 = rhs0 in // let tmp1 = rhs1 in // ... in // { assign lhss0 = tmp0; // assign lhss1 = tmp1; // ... // } var rhss = new List<IVariable>(); for (int i = 0; i < resolved.Count; i++) { if (!resolved[i].IsGhost) { var lhs = s.Lhss[i]; var rhs = s.Rhss[i]; if (!(rhs is HavocRhs)) { var target = new BoundVar(resolved[i].Tok, idGenerator.FreshId("_rhs"), lhs.Type); rhss.Add(target); // ELet v in { Stmt j.WriteStartArray(); j.WriteValue(KremlinAst.ELet); j.WriteStartArray(); WriteBinder(target, target.Name, true); // lident TrRhs(target, null, rhs); // expr VarTracker.Push(target); // "in" is the contents that follow } } } using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { for (int i = 0; i < rhss.Count; i++) { TrAssign(s.Lhss[i], rhss[i]); } } } rhss.Reverse(); foreach (var l in rhss) { VarTracker.Pop(l); j.WriteEndArray(); // Closing out the list of binder * expr * expr j.WriteEndArray(); // Closing out the array above ELet } } } else if (stmt is AssignStmt) { WriteToken(stmt.Tok); AssignStmt s = (AssignStmt)stmt; Contract.Assert(!(s.Lhs is SeqSelectExpr) || ((SeqSelectExpr)s.Lhs).SelectOne); // multi-element array assignments are not allowed TrRhs(null, s.Lhs, s.Rhs); } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; if (s.AssumeToken != null) { // Note, a non-ghost AssignSuchThatStmt may contain an assume Error("an assume statement cannot be compiled (line {0})", wr, s.AssumeToken.line); } else if (s.MissingBounds != null) { foreach (var bv in s.MissingBounds) { Error("this assign-such-that statement is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", wr, bv.Name, s.Tok.line); } } else { Contract.Assert(s.Bounds != null); // follows from s.MissingBounds == null WriteToken(stmt.Tok); TrAssignSuchThat( s.Lhss.ConvertAll(lhs => ((IdentifierExpr)lhs.Resolved).Var), // the resolver allows only IdentifierExpr left-hand sides s.Expr, s.Bounds, s.Tok.line, false); } } else if (stmt is CallStmt) { WriteToken(stmt.Tok); CallStmt s = (CallStmt)stmt; TrCallStmt(s); } else if (stmt is BlockStmt) { WriteToken(stmt.Tok); using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { WriteEUnit(); // in case the statement list is empty TrStmtList(((BlockStmt)stmt).Body); } } } else if (stmt is IfStmt) { WriteToken(stmt.Tok); IfStmt s = (IfStmt)stmt; if (s.Guard == null) { // we can compile the branch of our choice if (s.Els == null) { // let's compile the "else" branch, since that involves no work // (still, let's leave a marker in the source code to indicate that this is what we did) j.WriteComment("if (!false) { }"); } else { // let's compile the "then" branch j.WriteComment("if (true)"); TrStmt(s.Thn); } } else { using (WriteArray()) { j.WriteValue(KremlinAst.EIfThenElse); using (WriteArray()) { TrExpr(s.IsExistentialGuard ? Translator.AlphaRename((ExistsExpr)s.Guard, "eg_d", new Translator(null)) : s.Guard, false); // We'd like to do "TrStmt(s.Thn, indent)", except we want the scope of any existential variables to come inside the block using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { WriteEUnit(); // in case the statement list is empty if (s.IsExistentialGuard) { IntroduceAndAssignBoundVars((ExistsExpr)s.Guard); } TrStmtList(s.Thn.Body); } } using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { WriteEUnit(); // in case the statement list is empty if (s.Els != null) { TrStmt(s.Els); } } } } } } } else if (stmt is AlternativeStmt) { WriteToken(stmt.Tok); var s = (AlternativeStmt)stmt; WriteEAbort("BUGBUG AlternativeStmt is unsupported"); // bugbug: a cascade of if/else if/else. } else if (stmt is WhileStmt) { WhileStmt s = (WhileStmt)stmt; if (s.Body == null) { return; } WriteToken(stmt.Tok); if (s.Guard == null) { j.WriteComment("while (false) { }"); WriteEUnit(); } else { using (WriteArray()) { j.WriteValue(KremlinAst.EWhile); using (WriteArray()) { // of (expr * expr) TrExpr(s.Guard, false); TrStmt(s.Body); } } } } else if (stmt is AlternativeLoopStmt) { WriteToken(stmt.Tok); var s = (AlternativeLoopStmt)stmt; WriteEAbort("BUGBUG AlternativeLoopStmt is unsupported"); // bugbug: implement } else if (stmt is ForallStmt) { var s = (ForallStmt)stmt; if (s.Kind != ForallStmt.ParBodyKind.Assign) { // Call and Proof have no side effects, so they can simply be optimized away. return; } else if (s.BoundVars.Count == 0) { // the bound variables just spell out a single point, so the forall statement is equivalent to one execution of the body WriteToken(stmt.Tok); TrStmt(s.Body); return; } var s0 = (AssignStmt)s.S0; if (s0.Rhs is HavocRhs) { // The forall statement says to havoc a bunch of things. This can be efficiently compiled // into doing nothing. return; } WriteToken(stmt.Tok); var rhs = ((ExprRhs)s0.Rhs).Expr; WriteEAbort("BUGBUG Forall is unsupported"); // bugbug: implement } else if (stmt is MatchStmt) { WriteToken(stmt.Tok); MatchStmt s = (MatchStmt)stmt; WriteEAbort("BUGBUG MatchStmt is unsupported"); // bugbug: implement } else if (stmt is VarDeclStmt) { var s = (VarDeclStmt)stmt; foreach (var local in s.Locals) { if (!local.IsGhost) { // Note that a new local was introduced, and assume the caller // will inject an ELet in the correct order, to match the // VarTracker state. varDeclsList.Add(local); VarTracker.Push(local); } } if (s.Update != null) { TrStmt(s.Update); } } else if (stmt is LetStmt) { WriteToken(stmt.Tok); var s = (LetStmt)stmt; for (int i = 0; i < s.LHSs.Count; i++) { var lhs = s.LHSs[i]; if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) { TrCasePatternOpt(lhs, s.RHSs[i], null, false); } } } else if (stmt is ModifyStmt) { WriteToken(stmt.Tok); var s = (ModifyStmt)stmt; if (s.Body != null) { TrStmt(s.Body); } } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement } }
void TrSeqDisplayElements(List<Expression> expr, Type seqType, bool inLetExprBody) { Contract.Requires(expr != null); Contract.Requires(seqType != null); // ELet tmpVar1 = let tmpVar2 = EBufCreateL (list of initializers) in _ in tmpVar1; var tmpVar1 = new BoundVar(expr[0].tok, idGenerator.FreshId("_seq"), seqType); using (WriteArray()) { j.WriteValue(KremlinAst.ELet); using (WriteArray()) { // of (binder * expr * expr) WriteBinder(tmpVar1, tmpVar1.Name, false); // binder using (WriteArray()) { // expr1 j.WriteValue(KremlinAst.EBufCreateL); // of expr list using (WriteArray()) { for (int i = 0; i < expr.Count; ++i) { TrExpr(expr[i], inLetExprBody); } } } VarTracker.Push(tmpVar1); WriteEBound(tmpVar1); // expr2 VarTracker.Pop(tmpVar1); } } }
// Invoked typically as TrRhs(variable, null, RhsExpr) <- UpdateStmt with multi-assignment // or TrRhs(null, LhsExpr, RhsExpr) <- AssignStmt void TrRhs(BoundVar target, Expression targetExpr, AssignmentRhs rhs) { Contract.Requires((target == null) != (targetExpr == null)); var tRhs = rhs as TypeRhs; if (rhs is HavocRhs) { // do nothing } else { using (WriteArray()) { j.WriteValue(KremlinAst.ESequence); using (WriteArray()) { WriteEUnit(); // For C#, Dafny calls TrExpr(targetExpr), emits "=" then TrAssignmentRhs(rhs), // For Kremlin, we may generate EAssign or EBufWrite depending on the // targetExpr type. The ELet has already been generated by the caller and // we are inside an ESequence, about to generate the RHS expression code. if (target != null) { TrAssignmentRhs(rhs); } else { if (targetExpr is SeqSelectExpr) { SeqSelectExpr e = (SeqSelectExpr)targetExpr; Contract.Assert(e.Seq.Type != null); if (!e.SelectOne) { WriteEAbort("BUGBUG: TrRhs is a SeqSelectExpr with SelectMany"); // bugbug: is this valid Dafny? } else { using (WriteArray()) { j.WriteValue(KremlinAst.EBufWrite); using (WriteArray()) { // of (expr * expr * expr) TrExpr(e.Seq, false); // expr1 - the buffer identifier TrBufferIndexSizeExpr(e.E0, false); // expr2 - the buffer offset TrAssignmentRhs(rhs); // expr3 - the value to write } } } } else if (targetExpr is IdentifierExpr) { using (WriteArray()) { j.WriteValue(KremlinAst.EAssign); using (WriteArray()) { var e = (IdentifierExpr)targetExpr; WriteEBound(e.Var); TrAssignmentRhs(rhs); } } } else if (targetExpr is MemberSelectExpr) { MemberSelectExpr e = (MemberSelectExpr)targetExpr; SpecialField sf = e.Member as SpecialField; if (sf != null) { WriteEAbort("BUGBUG MemberSelectExpr TrRhs if SpecialField not supported"); // bugbug: implement } else { // EAssign of // EField(lident, EBufRead( EBound(var), 0), FieldName) using (WriteArray()) { j.WriteValue(KremlinAst.EAssign); using (WriteArray()) { // of (expr * expr) // EAssign expr1 using (WriteArray()) { j.WriteValue(KremlinAst.EField); using (WriteArray()) { // of (lident * expr * ident) WriteLident(e.Obj.Type); using (WriteArray()) { j.WriteValue(KremlinAst.EBufRead); using (WriteArray()) { // of (expr * expr) TrExpr(e.Obj, false); // This will generate an EBound reference to the variable WriteConstant(0u); // expr2 is the offset (always 0) } } j.WriteValue(e.Member.Name); } } TrAssignmentRhs(rhs); // right-hand-side expression } } } } else { WriteEAbort("BUGBUG TrRhs of unsupported targetExpr type " + targetExpr.ToString()); } } if (tRhs != null && tRhs.InitCall != null) { // We have now generated: var target = Default value; // Generate statement: target.ctor(); var oldEnclosingThis = enclosingThis; if (target != null) { j.WriteComment("TrRhs of InitCall to target"); enclosingThis = target; TrCallStmt(tRhs.InitCall); // expr2 } else { // targetExpr should be turned into the enclosingThis using (WriteArray()) { string nw = idGenerator.FreshId("_nw"); enclosingThis = new BoundVar(targetExpr.tok, nw, targetExpr.Type); j.WriteValue(KremlinAst.ELet); using (WriteArray()) { // of (binder * expr * expr) WriteBinder(enclosingThis, nw, true); TrExpr(targetExpr, false); VarTracker.Push(enclosingThis); TrCallStmt(tRhs.InitCall); } VarTracker.Pop(enclosingThis); } } enclosingThis = oldEnclosingThis; } } } } }
void IdentTypeOptional(out BoundVar var) { Contract.Ensures(Contract.ValueAtReturn(out var) != null); IToken id; Type ty; Type optType = null; WildIdent(out id, true); if (la.kind == 21) { Get(); Type(out ty); optType = ty; } var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); }
public override BoundVar CloneBoundVar(BoundVar bv) { // The difference here from the overridden method is that we do CloneType(bv.Type) instead of CloneType(bv.SyntacticType) var bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.Type)); bvNew.IsGhost = bv.IsGhost; return bvNew; }
public virtual BoundVar CloneBoundVar(BoundVar bv) { var bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.SyntacticType)); bvNew.IsGhost = bv.IsGhost; return bvNew; }
public RtlVar AsVar(BoundVar x) { string name = GhostVar(x.Name); return(new RtlVar(name, x.IsGhost, AppType(x.Type))); }
public RtlVar AsVar(BoundVar x) { string name = GhostVar(x.Name); return new RtlVar(name, x.IsGhost, AppType(x.Type)); }