예제 #1
0
    public RtlExp GhostLet(Microsoft.Boogie.IToken tok, List <BoundVar> lhss, List <RtlExp> rhss,
                           Func <RtlExp> body)
    {
        if (stmtExprEnabled && ignoreStmtExpr == 0)
        {
            var oldRenamer1 = PushRename();
            for (int i = 0; i < lhss.Count; i++)
            {
                var lhs = lhss[i];
                var rhs = rhss[i];
                AddGhostVarDecl(lhs.Name, lhs.Type, true);
                MoveGhost(new RtlVar(GhostVar(lhs.Name), true, AppType(lhs.Type)), rhs);
            }
            body();
            PopRename(oldRenamer1);
        }
        var oldRenamer2 = PushRename();

        lhss.ForEach(e => AddRename(e.Name));
        ignoreStmtExpr++;
        RtlExp rExp = new RtlLiteral("("
                                     + String.Concat(lhss.Zip(rhss, (lhs, rhs) =>
                                                              "let " + GhostVar(lhs.Name) + ":" + TypeString(AppType(lhs.Type))
                                                              + " := (" + rhs + ") in "))
                                     + " (" + body() + "))");

        ignoreStmtExpr--;
        PopRename(oldRenamer2);
        return(rExp);
    }
예제 #2
0
    public virtual void AddResolvedGhostStatement(Statement stmt)
    {
        BlockStmt          block      = stmt as BlockStmt;
        IfStmt             ifStmt     = stmt as IfStmt;
        AssertStmt         assertStmt = stmt as AssertStmt;
        AssignStmt         assignStmt = stmt as AssignStmt;
        CallStmt           callStmt   = stmt as CallStmt;
        VarDecl            varDecl    = stmt as VarDecl;
        CalcStmt           calcStmt   = stmt as CalcStmt;
        ForallStmt         forallStmt = stmt as ForallStmt;
        AssignSuchThatStmt existsStmt = stmt as AssignSuchThatStmt;

        if (block != null)
        {
            var oldRenamer = PushRename();
            block.Body.ForEach(AddGhostStatement);
            PopRename(oldRenamer);
        }
        else if (varDecl != null)
        {
            AddGhostVarDecl(varDecl.Name, varDecl.Type, varDecl.IsGhost);
        }
        else if (minVerify)
        {
            return;
        }
        else if (assignStmt != null)
        {
            ExprRhs expRhs = assignStmt.Rhs as ExprRhs;
            if (expRhs != null)
            {
                FieldSelectExpr fieldSelect = assignStmt.Lhs as FieldSelectExpr;
                RtlVar          destVar;
                if (fieldSelect != null)
                {
                    destVar = new RtlVar(GhostVar(fieldSelect.FieldName), true, fieldSelect.Type);
                }
                else
                {
                    destVar = AsVar(assignStmt.Lhs);
                    Util.Assert(destVar != null);
                }
                stmts.Add(new RtlGhostMove(new RtlVar[] { destVar },
                                           new RtlExp[] { GhostExpression(expRhs.Expr) }));
            }
            else
            {
                throw new Exception("not implemented: " + assignStmt.Rhs);
            }
        }
        else if (callStmt != null)
        {
            AddGhostCall(callStmt.Lhs.ConvertAll(AsVar), callStmt.Args,
                         dafnySpec.Compile_Method(callStmt.Method,
                                                  callStmt.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))),
                         DafnySpec.IsHeapMethod(callStmt.Method));
            SymdiffLinearityPoint();
        }
        else if (ifStmt != null)
        {
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                                               new RtlExp[] { GhostExpression(ifStmt.Guard) }));
            Indent();
            AddGhostStatement(ifStmt.Thn);
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            if (ifStmt.Els != null)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                                                   new RtlExp[] {
                    GhostExpression(new UnaryExpr(Bpl.Token.NoToken, UnaryExpr.Opcode.Not, ifStmt.Guard))
                }));
                Indent();
                AddGhostStatement(ifStmt.Els);
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else if (assertStmt != null)
        {
            stmts.Add(new RtlAssert(GhostExpression(assertStmt.Expr)));
        }
        else if (forallStmt != null)
        {
            var    oldRenamer = PushRename(forallStmt.BoundVars.Select(v => v.Name));
            RtlExp ens        = new RtlLiteral("true");
            foreach (var e in forallStmt.Ens)
            {
                ens = new RtlBinary("&&", ens, GhostExpression(e.E));
            }
            RtlExp range = (forallStmt.Range == null) ? new RtlLiteral("true")
                : GhostExpression(forallStmt.Range);
            List <RtlExp> wellFormed = GetTypeWellFormed(forallStmt.BoundVars.
                                                         Select(x => Tuple.Create(GhostVar(x.Name), x.IsGhost, x.Type)).ToList());
            wellFormed.ForEach(e => range = new RtlBinary("&&", e, range));
            ens = new RtlBinary("==>", range, ens);
            string vars = String.Join(", ", forallStmt.BoundVars.Select(x => GhostVar(x.Name) + ":" +
                                                                        TypeString(AppType(x.Type))));
            stmts.Add(new RtlGhostStmtComputed(s => "forall " + vars + "::(" + s.args[0] + ")",
                                               new List <RtlExp> {
                ens
            }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            stmts.Add(PushForall());
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                                               new List <RtlExp> {
                range
            }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            AddGhostStatement(forallStmt.Body);
            foreach (var e in forallStmt.Ens)
            {
                stmts.Add(new RtlAssert(GhostExpression(e.E)));
            }
            PopForall();
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            PopRename(oldRenamer);
        }
        else if (existsStmt != null)
        {
            List <RtlStmt> assigns = new List <RtlStmt>();
            List <RtlVar>  tmps    = new List <RtlVar>();
            List <Tuple <string, bool, Type> > varTuples = new List <Tuple <string, bool, Type> >();
            var oldRenamer = PushRename();
            foreach (var lhs in existsStmt.Lhss)
            {
                IdentifierExpr idExp   = lhs.Resolved as IdentifierExpr;
                RtlVar         origVar = AsVar(lhs);
                AddRename(idExp.Name);
                RtlVar renameVar = AsVar(lhs);
                tmps.Add(renameVar);
                varTuples.Add(Tuple.Create(renameVar.ToString(), true, idExp.Type));
                assigns.Add(new RtlGhostMove(new RtlVar[] { origVar },
                                             new RtlExp[] { renameVar }));
            }
            string vars = String.Join(", ", tmps.Select(x => x.getName() + ":" + TypeString(AppType(x.type))));
            stmts.Add(new RtlGhostStmtComputed(s => "exists " + vars + "::(" + s.args[0] + ");",
                                               new List <RtlExp> {
                GetTypeWellFormedExp(varTuples.ToList(), "&&", GhostExpression(existsStmt.Expr))
            }));
            stmts.AddRange(assigns);
            PopRename(oldRenamer);
        }
        else if (calcStmt != null)
        {
            Util.Assert(calcStmt.Steps.Count == calcStmt.Hints.Count);
            CalcStmt.BinaryCalcOp binOp = calcStmt.Op as CalcStmt.BinaryCalcOp;
            bool isImply = binOp != null && binOp.Op == BinaryExpr.Opcode.Imp && calcStmt.Steps.Count > 0;
            if (isImply)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                                                   new RtlExp[] { GhostExpression(CalcStmt.Lhs(calcStmt.Steps[0])) }));
                stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                Indent();
            }
            var stepCount = calcStmt.Hints.Last().Body.Count == 0 ? calcStmt.Steps.Count - 1 : calcStmt.Steps.Count;
            for (int i = 0; i < stepCount; i++)
            {
                if (calcStmt.Hints[i] == null)
                {
                    stmts.Add(new RtlAssert(GhostExpression(calcStmt.Steps[i])));
                }
                else
                {
                    stmts.Add(new RtlGhostStmtComputed(s => "forall::(" + s.args[0] + ")",
                                                       new List <RtlExp> {
                        GhostExpression(calcStmt.Steps[i])
                    }));
                    stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                    Indent();
                    var dict = new Dictionary <string, RtlVar>();
                    stmts.Add(new RtlGhostStmtComputed(s => String.Concat(dict.Values.Select(
                                                                              x => "var " + x.x + ":" + TypeString(x.type) + ";")),
                                                       new RtlExp[0]));
                    forallVars.Add(dict);
                    AddGhostStatement(calcStmt.Hints[i]);
                    forallVars.RemoveAt(forallVars.Count - 1);
                    Unindent();
                    stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
                }
            }
            if (isImply)
            {
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else
        {
            throw new Exception("not implemented in ghost methods: " + stmt);
        }
    }
