Theory BigStep

(*  Title:       CoreC++
    Author:      Daniel Wasserrab
    Maintainer:  Daniel Wasserrab <wasserra at fmi.uni-passau.de>

    Based on the Jinja theory J/BigStep.thy by Tobias Nipkow
*)

section ‹Big Step Semantics›

theory BigStep
imports Syntax State
begin


subsection ‹The rules›

inductive
  eval :: "prog  env  expr  state  expr  state  bool"
          ("_,_  ((1_,/_) / (1_,/_))" [51,0,0,0,0] 81)
  and evals :: "prog  env  expr list  state  expr list  state  bool"
           ("_,_  ((1_,/_) [⇒]/ (1_,/_))" [51,0,0,0,0] 81)
  for P :: prog
where

  New:
  " new_Addr h = Some a; h' = h(a(C,Collect (init_obj P C))) 
   P,E  new C,(h,l)  ref (a,[C]),(h',l)"

| NewFail:
  "new_Addr h = None 
  P,E  new C, (h,l)  THROW OutOfMemory,(h,l)"

| StaticUpCast:
  " P,E  e,s0  ref (a,Cs),s1; P  Path last Cs to C via Cs'; Ds = Cs@pCs' 
   P,E  Ce,s0  ref (a,Ds),s1"

| StaticDownCast:
  "P,E  e,s0  ref (a,Cs@[C]@Cs'),s1
    P,E  Ce,s0  ref (a,Cs@[C]),s1"

| StaticCastNull:
  "P,E  e,s0  null,s1 
  P,E  Ce,s0  null,s1"

| StaticCastFail:
  " P,E  e,s0  ref (a,Cs),s1; ¬ P  (last Cs) * C; C  set Cs 
   P,E  Ce,s0  THROW ClassCast,s1"

| StaticCastThrow:
  "P,E  e,s0  throw e',s1 
  P,E  Ce,s0  throw e',s1"

| StaticUpDynCast:(* path uniqueness not necessary for type proof but for determinism *)
  "P,E  e,s0  ref(a,Cs),s1; P  Path last Cs to C unique;
    P  Path last Cs to C via Cs'; Ds = Cs@pCs' 
   P,E  Cast C e,s0  ref(a,Ds),s1"

| StaticDownDynCast:
  "P,E  e,s0  ref (a,Cs@[C]@Cs'),s1
    P,E  Cast C e,s0  ref (a,Cs@[C]),s1"

| DynCast: (* path uniqueness not necessary for type proof but for determinism *)
  " P,E  e,s0  ref (a,Cs),(h,l); h a = Some(D,S);
    P  Path D to C via Cs'; P  Path D to C unique 
   P,E  Cast C e,s0  ref (a,Cs'),(h,l)"

| DynCastNull:
  "P,E  e,s0  null,s1 
  P,E  Cast C e,s0  null,s1"

| DynCastFail: (* fourth premise not necessary for type proof but for determinism *)
  " P,E  e,s0 ref (a,Cs),(h,l); h a = Some(D,S); ¬ P  Path D to C unique;
    ¬ P  Path last Cs to C unique; C  set Cs 
   P,E  Cast C e,s0  null,(h,l)"

| DynCastThrow:
  "P,E  e,s0  throw e',s1 
  P,E  Cast C e,s0  throw e',s1"

| Val:
  "P,E  Val v,s  Val v,s"

| BinOp:
  " P,E  e1,s0  Val v1,s1; P,E  e2,s1  Val v2,s2; 
    binop(bop,v1,v2) = Some v 
   P,E  e1 «bop» e2,s0Val v,s2"

| BinOpThrow1:
  "P,E  e1,s0  throw e,s1 
  P,E  e1 «bop» e2, s0  throw e,s1"

| BinOpThrow2:
  " P,E  e1,s0  Val v1,s1; P,E  e2,s1  throw e,s2 
   P,E  e1 «bop» e2,s0  throw e,s2"

| Var:
  "l V = Some v 
  P,E  Var V,(h,l)  Val v,(h,l)"

| LAss:
  " P,E  e,s0  Val v,(h,l); E V = Some T;
     P  T casts v to v'; l' = l(Vv') 
   P,E  V:=e,s0  Val v',(h,l')"

| LAssThrow:
  "P,E  e,s0  throw e',s1 
  P,E  V:=e,s0  throw e',s1"

| FAcc:
  " P,E  e,s0  ref (a,Cs'),(h,l); h a = Some(D,S);
     Ds = Cs'@pCs; (Ds,fs)  S; fs F = Some v 
   P,E  eF{Cs},s0  Val v,(h,l)"

| FAccNull:
  "P,E  e,s0  null,s1 
  P,E  eF{Cs},s0  THROW NullPointer,s1" 

| FAccThrow:
  "P,E  e,s0  throw e',s1 
  P,E  eF{Cs},s0  throw e',s1"

| FAss:
  " P,E  e1,s0  ref (a,Cs'),s1; P,E  e2,s1  Val v,(h2,l2);
     h2 a = Some(D,S); P  (last Cs') has least F:T via Cs; P  T casts v to v';
     Ds = Cs'@pCs; (Ds,fs)  S; fs' = fs(Fv'); 
     S' = S - {(Ds,fs)}  {(Ds,fs')}; h2' = h2(a(D,S'))
   P,E  e1F{Cs}:=e2,s0  Val v',(h2',l2)"

