datatype List<T> = Nil | Cons(head: T, tail: List<T>)
ghost function append(xs: List, ys: List): List
case Cons(x, tail) => Cons(x, append(tail, ys))
datatype aexp = N(n: int) | V(vname) | Plus(aexp, aexp)
type state = vname -> val
ghost function aval(a: aexp, s: state): val
case Plus(a0, a1) => aval(a0, s) + aval(a1, s)
var y := aval(Plus(N(3), V("x")), x => 0);
ghost function asimp_const(a: aexp): aexp
var as0, as1 := asimp_const(a0), asimp_const(a1);
lemma AsimpConst(a: aexp, s: state)
ensures aval(asimp_const(a), s) == aval(a, s)
AsimpConst(a', s); // this invokes the induction hypothesis for every a' that is structurally smaller than a
ghost function plus(a0: aexp, a1: aexp): aexp
if a0.n == 0 then a1 else Plus(a0, a1)
if a1.n == 0 then a0 else Plus(a0, a1)
lemma AvalPlus(a0: aexp, a1: aexp, s: state)
ensures aval(plus(a0, a1), s) == aval(a0, s) + aval(a1, s)
ghost function asimp(a: aexp): aexp
case Plus(a0, a1) => plus(asimp(a0), asimp(a1))
lemma AsimpCorrect(a: aexp, s: state)
ensures aval(asimp(a), s) == aval(a, s)
forall a' | a' < a { AsimpCorrect(a', s); }
lemma ASimplInvolutive(a: aexp)
ensures asimp(asimp(a)) == asimp(a)
datatype bexp = Bc(v: bool) | Not(bexp) | And(bexp, bexp) | Less(aexp, aexp)
ghost function bval(b: bexp, s: state): bool
case Not(b) => !bval(b, s)
case And(b0, b1) => bval(b0, s) && bval(b1, s)
case Less(a0, a1) => aval(a0, s) < aval(a1, s)
ghost function not(b: bexp): bexp
case Less(_, _) => Not(b)
ghost function and(b0: bexp, b1: bexp): bexp
ghost function less(a0: aexp, a1: aexp): bexp
ghost function bsimp(b: bexp): bexp
case Not(b0) => not(bsimp(b0))
case And(b0, b1) => and(bsimp(b0), bsimp(b1))
case Less(a0, a1) => less(asimp(a0), asimp(a1))
lemma BsimpCorrect(b: bexp, s: state)
ensures bval(bsimp(b), s) == bval(b, s)
BsimpCorrect(b0, s); BsimpCorrect(b1, s);
AsimpCorrect(a0, s); AsimpCorrect(a1, s);
datatype instr = LOADI(val) | LOAD(vname) | ADD
ghost function exec1(i: instr, s: state, stk: stack): stack
case LOADI(n) => Cons(n, stk)
case LOAD(x) => Cons(s(x), stk)
if stk.Cons? && stk.tail.Cons? then
var Cons(a1, Cons(a0, tail)) := stk;
ghost function exec(ii: List<instr>, s: state, stk: stack): stack
case Cons(i, rest) => exec(rest, s, exec1(i, s, stk))
ghost function comp(a: aexp): List<instr>
case N(n) => Cons(LOADI(n), Nil)
case V(x) => Cons(LOAD(x), Nil)
case Plus(a0, a1) => append(append(comp(a0), comp(a1)), Cons(ADD, Nil))
lemma CorrectCompilation(a: aexp, s: state, stk: stack)
ensures exec(comp(a), s, stk) == Cons(aval(a, s), stk)
exec(append(append(comp(a0), comp(a1)), Cons(ADD, Nil)), s, stk);
{ ExecAppend(append(comp(a0), comp(a1)), Cons(ADD, Nil), s, stk); }
exec(Cons(ADD, Nil), s, exec(append(comp(a0), comp(a1)), s, stk));
{ ExecAppend(comp(a0), comp(a1), s, stk); }
exec(Cons(ADD, Nil), s, exec(comp(a1), s, exec(comp(a0), s, stk)));
{ CorrectCompilation(a0, s, stk); }
exec(Cons(ADD, Nil), s, exec(comp(a1), s, Cons(aval(a0, s), stk)));
{ CorrectCompilation(a1, s, Cons(aval(a0, s), stk)); }
exec(Cons(ADD, Nil), s, Cons(aval(a1, s), Cons(aval(a0, s), stk)));
Cons(aval(a1, s) + aval(a0, s), stk);
lemma ExecAppend(ii0: List<instr>, ii1: List<instr>, s: state, stk: stack)
ensures exec(append(ii0, ii1), s, stk) == exec(ii1, s, exec(ii0, s, stk))