예제 #3
0
    public RtlExp GhostExpressionRec(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false)
    {
        Util.Assert(!isPrinting);
        exp = GetExp(exp);
        StmtExpr         stmtExpr    = exp as StmtExpr;
        IdentifierExpr   idExp       = exp as IdentifierExpr;
        LiteralExpr      literal     = exp as LiteralExpr;
        BinaryExpr       binary      = exp as BinaryExpr;
        UnaryExpr        unary       = exp as UnaryExpr;
        ITEExpr          ite         = exp as ITEExpr;
        ExistsExpr       existsExp   = exp as ExistsExpr;
        ForallExpr       forallExp   = exp as ForallExpr;
        LetExpr          letExp      = exp as LetExpr;
        MatchExpr        matchExp    = exp as MatchExpr;
        OldExpr          oldExp      = exp as OldExpr;
        FreshExpr        freshExp    = exp as FreshExpr;
        FunctionCallExpr funCall     = exp as FunctionCallExpr;
        DatatypeValue    dataVal     = exp as DatatypeValue;
        FieldSelectExpr  fieldSelect = exp as FieldSelectExpr;
        SeqSelectExpr    seqSelect   = exp as SeqSelectExpr;
        SeqUpdateExpr    seqUpdate   = exp as SeqUpdateExpr;
        SeqDisplayExpr   seqDisplay  = exp as SeqDisplayExpr;

        Func <Expression, RtlExp> G = e => GhostExpression(e, inRecSpec, inRequiresOrOld);

        if (stmtExpr != null)
        {
            if (stmtExprEnabled)
            {
                if (ignoreStmtExpr == 0)
                {
                    AddGhostStatement(stmtExpr.S);
                }
                return(G(stmtExpr.E));
            }
            else
            {
                throw new Exception("not implemented: cannot handle statement expression here");
            }
        }
        else if (idExp != null)
        {
            return(AsVar(idExp));
        }
        else if (literal != null && literal.Value is BigInteger)
        {
            return(new RtlInt((BigInteger)(literal.Value)));
        }
        else if (literal != null && literal.Value is bool)
        {
            return(new RtlLiteral((bool)(literal.Value) ? "true" : "false"));
        }
        else if (literal != null && literal.Value == null)
        {
            return(new RtlLiteral("ArrayOfInt(0 - 1, NO_ABS)"));
        }
        else if (literal != null && literal.Value is Microsoft.Basetypes.BigDec)
        {
            return(new RtlLiteral(((Microsoft.Basetypes.BigDec)literal.Value).ToDecimalString()));
        }
        else if (binary != null)
        {
            string          op              = null;
            string          internalOp      = null;
            CompileFunction compileFunction = this as CompileFunction;
            string          thisFuncName    = (compileFunction == null) ? null : compileFunction.function.Name;
            switch (binary.ResolvedOp)
            {
            case BinaryExpr.ResolvedOpcode.SeqEq:
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                                    new RtlExp[] { G(binary.E0), G(binary.E1) }));

            case BinaryExpr.ResolvedOpcode.SeqNeq:
                return(new RtlLiteral("(!" +
                                      new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                                                   new RtlExp[] { G(binary.E0), G(binary.E1) }) + ")"));

            case BinaryExpr.ResolvedOpcode.Concat:
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.Type), "Seq_Append"),
                                    new RtlExp[] { G(binary.E0), G(binary.E1) }));
            }
            if (binary.Op == BinaryExpr.Opcode.Exp)
            {
                binary = new BinaryExpr(binary.tok, BinaryExpr.Opcode.Imp, binary.E0, binary.E1);
            }
            switch (binary.Op)
            {
            case BinaryExpr.Opcode.Disjoint:
            case BinaryExpr.Opcode.In:
            case BinaryExpr.Opcode.NotIn:
                throw new Exception("not implemented: binary operator '" + BinaryExpr.OpcodeString(binary.Op) + "'");
            }
            if (AppType(binary.E0.Type) is IntType && AppType(binary.E1.Type) is IntType)
            {
                switch (binary.Op)
                {
                case BinaryExpr.Opcode.Le: internalOp = "INTERNAL_le_boogie"; break;

                case BinaryExpr.Opcode.Lt: internalOp = "INTERNAL_lt_boogie"; break;

                case BinaryExpr.Opcode.Ge: internalOp = "INTERNAL_ge_boogie"; break;

                case BinaryExpr.Opcode.Gt: internalOp = "INTERNAL_gt_boogie"; break;

                case BinaryExpr.Opcode.Add: internalOp = "INTERNAL_add_boogie"; break;

                case BinaryExpr.Opcode.Sub: internalOp = "INTERNAL_sub_boogie"; break;

                case BinaryExpr.Opcode.Mul:
                    op = "*";
                    if (thisFuncName != "INTERNAL_mul")
                    {
                        internalOp = FunName("INTERNAL__mul");
                    }
                    break;

                case BinaryExpr.Opcode.Div:
                    op = "div";
                    if (thisFuncName != "INTERNAL_div")
                    {
                        internalOp = FunName("INTERNAL__div");
                    }
                    break;

                case BinaryExpr.Opcode.Mod:
                    op = "mod";
                    if (thisFuncName != "INTERNAL_mod")
                    {
                        internalOp = FunName("INTERNAL__mod");
                    }
                    break;

                default:
                    op = BinaryExpr.OpcodeString(binary.Op);
                    break;
                }
            }
            else
            {
                op = BinaryExpr.OpcodeString(binary.Op);
            }
            if (internalOp == null)
            {
                return(new RtlBinary(op, G(binary.E0), G(binary.E1)));
            }
            else
            {
                return(new RtlApply(internalOp, new RtlExp[]
                                    { G(binary.E0), G(binary.E1) }));
            }
        }
        else if (unary != null && unary.Op == UnaryExpr.Opcode.Not)
        {
            return(new RtlLiteral("(!(" + G(unary.E) + "))"));
        }
        else if (unary != null && unary.Op == UnaryExpr.Opcode.SeqLength)
        {
            return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(unary.E.Type), "Seq_Length"),
                                new RtlExp[] { G(unary.E) }));
        }
        else if (ite != null)
        {
            return(GhostIfThenElse(G(ite.Test), () => G(ite.Thn), () => G(ite.Els)));
        }
        else if (funCall != null)
        {
            switch (funCall.Function.Name)
            {
            case "left":
            case "right":
            case "relation":
            case "public":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply(funCall.Function.Name, new RtlExp[] { G(funCall.Args[0]) }));

            case "sizeof":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply(funCall.Function.Name + "##" + TypeString(AppType(funCall.Args[0].Type)),
                                    new RtlExp[] { G(funCall.Args[0]) }));

            case "INTERNAL_add_raw":
                Util.Assert(funCall.Args.Count == 2);
                return(new RtlBinary("+", G(funCall.Args[0]), G(funCall.Args[1])));

            case "INTERNAL_sub_raw":
                Util.Assert(funCall.Args.Count == 2);
                return(new RtlBinary("-", G(funCall.Args[0]), G(funCall.Args[1])));

            case "IntToReal":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply("real", new RtlExp[] { G(funCall.Args[0]) }));

            case "RealToInt":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply("int", new RtlExp[] { G(funCall.Args[0]) }));
            }
            TypeApply app = dafnySpec.Compile_Function(funCall.Function,
                                                       funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value)));
            string        name     = FunName(SimpleName(app.AppName()));
            string        fullName = FunName(SimpleName(app.AppFullName()));
            List <RtlExp> rtlArgs  = funCall.Args.Select(G).ToList();
            List <RtlExp> rtlReads = funCall.Function.Reads.Where(e => e.Field != null).ToList()
                                     .ConvertAll(e => (RtlExp) new RtlVar(
                                                     GhostVar(e.FieldName), e.Field.IsGhost, AppType(e.Field.Type)));
            rtlArgs = rtlReads.Concat(rtlArgs).ToList();
            if (name.EndsWith("__INTERNAL__HEAP"))
            {
                name = name.Substring(0, name.Length - "__INTERNAL__HEAP".Length);
            }
            else if (DafnySpec.IsHeapFunction(funCall.Function))
            {
                rtlArgs.Insert(0, new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"));
            }
            if (Attributes.Contains(funCall.Function.Attributes, "opaque") &&
                funCall.Function.Formals.Count + rtlReads.Count == 0)
            {
                rtlArgs.Insert(0, new RtlLiteral("true"));
            }
            if (fullName == recFunName)
            {
                name = fullName;
            }
            if (name == recFunName)
            {
                recCalls.Add(new List <RtlExp>(rtlArgs));
                rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List <RtlExp>(rtlArgs)));
                rtlArgs.Insert(1, new RtlLiteral(inRecSpec ? "__unroll" : "__unroll + 1"));
                name = "rec_" + name;
            }
            return(new RtlApply(name, rtlArgs));
        }
        else if (dataVal != null)
        {
            bool isSeq = dataVal.Type.TypeName(null).StartsWith("Seq<");
            return(new RtlApply((isSeq ? "_" : "") + dafnySpec.Compile_Constructor(
                                    dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(),
                                dataVal.Arguments.Select(G)));
        }
        else if (existsExp != null || forallExp != null)
        {
            QuantifierExpr qExp               = (QuantifierExpr)exp;
            bool           isForall           = forallExp != null;
            var            varTuples          = qExp.BoundVars.Select(v => Tuple.Create(GhostVar(v.Name), v.IsGhost, v.Type));
            var            oldRenamer         = PushRename(qExp.BoundVars.Select(v => v.Name));
            var            oldStmtExprEnabled = stmtExprEnabled;
            stmtExprEnabled = false;
            RtlExp rExp = new RtlLiteral((isForall ? "(forall " : "(exists ")
                                         + string.Join(", ", qExp.BoundVars.Select(v => GhostVar(v.Name) + ":" + TypeString(AppType(v.Type))))
                                         + " :: " + Triggers(qExp.Attributes, G) + " "
                                         + GetTypeWellFormedExp(varTuples.ToList(), isForall ? "==>" : "&&", G(qExp.Term)) + ")");
            stmtExprEnabled = oldStmtExprEnabled;
            PopRename(oldRenamer);
            return(rExp);
        }
        else if (letExp != null)
        {
            List <RtlExp> rhss;
            if (letExp.Exact)
            {
                rhss = letExp.RHSs.ConvertAll(e => G(e));
            }
            else if (letExp.LHSs.Count == 1 && LiteralExpr.IsTrue(letExp.RHSs[0]) && AppType(letExp.LHSs[0].Var.Type) is IntType)
            {
                rhss = new List <RtlExp> {
                    new RtlLiteral("0")
                };
            }
            else
            {
                throw new Exception("not implemented: LetExpr: " + letExp);
            }
            return(GhostLet(exp.tok, letExp.LHSs.ConvertAll(lhs => lhs.Var), rhss, () => G(letExp.Body)));
        }
        else if (matchExp != null)
        {
            if (matchExp.MissingCases.Count != 0)
            {
                throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp);
            }
            //- match src case c1(ps1) => e1 ... cn(psn) => en
            //-   -->
            //- let x := src in
            //-   if x is c1 then let ps1 := ...x.f1... in e1 else
            //-   if x is c2 then let ps2 := ...x.f2... in e2 else
            //-                   let ps3 := ...x.f3... in e3
            var           src   = G(matchExp.Source);
            var           cases = matchExp.Cases;
            string        x     = TempName();
            Func <RtlExp> body  = null;
            for (int i = cases.Count; i > 0;)
            {
                i--;
                MatchCaseExpr         c     = cases[i];
                Func <List <RtlExp> > cRhss = () => c.Ctor.Formals.ConvertAll(f => (RtlExp) new RtlLiteral("("
                                                                                                           + f.Name + "#" + c.Ctor.Name + "(" + GhostVar(x) + "))"));
                Func <RtlExp> ec = () => GhostLet(exp.tok, c.Arguments, cRhss(), () => G(c.Body));
                if (body == null)
                {
                    body = ec;
                }
                else
                {
                    var prevBody = body;
                    body = () => GhostIfThenElse(new RtlLiteral("(" + GhostVar(x) + " is " + c.Ctor.Name + ")"),
                                                 ec, prevBody);
                }
            }
            return(GhostLet(exp.tok, new List <BoundVar> {
                new BoundVar(exp.tok, x, matchExp.Source.Type)
            },
                            new List <RtlExp> {
                src
            }, body));
        }
        else if (oldExp != null)
        {
            return(new RtlLiteral("old(" + GhostExpression(oldExp.E, inRecSpec, true) + ")"));
        }
        else if (freshExp != null)
        {
            Util.Assert(DafnySpec.IsArrayType(freshExp.E.Type));
            string abs = G(freshExp.E) + ".arrAbs";
            return(new RtlLiteral("(heap_old.absData[" + abs + "] is AbsNone)"));
        }
        else if (fieldSelect != null && fieldSelect.FieldName.EndsWith("?"))
        {
            string constructor = fieldSelect.FieldName.Substring(0, fieldSelect.FieldName.Length - 1);
            constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type, constructor, null, typeApply.typeArgs).AppName();
            bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return(isSeq
                ? new RtlLiteral("is_" + constructor + "(" + G(fieldSelect.Obj) + ")")
                : new RtlLiteral("((" + G(fieldSelect.Obj) + ") is " + constructor + ")"));
        }
        else if (fieldSelect != null && !fieldSelect.Field.IsStatic && AppType(fieldSelect.Obj.Type) is UserDefinedType &&
                 fieldSelect.Field is DatatypeDestructor)
        {
            DatatypeDestructor field       = (DatatypeDestructor)fieldSelect.Field;
            string             constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type,
                                                                           field.EnclosingCtor.Name, null, typeApply.typeArgs).AppName();
            bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return(new RtlLiteral("(" + fieldSelect.FieldName + (isSeq ? "_" : "#") + constructor
                                  + "(" + G(fieldSelect.Obj) + "))"));
        }
        else if (fieldSelect != null && DafnySpec.IsArrayType(AppType(fieldSelect.Obj.Type)) &&
                 fieldSelect.FieldName == "Length")
        {
            return(new RtlLiteral("(Arr_Length(" + G(fieldSelect.Obj) + "))"));
        }
        else if (fieldSelect != null && fieldSelect.Obj is ImplicitThisExpr)
        {
            //- we don't support objects yet, so interpret this as a global variable
            return(new RtlVar(GhostVar(fieldSelect.FieldName), true, fieldSelect.Type));
        }
        else if (seqSelect != null)
        {
            if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
            {
                return(new RtlExpComputed(e => "fun_INTERNAL__array__elems__index("
                                          + (inRequiresOrOld ? "$absMem_old" : "$absMem") + "[" + e.args[0] + ".arrAbs], ("
                                          + e.args[1] + "))", new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }));
            }
            else if (seqSelect.SelectOne)
            {
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Seq.Type), "Seq_Index"),
                                    new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }));
            }
            else
            {
                RtlExp seq = G(seqSelect.Seq);
                if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
                {
                    seq = new RtlApply(FunName("Seq__FromArray"), new RtlExp[] {
                        new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"), seq
                    });
                }
                if (seqSelect.E1 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Take"),
                                       new RtlExp[] { seq, G(seqSelect.E1) });
                }
                if (seqSelect.E0 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Drop"),
                                       new RtlExp[] { seq, G(seqSelect.E0) });
                }
                return(seq);
            }
        }
        else if (seqUpdate != null)
        {
            if (seqUpdate.ResolvedUpdateExpr != null)
            {
                return(GhostExpressionRec(seqUpdate.ResolvedUpdateExpr, inRecSpec, inRequiresOrOld));
            }
            return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqUpdate.Seq.Type), "Seq_Update"),
                                new RtlExp[] { G(seqUpdate.Seq), G(seqUpdate.Index), G(seqUpdate.Value) }));
        }
        else if (seqDisplay != null)
        {
            RtlExp seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Empty"), new RtlExp[0]);
            foreach (Expression ei in seqDisplay.Elements)
            {
                seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Build"),
                                   new RtlExp[] { seq, G(ei) });
            }
            return(seq);
        }
        else
        {
            throw new Exception("not implemented: " + exp);
        }
    }
