public override Expr VisitLetExpr(LetExpr node) { if (GetReplacementVariable(node, out var variable)) { return(new IdentifierExpr(variable.tok, variable)); } return(base.VisitLetExpr(node)); }
List <Expression> GatherReqs(Function fun, List <Expression> args) { List <Expression> translated_f_reqs = new List <Expression>(); if (fun.Req.Count > 0) { List <Tuple <BoundVar, Expression> > substs = fun.Formals.Zip(args, (f, arg) => Tuple.Create(new BoundVar(Token.NoToken, f.Name, f.Type), arg)).ToList(); substs = substs.Where(p => !(p.Item2 is IdentifierExpr) || ((IdentifierExpr)p.Item2).Name != p.Item1.Name).ToList(); List <ExprLhs> lhss = substs.ConvertAll(p => new ExprLhs(p.Item1)); foreach (var req in fun.Req) { var letExpr = new LetExpr(true, lhss, substs.ConvertAll(p => p.Item2), req); letExpr.tryToEliminate = true; translated_f_reqs.Add(letExpr); } } return(translated_f_reqs); }
public override Expr VisitLetExpr(LetExpr node) { Contract.Requires(node != null); if (_templates.ContainsKey(node)) { return(node); } _nestedBoundVariables.AddRange(node.Dummies); base.VisitLetExpr(node); var bodyTemplate = _templates[node.Body]; var varBodies = node.Rhss; if (bodyTemplate.ContainsBoundVariables() || varBodies.Any(body => _templates[body].ContainsBoundVariables())) { var replacements = new List <Expr>(); foreach (Expr body in varBodies) { replacements.AddRange(_templates[body].GetReplacements()); } replacements.AddRange(bodyTemplate.GetReplacements()); _templates[node] = new TemplateWithBoundVariables(replacements); } else { var newRhss = from arg in varBodies select((TemplateNoBoundVariables)_templates[arg]).GetReplacement(); LambdaLiftingTemplate template = new TemplateNoBoundVariables( new LetExpr(node.tok, node.Dummies, newRhss.ToList(), node.Attributes, ((TemplateNoBoundVariables)_templates[node.Body]) .GetReplacement()) { Type = node.Type }); _templates[node] = template; } return(node); }
public override IUnboundExpr Transform(LetExpr expr) { // a let expression desugars like this: // // let a b <- Foo then Bar else Bang // // becomes... // // def let__ <- Foo // if Some? let__ then // def a b <- 0 SomeValue let__ // Bar // else Bang var c = new CodeBuilder(mNameGenerator, expr.Position); var option = c.TempName(); return c.Block( c.Def(option, expr.Condition), c.If(c.Call("Some?", option), c.Block( c.Def(expr.Names, c.Call("SomeValue", option)), expr.ThenBody), expr.ElseBody)); }
private TriggerAnnotation AnnotateLetExpr(LetExpr expr) { return(AnnotateQuantifierOrLetExpr(expr, expr.BoundVars)); }
internal static bool IsInlineable(this LetExpr expr) { return(expr.LHSs.All(p => p.Var != null) && expr.Exact); }
private static bool ShallowEq(LetExpr expr1, LetExpr expr2) { return(expr1.Exact == expr2.Exact && ShallowSameAttributes(expr1.Attributes, expr2.Attributes)); }
void LetExpr(out Expression e, bool allowSemi, bool allowLambda) { IToken x = null; bool isGhost = false; var letLHSs = new List<CasePattern>(); var letRHSs = new List<Expression>(); CasePattern pat; bool exact = true; Attributes attrs = null; e = dummyExpr; if (la.kind == 73) { Get(); isGhost = true; x = t; } Expect(78); if (!isGhost) { x = t; } CasePattern(out pat); if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); } letLHSs.Add(pat); while (la.kind == 22) { Get(); CasePattern(out pat); if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); } letLHSs.Add(pat); } if (la.kind == 95) { Get(); } else if (la.kind == 25 || la.kind == 46) { while (la.kind == 46) { Attribute(ref attrs); } Expect(25); exact = false; foreach (var lhs in letLHSs) { if (lhs.Arguments != null) { SemErr(lhs.tok, "LHS of let-such-that expression must be variables, not general patterns"); } } } else SynErr(240); Expression(out e, false, true); letRHSs.Add(e); while (la.kind == 22) { Get(); Expression(out e, false, true); letRHSs.Add(e); } Expect(28); Expression(out e, allowSemi, allowLambda); e = new LetExpr(x, letLHSs, letRHSs, e, exact, attrs); }
List<Expression> GatherReqs(Function fun, List<Expression> args) { List<Expression> translated_f_reqs = new List<Expression>(); if (fun.Req.Count > 0) { List<Tuple<BoundVar,Expression>> substs = fun.Formals.Zip(args, (f, arg) => Tuple.Create(new BoundVar(Token.NoToken, f.Name, f.Type), arg)).ToList(); substs = substs.Where(p => !(p.Item2 is IdentifierExpr) || ((IdentifierExpr)p.Item2).Name != p.Item1.Name).ToList(); List<ExprLhs> lhss = substs.ConvertAll(p => new ExprLhs(p.Item1)); foreach (var req in fun.Req) { var letExpr = new LetExpr(true, lhss, substs.ConvertAll(p => p.Item2), req); letExpr.tryToEliminate = true; translated_f_reqs.Add(letExpr); } } return translated_f_reqs; }
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); } }
void EndlessExpression(out Expression e, bool allowSemi, bool allowLambda) { IToken/*!*/ x; Expression e0, e1; Statement s; bool isExistentialGuard = false; e = dummyExpr; switch (la.kind) { case 113: { Get(); x = t; if (IsExistentialGuard()) { ExistentialGuard(out e, true); isExistentialGuard = true; } else if (StartOf(9)) { Expression(out e, true, true); } else SynErr(252); Expect(34); Expression(out e0, true, true); Expect(35); Expression(out e1, allowSemi, allowLambda); if (isExistentialGuard) { var exists = (ExistsExpr) e; List<CasePattern> LHSs = new List<CasePattern>(); foreach (var v in exists.BoundVars) { LHSs.Add(new CasePattern(e.tok, v)); } e0 = new LetExpr(e.tok, LHSs, new List<Expression>() { exists.Term }, e0, false); } e = new ITEExpr(x, isExistentialGuard, e, e0, e1); break; } case 62: { MatchExpression(out e, allowSemi, allowLambda); break; } case 116: case 136: case 137: case 138: { QuantifierGuts(out e, allowSemi, allowLambda); break; } case 13: { Get(); x = t; SetComprehensionExpr(x, true, out e, allowSemi, allowLambda); break; } case 14: { Get(); x = t; SetComprehensionExpr(x, false, out e, allowSemi, allowLambda); break; } case 31: case 32: case 99: { StmtInExpr(out s); Expression(out e, allowSemi, allowLambda); e = new StmtExpr(s.Tok, s, e); break; } case 61: case 65: { LetExpr(out e, allowSemi, allowLambda); break; } case 17: { Get(); x = t; MapComprehensionExpr(x, true, out e, allowSemi, allowLambda); break; } case 18: { Get(); x = t; MapComprehensionExpr(x, false, out e, allowSemi, allowLambda); break; } case 97: { NamedExpr(out e, allowSemi, allowLambda); break; } default: SynErr(253); break; } }
public override Expr VisitLetExpr(LetExpr node) { throw new NotImplementedException(); }