Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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());
        }
Exemplo n.º 6
0
    /// <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
      }
    }
Exemplo n.º 7
0
        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;
              }
        }
Exemplo n.º 8
0
        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
            }
              }
        }
Exemplo n.º 9
0
        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
              }
        }
Exemplo n.º 10
0
        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);
            }
              }
        }
Exemplo n.º 11
0
        // 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;
            }
              }
            }
              }
        }
Exemplo n.º 12
0
        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);
        }
Exemplo n.º 13
0
 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;
 }
Exemplo n.º 14
0
 public virtual BoundVar CloneBoundVar(BoundVar bv) {
   var bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.SyntacticType));
   bvNew.IsGhost = bv.IsGhost;
   return bvNew;
 }
Exemplo n.º 15
0
    public RtlVar AsVar(BoundVar x)
    {
        string name = GhostVar(x.Name);

        return(new RtlVar(name, x.IsGhost, AppType(x.Type)));
    }
Exemplo n.º 16
0
 public RtlVar AsVar(BoundVar x)
 {
     string name = GhostVar(x.Name);
     return new RtlVar(name, x.IsGhost, AppType(x.Type));
 }