예제 #4
0
    public virtual void AddResolvedGhostStatement(Statement stmt, Attributes attrs)
    {
        BlockStmt block = stmt as BlockStmt;
        IfStmt ifStmt = stmt as IfStmt;
        AssertStmt assertStmt = stmt as AssertStmt;
        AssignStmt assignStmt = stmt as AssignStmt;
        CallStmt callStmt = stmt as CallStmt;
        VarDeclStmt varDecl = stmt as VarDeclStmt;
        CalcStmt calcStmt = stmt as CalcStmt;
        ForallStmt forallStmt = stmt as ForallStmt;
        AssignSuchThatStmt existsStmt = stmt as AssignSuchThatStmt;

        if (block != null)
        {
            var oldRenamer = PushRename();
            block.Body.ForEach(s => AddGhostStatement(s, attrs));
            PopRename(oldRenamer);
        }
        else if (varDecl != null)
        {
            foreach (var varLocal in varDecl.Locals) { 
                AddGhostVarDecl(varLocal.Name, varLocal.Type, varLocal.IsGhost);
            }

            if (varDecl.Update != null) {                
                Util.Assert(varDecl.Update is UpdateStmt || varDecl.Update is AssignSuchThatStmt);
                AddGhostStatement((Statement)varDecl.Update, attrs);
                //Util.Assert(varDecl.Update.Lhss.Count() == 1);
                //var destVar = AsVar(varDecl.Update.Lhss[0]);
                //Util.Assert(destVar != null);
                //ExprRhs expRhs = ((UpdateStmt)varDecl.Update).Rhss[0] as ExprRhs;
                //if (expRhs != null) { 
                //    stmts.Add(new RtlGhostMove(new RtlVar[] { destVar },
                //        new RtlExp[] { GhostExpression(expRhs.Expr) }));
                //} else {
                //    throw new Exception("not implemented: " + ((UpdateStmt)varDecl.Update).Rhss[0]);
                //}
            }
        }
        else if (minVerify)
        {
            return;
        }
        else if (assignStmt != null)
        {
            ExprRhs expRhs = assignStmt.Rhs as ExprRhs;
            if (expRhs != null)
            {
              MemberSelectExpr memberSelect = assignStmt.Lhs as MemberSelectExpr;
                RtlVar destVar;
                if (memberSelect != null && memberSelect.Member is Field)
                {
                    // assume that this is a global variable; we don't support objects yet
                    destVar = new RtlVar(GhostVar(memberSelect.MemberName), true, memberSelect.Type);
                }
                else
                {
                    destVar = AsVar(assignStmt.Lhs);
                    Util.Assert(destVar != null);
                }
                stmts.Add(new RtlGhostMove(new RtlVar[] { destVar },
                    new RtlExp[] { GhostExpression(expRhs.Expr) }));
            }
            else
            {
                throw new Exception("not implemented: " + assignStmt.Rhs);
            }
        }
        else if (callStmt != null)
        {
            var extraTypeargs = GetTypeArgs(attrs);
            var extraTypeargsDict = extraTypeargs.Select((t,index) => Tuple.Create(new TypeParameter(callStmt.Tok, "Fake" + index),t)).ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);
            var subst = callStmt.MethodSelect.TypeArgumentSubstitutions().Concat(extraTypeargsDict);

            AddGhostCall(callStmt.Lhs.ConvertAll(AsVar), callStmt.Args,
                dafnySpec.Compile_Method((Method)callStmt.MethodSelect.Member,
                    subst.ToDictionary(p => p.Key, p => AppType(p.Value)),
                    extraTypeargsDict.Keys.ToList()),
                DafnySpec.IsHeapMethod((Method)callStmt.MethodSelect.Member));
            SymdiffLinearityPoint();
        }
        else if (ifStmt != null)
        {
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                new RtlExp[] { GhostExpression(ifStmt.Guard) }));
            Indent();
            AddGhostStatement(ifStmt.Thn, attrs);
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            if (ifStmt.Els != null)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                    new RtlExp[] {
                        GhostExpression(new UnaryOpExpr(Bpl.Token.NoToken, UnaryOpExpr.Opcode.Not, ifStmt.Guard)) }));
                Indent();
                AddGhostStatement(ifStmt.Els, attrs);
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else if (assertStmt != null)
        {
            stmts.Add(new RtlAssert(GhostExpression(assertStmt.Expr)));
        }
        else if (forallStmt != null)
        {
            var oldRenamer = PushRename(forallStmt.BoundVars.Select(v => v.Name));
            RtlExp ens = new RtlLiteral("true");
            foreach (var e in forallStmt.Ens)
            {
                ens = new RtlBinary("&&", ens, GhostExpression(e.E));
            }
            RtlExp range = (forallStmt.Range == null) ? new RtlLiteral("true")
                : GhostExpression(forallStmt.Range);
            List<RtlExp> wellFormed = GetTypeWellFormed(forallStmt.BoundVars.
                Select(x => Tuple.Create(GhostVar(x.Name), x.IsGhost, x.Type)).ToList());
            wellFormed.ForEach(e => range = new RtlBinary("&&", e, range));
            ens = new RtlBinary("==>", range, ens);
            string vars = String.Join(", ", forallStmt.BoundVars.Select(x => GhostVar(x.Name) + ":" +
                TypeString(AppType(x.Type))));
            stmts.Add(new RtlGhostStmtComputed(s => "forall " + vars + "::(" + s.args[0] + ")",
                new List<RtlExp> { ens }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            stmts.Add(PushForall());
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                new List<RtlExp> { range }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            AddGhostStatement(forallStmt.Body, attrs);
            foreach (var e in forallStmt.Ens)
            {
                stmts.Add(new RtlAssert(GhostExpression(e.E)));
            }
            PopForall();
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            PopRename(oldRenamer);
        }
        else if (existsStmt != null)
        {
            List<RtlStmt> assigns = new List<RtlStmt>();
            List<RtlVar> tmps = new List<RtlVar>();
            List<Tuple<string,bool,Type>> varTuples = new List<Tuple<string,bool,Type>>();
            var oldRenamer = PushRename();
            foreach (var lhs in existsStmt.Lhss)
            {
                IdentifierExpr idExp = lhs.Resolved as IdentifierExpr;
                RtlVar origVar = AsVar(lhs);
                AddRename(idExp.Name);
                RtlVar renameVar = AsVar(lhs);
                tmps.Add(renameVar);
                varTuples.Add(Tuple.Create(renameVar.ToString(), true, idExp.Type));
                assigns.Add(new RtlGhostMove(new RtlVar[] { origVar },
                    new RtlExp[] { renameVar }));
            }
            string vars = String.Join(", ", tmps.Select(x => x.getName() + ":" + TypeString(AppType(x.type))));
            stmts.Add(new RtlGhostStmtComputed(s => "exists " + vars + "::(" + s.args[0] + ");",
                new List<RtlExp> {
                    GetTypeWellFormedExp(varTuples.ToList(), "&&", GhostExpression(existsStmt.Expr)) }));
            stmts.AddRange(assigns);
            PopRename(oldRenamer);
        }
        else if (calcStmt != null)
        {
            Util.Assert(calcStmt.Steps.Count == calcStmt.Hints.Count);
            CalcStmt.BinaryCalcOp binOp = calcStmt.Op as CalcStmt.BinaryCalcOp;
            bool isImply = binOp != null && binOp.Op == BinaryExpr.Opcode.Imp && calcStmt.Steps.Count > 0;
            if (isImply)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                    new RtlExp[] { GhostExpression(CalcStmt.Lhs(calcStmt.Steps[0])) }));
                stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                Indent();
            }
            var stepCount = calcStmt.Hints.Last().Body.Count == 0 ? calcStmt.Steps.Count - 1 : calcStmt.Steps.Count;
            for (int i = 0; i < stepCount; i++)
            {
                if (calcStmt.Hints[i] == null)
                {
                    stmts.Add(new RtlAssert(GhostExpression(calcStmt.Steps[i])));
                }
                else
                {
                    stmts.Add(new RtlGhostStmtComputed(s => "forall::(" + s.args[0] + ")",
                        new List<RtlExp> { GhostExpression(calcStmt.Steps[i]) }));
                    stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                    Indent();
                    var dict = new Dictionary<string,RtlVar>();
                    stmts.Add(new RtlGhostStmtComputed(s => String.Concat(dict.Values.Select(
                        x => "var " + x.x + ":" + TypeString(x.type) + ";")),
                        new RtlExp[0]));
                    forallVars.Add(dict);
                    AddGhostStatement(calcStmt.Hints[i], attrs);
                    forallVars.RemoveAt(forallVars.Count - 1);
                    Unindent();
                    stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
                }
            }
            if (isImply)
            {
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else
        {
            throw new Exception("not implemented in ghost methods: " + stmt);
        }
    }