| FAssNull:
  " P,E  e1,s0  null,s1;  P,E  e2,s1  Val v,s2  
  P,E  e1F{Cs}:=e2,s0  THROW NullPointer,s2" 

| FAssThrow1:
  "P,E  e1,s0  throw e',s1 
  P,E  e1F{Cs}:=e2,s0  throw e',s1"

| FAssThrow2:
  " P,E  e1,s0  Val v,s1; P,E  e2,s1  throw e',s2 
   P,E  e1F{Cs}:=e2,s0  throw e',s2"

| CallObjThrow:
  "P,E  e,s0  throw e',s1 
  P,E  Call e Copt M es,s0  throw e',s1"

| CallParamsThrow:
  " P,E  e,s0  Val v,s1; P,E  es,s1 [⇒] map Val vs @ throw ex # es',s2 
    P,E  Call e Copt M es,s0  throw ex,s2"

| Call:
  " P,E  e,s0  ref (a,Cs),s1;  P,E  ps,s1 [⇒] map Val vs,(h2,l2);
     h2 a = Some(C,S);  P  last Cs has least M = (Ts',T',pns',body') via Ds;
     P  (C,Cs@pDs) selects M = (Ts,T,pns,body) via Cs'; length vs = length pns; 
     P  Ts Casts vs to vs'; l2' = [thisRef (a,Cs'), pns[↦]vs'];
     new_body = (case T' of Class D  Dbody   | _   body);  
     P,E(thisClass(last Cs'), pns[↦]Ts)  new_body,(h2,l2')  e',(h3,l3) 
   P,E  eM(ps),s0  e',(h3,l2)"

| StaticCall:
  " P,E  e,s0  ref (a,Cs),s1;  P,E  ps,s1 [⇒] map Val vs,(h2,l2);
     P  Path (last Cs) to C unique; P  Path (last Cs) to C via Cs'';
     P  C has least M = (Ts,T,pns,body) via Cs'; Ds = (Cs@pCs'')@pCs';
     length vs = length pns; P  Ts Casts vs to vs'; 
     l2' = [thisRef (a,Ds), pns[↦]vs'];
     P,E(thisClass(last Ds), pns[↦]Ts)  body,(h2,l2')  e',(h3,l3) 
   P,E  e∙(C::)M(ps),s0  e',(h3,l2)"

| CallNull:
  " P,E  e,s0  null,s1;  P,E  es,s1 [⇒] map Val vs,s2 
   P,E  Call e Copt M es,s0  THROW NullPointer,s2"

| Block:
  "P,E(V  T)  e0,(h0,l0(V:=None))  e1,(h1,l1)  
  P,E  {V:T; e0},(h0,l0)  e1,(h1,l1(V:=l0 V))"

| Seq:
  " P,E  e0,s0  Val v,s1; P,E  e1,s1  e2,s2 
   P,E  e0;;e1,s0  e2,s2"

| SeqThrow:
  "P,E  e0,s0  throw e,s1 
  P,E  e0;;e1,s0throw e,s1"

| CondT:
  " P,E  e,s0  true,s1; P,E  e1,s1  e',s2 
   P,E  if (e) e1 else e2,s0  e',s2"

| CondF:
  " P,E  e,s0  false,s1; P,E  e2,s1  e',s2 
   P,E  if (e) e1 else e2,s0  e',s2"

| CondThrow:
  "P,E  e,s0  throw e',s1 
  P,E  if (e) e1 else e2, s0  throw e',s1"

| WhileF:
  "P,E  e,s0  false,s1 
  P,E  while (e) c,s0  unit,s1"

| WhileT:
  " P,E  e,s0  true,s1; P,E  c,s1  Val v1,s2; 
     P,E  while (e) c,s2  e3,s3 
   P,E  while (e) c,s0  e3,s3"

| WhileCondThrow:
  "P,E  e,s0   throw e',s1 
  P,E  while (e) c,s0  throw e',s1"

| WhileBodyThrow:
  " P,E  e,s0  true,s1; P,E  c,s1  throw e',s2
   P,E  while (e) c,s0  throw e',s2"

| Throw:
  "P,E  e,s0  ref r,s1 
  P,E  throw e,s0  Throw r,s1"

| ThrowNull:
  "P,E  e,s0  null,s1 
  P,E  throw e,s0  THROW NullPointer,s1"

| ThrowThrow:
  "P,E  e,s0  throw e',s1 
  P,E  throw e,s0  throw e',s1"

| Nil:
  "P,E  [],s [⇒] [],s"

| Cons:
  " P,E  e,s0  Val v,s1; P,E  es,s1 [⇒] es',s2 
   P,E  e#es,s0 [⇒] Val v # es',s2"

| ConsThrow:
  "P,E  e, s0  throw e', s1 
  P,E  e#es, s0 [⇒] throw e' # es, s1"

lemmas eval_evals_induct = eval_evals.induct [split_format (complete)]
  and eval_evals_inducts = eval_evals.inducts [split_format (complete)]

inductive_cases eval_cases [cases set]:
 "P,E  new C,s  e',s'"
 "P,E  Cast C e,s  e',s'"
 "P,E  Ce,s  e',s'"
 "P,E  Val v,s  e',s'"
 "P,E  e1 «bop» e2,s  e',s'"
 "P,E  Var V,s  e',s'"
 "P,E  V:=e,s  e',s'"
 "P,E  eF{Cs},s  e',s'"
 "P,E  e1F{Cs}:=e2,s  e',s'"
 "P,E  eM(es),s  e',s'"
 "P,E  e∙(C::)M(es),s  e',s'"
 "P,E  {V:T;e1},s  e',s'"
 "P,E  e1;;e2,s  e',s'"
 "P,E  if (e) e1 else e2,s  e',s'"
 "P,E  while (b) c,s  e',s'"
 "P,E  throw e,s  e',s'"
  
inductive_cases evals_cases [cases set]:
 "P,E  [],s [⇒] e',s'"
 "P,E  e#es,s [⇒] e',s'"



subsection ‹Final expressions›

definition final :: "expr  bool" where
  "final e    (v. e = Val v)  (r. e = Throw r)"

definition finals:: "expr list  bool" where
  "finals es    (vs. es = map Val vs)  (vs r es'. es = map Val vs @ Throw r # es')"

lemma [simp]: "final(Val v)"
by(simp add:final_def)

lemma [simp]: "final(throw e) = (r. e = ref r)"
by(simp add:final_def)

lemma finalE: " final e;  v. e = Val v  Q;  r. e = Throw r  Q   Q"
by(auto simp:final_def)

lemma [iff]: "finals []"
by(simp add:finals_def)

lemma [iff]: "finals (Val v # es) = finals es"

apply(clarsimp simp add:finals_def)
apply(rule iffI)
 apply(erule disjE)
  apply simp
 apply(rule disjI2)
 apply clarsimp
 apply(case_tac vs)
  apply simp
 apply fastforce
apply(erule disjE)
 apply (rule disjI1)
 apply clarsimp
apply(rule disjI2)
apply clarsimp
apply(rule_tac x = "v#vs" in exI)
apply simp
done


lemma finals_app_map[iff]: "finals (map Val vs @ es) = finals es"
by(induct_tac vs, auto)

lemma [iff]: "finals (map Val vs)"
using finals_app_map[of vs "[]"]by(simp)

lemma [iff]: "finals (throw e # es) = (r. e = ref r)"

apply(simp add:finals_def)
apply(rule iffI)
 apply clarsimp
 apply(case_tac vs)
  apply simp
 apply fastforce
apply fastforce
done


lemma not_finals_ConsI: "¬ final e  ¬ finals(e#es)"
 
apply(auto simp add:finals_def final_def)
apply(case_tac vs)
apply auto
done


lemma eval_final: "P,E  e,s  e',s'  final e'"
 and evals_final: "P,E  es,s [⇒] es',s'  finals es'"
by(induct rule:eval_evals.inducts, simp_all)


lemma eval_lcl_incr: "P,E  e,(h0,l0)  e',(h1,l1)  dom l0  dom l1"
 and evals_lcl_incr: "P,E  es,(h0,l0) [⇒] es',(h1,l1)  dom l0  dom l1"
by (induct rule:eval_evals_inducts) (auto simp del:fun_upd_apply)


text‹Only used later, in the small to big translation, but is already a
good sanity check:›

lemma eval_finalId:  "final e  P,E  e,s  e,s"
by (erule finalE) (fastforce intro: eval_evals.intros)+


lemma eval_finalsId:
assumes finals: "finals es" shows "P,E  es,s [⇒] es,s"

  using finals
proof (induct es type: list)
  case Nil show ?case by (rule eval_evals.intros)
next
  case (Cons e es)
  have hyp: "finals es  P,E  es,s [⇒] es,s"
   and finals: "finals (e # es)" by fact+
  show "P,E  e # es,s [⇒] e # es,s"
  proof cases
    assume "final e"
    thus ?thesis
    proof (cases rule: finalE)
      fix v assume e: "e = Val v"
      have "P,E  Val v,s  Val v,s" by (simp add: eval_finalId)
      moreover from finals e have "P,E  es,s [⇒] es,s" by(fast intro:hyp)
      ultimately have "P,E  Val v#es,s [⇒] Val v#es,s"
        by (rule eval_evals.intros)
      with e show ?thesis by simp
    next
      fix a assume e: "e = Throw a"
      have "P,E  Throw a,s  Throw a,s" by (simp add: eval_finalId)
      hence "P,E  Throw a#es,s [⇒] Throw a#es,s" by (rule eval_evals.intros)
      with e show ?thesis by simp
    qed
  next
    assume "¬ final e"
    with not_finals_ConsI finals have False by blast
    thus ?thesis ..
  qed
qed


lemma
eval_preserves_obj:"P,E  e,(h,l)  e',(h',l')  (S. h a = Some(D,S) 
   S'. h' a = Some(D,S'))"
and evals_preserves_obj:"P,E  es,(h,l) [⇒] es',(h',l') 
 (S. h a = Some(D,S)  S'. h' a = Some(D,S'))"
by(induct rule:eval_evals_inducts)(fastforce dest:new_Addr_SomeD)+

end