예제 #5
0
    public RtlExp GhostExpressionRec(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false)
    {
        Util.Assert(!isPrinting);
        exp = GetExp(exp);
        StmtExpr stmtExpr = exp as StmtExpr;
        IdentifierExpr idExp = exp as IdentifierExpr;
        LiteralExpr literal = exp as LiteralExpr;
        BinaryExpr binary = exp as BinaryExpr;
        UnaryExpr unary = exp as UnaryExpr;
        ITEExpr ite = exp as ITEExpr;
        ExistsExpr existsExp = exp as ExistsExpr;
        ForallExpr forallExp = exp as ForallExpr;
        LetExpr letExp = exp as LetExpr;
        MatchExpr matchExp = exp as MatchExpr;
        OldExpr oldExp = exp as OldExpr;
        FunctionCallExpr funCall = exp as FunctionCallExpr;
        DatatypeValue dataVal = exp as DatatypeValue;
        MemberSelectExpr memberSelect = exp as MemberSelectExpr;
        SeqSelectExpr seqSelect = exp as SeqSelectExpr;
        SeqUpdateExpr seqUpdate = exp as SeqUpdateExpr;
        SeqDisplayExpr seqDisplay = exp as SeqDisplayExpr;

        Func<Expression,RtlExp> G = e => GhostExpression(e, inRecSpec, inRequiresOrOld);

        if (stmtExpr != null)
        {
            if (stmtExprEnabled)
            {
                if (ignoreStmtExpr == 0)
                {
                    AddGhostStatement(stmtExpr.S, null);
                }
                return G(stmtExpr.E);
            }
            else
            {
                throw new Exception("not implemented: cannot handle statement expression here");
            }
        }
        else if (idExp != null)
        {
            return AsVar(idExp);
        }
        else if (literal != null && literal.Value is BigInteger)
        {
            return new RtlInt((BigInteger)(literal.Value));
        }
        else if (literal != null && literal.Value is bool)
        {
            return new RtlLiteral((bool)(literal.Value) ? "true" : "false");
        }
        else if (literal != null && literal.Value == null)
        {
            return new RtlLiteral("ArrayOfInt(0 - 1, NO_ABS)");
        }
        else if (literal != null && literal.Value is Microsoft.Basetypes.BigDec)
        {
            return new RtlLiteral(((Microsoft.Basetypes.BigDec)literal.Value).ToDecimalString());
        }
        else if (binary != null)
        {
            string op = null;
            string internalOp = null;
            CompileFunction compileFunction = this as CompileFunction;
            string thisFuncName = (compileFunction == null) ? null : compileFunction.function.Name;
            switch (binary.ResolvedOp)
            {
                case BinaryExpr.ResolvedOpcode.SeqEq:
                    return new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                        new RtlExp[] { G(binary.E0), G(binary.E1) });
                case BinaryExpr.ResolvedOpcode.SeqNeq:
                    return new RtlLiteral("(!" +
                        new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                            new RtlExp[] { G(binary.E0), G(binary.E1) }) + ")");
                case BinaryExpr.ResolvedOpcode.Concat:
                    return new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.Type), "Seq_Append"),
                        new RtlExp[] { G(binary.E0), G(binary.E1) });
            }
            if (binary.Op == BinaryExpr.Opcode.Exp)
            {
                binary = new BinaryExpr(binary.tok, BinaryExpr.Opcode.Imp, binary.E0, binary.E1);
            }
            switch (binary.Op)
            {
                case BinaryExpr.Opcode.Disjoint:
                case BinaryExpr.Opcode.In:
                case BinaryExpr.Opcode.NotIn:
                    throw new Exception("not implemented: binary operator '" + BinaryExpr.OpcodeString(binary.Op) + "'");
            }
            if (AppType(binary.E0.Type) is IntType && AppType(binary.E1.Type) is IntType)
            {
                switch (binary.Op)
                {
                    case BinaryExpr.Opcode.Le: internalOp = "INTERNAL_le_boogie"; break;
                    case BinaryExpr.Opcode.Lt: internalOp = "INTERNAL_lt_boogie"; break;
                    case BinaryExpr.Opcode.Ge: internalOp = "INTERNAL_ge_boogie"; break;
                    case BinaryExpr.Opcode.Gt: internalOp = "INTERNAL_gt_boogie"; break;
                    case BinaryExpr.Opcode.Add: internalOp = "INTERNAL_add_boogie"; break;
                    case BinaryExpr.Opcode.Sub: internalOp = "INTERNAL_sub_boogie"; break;
                    case BinaryExpr.Opcode.Mul:
                        op = "*";
                        if (thisFuncName != "INTERNAL_mul")
                        {
                            internalOp = FunName("INTERNAL__mul");
                        }
                        break;
                    case BinaryExpr.Opcode.Div:
                        op = "div";
                        if (thisFuncName != "INTERNAL_div")
                        {
                            internalOp = FunName("INTERNAL__div");
                        }
                        break;
                    case BinaryExpr.Opcode.Mod:
                        op = "mod";
                        if (thisFuncName != "INTERNAL_mod")
                        {
                            internalOp = FunName("INTERNAL__mod");
                        }
                        break;
                    default:
                        op = BinaryExpr.OpcodeString(binary.Op);
                        break;
                }
            }
            else
            {
                op = BinaryExpr.OpcodeString(binary.Op);
            }
            if (internalOp == null)
            {
                return new RtlBinary(op, G(binary.E0), G(binary.E1));
            }
            else
            {
                return new RtlApply(internalOp, new RtlExp[]
                    { G(binary.E0), G(binary.E1) });
            }
        } else if (unary != null) {
          if (unary is UnaryOpExpr) {
            UnaryOpExpr unaryOp = (UnaryOpExpr)unary;
            if (unaryOp.Op == UnaryOpExpr.Opcode.Not) {
              return new RtlLiteral("(!(" + G(unaryOp.E) + "))");
            } else if (unaryOp.Op == UnaryOpExpr.Opcode.Cardinality) {
              return new RtlApply(dafnySpec.GetSeqOperationName(AppType(unaryOp.E.Type), "Seq_Length"),
                new RtlExp[] { G(unaryOp.E) });
            } else if (unaryOp.Op == UnaryOpExpr.Opcode.Fresh) {
              Util.Assert(DafnySpec.IsArrayType(unaryOp.E.Type));
              string abs = G(unaryOp.E) + ".arrAbs";
              return new RtlLiteral("(heap_old.absData[" + abs + "] is AbsNone)");
            } else {
              throw new Exception("not implemented: " + exp);
            }
          } else if (unary is ConversionExpr) {
             var e = (ConversionExpr)unary;
             var fromInt = e.E.Type.IsNumericBased(Type.NumericPersuation.Int);
             var toInt = e.ToType.IsNumericBased(Type.NumericPersuation.Int);
             if (fromInt && !toInt) {
                return new RtlApply("real", new RtlExp[] { G(e.E) });
              } else if (!fromInt && toInt) {
                return new RtlApply("int", new RtlExp[] { G(e.E) });
              } else {
                Util.Assert(fromInt == toInt);
                return GhostExpressionRec(e.E, inRecSpec, inRequiresOrOld);
              }
          } else {
            throw new Exception("not implemented: " + exp);
          }
        }
        else if (ite != null)
        {
            return GhostIfThenElse(G(ite.Test), () => G(ite.Thn), () => G(ite.Els));
        }
        else if (funCall != null)
        {
            switch (funCall.Function.Name)
            {
                case "left":
                case "right":
                case "relation":
                case "public":
                    Util.Assert(funCall.Args.Count == 1);
                    return new RtlApply(funCall.Function.Name, new RtlExp[] { G(funCall.Args[0]) });
                case "sizeof":
                    Util.Assert(funCall.Args.Count == 1);
                    return new RtlApply(funCall.Function.Name + "##" + TypeString(AppType(funCall.Args[0].Type)),
                        new RtlExp[] { G(funCall.Args[0]) });
                case "INTERNAL_add_raw":
                    Util.Assert(funCall.Args.Count == 2);
                    return new RtlBinary("+", G(funCall.Args[0]), G(funCall.Args[1]));
                case "INTERNAL_sub_raw":
                    Util.Assert(funCall.Args.Count == 2);
                    return new RtlBinary("-", G(funCall.Args[0]), G(funCall.Args[1]));                
            }
            TypeApply app = dafnySpec.Compile_Function(funCall.Function,
                funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value)));
            string name = FunName(SimpleName(app.AppName()));
            string fullName = FunName(SimpleName(app.AppFullName()));
            List<RtlExp> rtlArgs = funCall.Args.Select(G).ToList();
            List<RtlExp> rtlReads = funCall.Function.Reads.Where(e => e.Field != null).ToList()
                .ConvertAll(e => (RtlExp)new RtlVar(
                    GhostVar(e.FieldName), e.Field.IsGhost, AppType(e.Field.Type)));
            rtlArgs = rtlReads.Concat(rtlArgs).ToList();
            if (name.EndsWith("__INTERNAL__HEAP"))
            {
                name = name.Substring(0, name.Length - "__INTERNAL__HEAP".Length);
            }
            else if (DafnySpec.IsHeapFunction(funCall.Function))
            {
                rtlArgs.Insert(0, new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"));
            }
            if (Attributes.Contains(funCall.Function.Attributes, "opaque")
                && funCall.Function.Formals.Count + rtlReads.Count == 0)
            {
                rtlArgs.Insert(0, new RtlLiteral("true"));
            }
            if (fullName == recFunName)
            {
                name = fullName;
            }
            if (name == recFunName)
            {
                recCalls.Add(new List<RtlExp>(rtlArgs));
                rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List<RtlExp>(rtlArgs)));
                rtlArgs.Insert(1, new RtlLiteral(inRecSpec ? "__unroll" : "__unroll + 1"));
                name = "rec_" + name;
            }
            return new RtlApply(name, rtlArgs);
        }
        else if (dataVal != null)
        {
            bool isSeq = dataVal.Type.TypeName(null).StartsWith("Seq<");
            return new RtlApply((isSeq ? "_" : "") + dafnySpec.Compile_Constructor(
                dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(),
                dataVal.Arguments.Select(G));
        }
        else if (existsExp != null || forallExp != null)
        {
            QuantifierExpr qExp = (QuantifierExpr)exp;
            bool isForall = forallExp != null;
            var varTuples = qExp.BoundVars.Select(v => Tuple.Create(GhostVar(v.Name), v.IsGhost, v.Type));
            var oldRenamer = PushRename(qExp.BoundVars.Select(v => v.Name));
            var oldStmtExprEnabled = stmtExprEnabled;
            stmtExprEnabled = false; 
            RtlExp rExp = new RtlLiteral((isForall ? "(forall " : "(exists ")
                + string.Join(", ", qExp.BoundVars.Select(v => GhostVar(v.Name) + ":" + TypeString(AppType(v.Type))))
                + " :: " + Triggers(qExp.Attributes, G) + " "
                + GetTypeWellFormedExp(varTuples.ToList(), isForall ? "==>" : "&&", G(qExp.Term)) + ")");
            stmtExprEnabled = oldStmtExprEnabled;
            PopRename(oldRenamer);
            return rExp;
        }
        else if (letExp != null)
        {
            List<RtlExp> rhss;
            if (letExp.Exact)
            {
                rhss = letExp.RHSs.ConvertAll(e => G(e));
            }
            else if (letExp.LHSs.Count == 1 && LiteralExpr.IsTrue(letExp.RHSs[0]) && AppType(letExp.LHSs[0].Var.Type) is IntType)
            {
                rhss = new List<RtlExp> { new RtlLiteral("0") };
            }
            else
            {
                throw new Exception("not implemented: LetExpr: " + letExp);
            }
            return GhostLet(exp.tok, letExp.LHSs.ConvertAll(lhs => lhs.Var), rhss, () => G(letExp.Body));
        }
        else if (matchExp != null)
        {
            if (matchExp.MissingCases.Count != 0)
            {
                throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp);
            }
            //- match src case c1(ps1) => e1 ... cn(psn) => en
            //-   -->
            //- let x := src in
            //-   if x is c1 then let ps1 := ...x.f1... in e1 else
            //-   if x is c2 then let ps2 := ...x.f2... in e2 else
            //-                   let ps3 := ...x.f3... in e3
            var src = G(matchExp.Source);
            var cases = matchExp.Cases;
            string x = TempName();
            Func<RtlExp> body = null;
            for (int i = cases.Count; i > 0; )
            {
                i--;
                MatchCaseExpr c = cases[i];
                Func<List<RtlExp>> cRhss = () => c.Ctor.Formals.ConvertAll(f => (RtlExp)new RtlLiteral("("
                    + f.Name + "#" + c.Ctor.Name + "(" + GhostVar(x) + "))"));
                Func<RtlExp> ec = () => GhostLet(exp.tok, c.Arguments, cRhss(), () => G(c.Body));
                if (body == null)
                {
                    body = ec;
                }
                else
                {
                    var prevBody = body;
                    body = () => GhostIfThenElse(new RtlLiteral("(" + GhostVar(x) + " is " + c.Ctor.Name + ")"),
                        ec, prevBody);
                }
            }
            return GhostLet(exp.tok, new List<BoundVar> { new BoundVar(exp.tok, x, matchExp.Source.Type) },
                new List<RtlExp> { src }, body);
        }
        else if (oldExp != null)
        {
            return new RtlLiteral("old(" + GhostExpression(oldExp.E, inRecSpec, true) + ")");
        }        
        else if (memberSelect != null && memberSelect.MemberName.EndsWith("?"))
        {
          string constructor = memberSelect.MemberName.Substring(0, memberSelect.MemberName.Length - 1);
            constructor = dafnySpec.Compile_Constructor(memberSelect.Obj.Type, constructor, null, typeApply.typeArgs).AppName();
            bool isSeq = memberSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return isSeq
                ? new RtlLiteral("is_" + constructor + "(" + G(memberSelect.Obj) + ")")
                : new RtlLiteral("((" + G(memberSelect.Obj) + ") is " + constructor + ")");
        } 
        else if (memberSelect != null && memberSelect.Member is Field && !memberSelect.Member.IsStatic && AppType(memberSelect.Obj.Type) is UserDefinedType
            && memberSelect.Member is DatatypeDestructor)
        {
            DatatypeDestructor field = (DatatypeDestructor) memberSelect.Member;
            string constructor = dafnySpec.Compile_Constructor(memberSelect.Obj.Type,
                field.EnclosingCtor.Name, null, typeApply.typeArgs).AppName();
            bool isSeq = memberSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return new RtlLiteral("(" + memberSelect.MemberName + (isSeq ? "_" : "#") + constructor
                + "(" + G(memberSelect.Obj) + "))");
        }
        else if (memberSelect != null && memberSelect.Member is Field && DafnySpec.IsArrayType(AppType(memberSelect.Obj.Type))
            && memberSelect.MemberName == "Length")
        {
            return new RtlLiteral("(Arr_Length(" + G(memberSelect.Obj) + "))");
        } 
        else if (memberSelect != null && memberSelect.Member is Field && memberSelect.Obj is ImplicitThisExpr)
        {
            //- we don't support objects yet, so interpret this as a global variable
            return new RtlVar(GhostVar(memberSelect.MemberName), true, memberSelect.Type);
        }
        else if (seqSelect != null)
        {
            if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
            {
                return new RtlExpComputed(e => "fun_INTERNAL__array__elems__index("
                    + (inRequiresOrOld ? "$absMem_old" : "$absMem") + "[" + e.args[0] + ".arrAbs], ("
                    + e.args[1] + "))", new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) });
            }
            else if (seqSelect.SelectOne)
            {
                return new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Seq.Type), "Seq_Index"),
                    new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) });
            }
            else
            {
                RtlExp seq = G(seqSelect.Seq);
                if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
                {
                    seq = new RtlApply(FunName("Seq__FromArray"), new RtlExp[] {
                        new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"), seq });
                }
                if (seqSelect.E1 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Take"),
                        new RtlExp[] { seq, G(seqSelect.E1) });
                }
                if (seqSelect.E0 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Drop"),
                        new RtlExp[] { seq, G(seqSelect.E0) });
                }
                return seq;
            }
        }
        else if (seqUpdate != null)
        {
            if (seqUpdate.ResolvedUpdateExpr != null) {
                return GhostExpressionRec(seqUpdate.ResolvedUpdateExpr, inRecSpec, inRequiresOrOld); 
            } 
            return new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqUpdate.Seq.Type), "Seq_Update"),
                new RtlExp[] { G(seqUpdate.Seq), G(seqUpdate.Index), G(seqUpdate.Value) });
        }
        else if (seqDisplay != null)
        {
            RtlExp seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Empty"), new RtlExp[0]);
            foreach (Expression ei in seqDisplay.Elements)
            {
                seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Build"),
                    new RtlExp[] { seq, G(ei) });
            }
            return seq;
        }
        else
        {
            throw new Exception("not implemented: " + exp);
        }
    }
예제 #6
0
 public RtlExp GhostLet(Microsoft.Boogie.IToken tok, List<BoundVar> lhss, List<RtlExp> rhss,
     Func<RtlExp> body)
 {
     if (stmtExprEnabled && ignoreStmtExpr == 0)
     {
         var oldRenamer1 = PushRename();
         for (int i = 0; i < lhss.Count; i++)
         {
             var lhs = lhss[i];
             var rhs = rhss[i];
             AddGhostVarDecl(lhs.Name, lhs.Type, true);
             MoveGhost(new RtlVar(GhostVar(lhs.Name), true, AppType(lhs.Type)), rhs);
         }
         body();
         PopRename(oldRenamer1);
     }
     var oldRenamer2 = PushRename();
     lhss.ForEach(e => AddRename(e.Name));
     ignoreStmtExpr++; 
     RtlExp rExp = new RtlLiteral("("
         + String.Concat(lhss.Zip(rhss, (lhs, rhs) =>
             "let " + GhostVar(lhs.Name) + ":" + TypeString(AppType(lhs.Type))
             + " := (" + rhs + ") in "))
         + " (" + body() + "))");
     ignoreStmtExpr--;
     PopRename(oldRenamer2);
     return rExp;
 }