Theory Execute

Up to index of Isabelle/HOL/CoreC++

theory Execute
imports BigStep WellType Executable_Set Efficient_Nat

(*  Title:       CoreC++
    ID:          $Id: Execute.thy,v 1.22 2009-07-14 09:00:10 fhaftmann Exp $
    Author:      Daniel Wasserrab, Stefan Berghofer
    Maintainer:  Daniel Wasserrab <wasserra at fmi.uni-passau.de>
*)


header {* \isaheader{Code generation for Semantics and Type System} *}

theory Execute
imports BigStep WellType Executable_Set Efficient_Nat
begin

section{* General redefinitions *}

inductive app :: "'a list => 'a list => 'a list => bool"
where
  "app [] ys ys"
| "app xs ys zs ==> app (x # xs) ys (x # zs)"

theorem app_eq1: "!!ys zs. zs = xs @ ys ==> app xs ys zs"
  apply (induct xs)
   apply simp
   apply (rule app.intros)
  apply simp
  apply (iprover intro: app.intros)
  done

theorem app_eq2: "app xs ys zs ==> zs = xs @ ys"
  by (erule app.induct) simp_all

theorem app_eq: "app xs ys zs = (zs = xs @ ys)"
  apply (rule iffI)
   apply (erule app_eq2)
  apply (erule app_eq1)
  done


inductive
  casts_aux :: "prog => ty => val => val => bool"
  for P :: prog
where
  "(case T of Class C => False | _ => True) ==> casts_aux P T v v"
| "casts_aux P (Class C) Null Null"
| "[|Subobjs P (last Cs) Cs'; last Cs' = C;
    last Cs = hd Cs'; Cs @ tl Cs' = Ds|] 
  ==> casts_aux P (Class C) (Ref(a,Cs)) (Ref(a,Ds))"
| "[|Subobjs P (last Cs) Cs'; last Cs' = C; last Cs ≠ hd Cs'|]
  ==> casts_aux P (Class C) (Ref(a,Cs)) (Ref(a,Cs'))"

lemma casts_aux_eq:
"(P \<turnstile> T casts v to v') = casts_aux P T v v'"
apply (rule iffI)
 apply(induct rule:casts_to.induct)
 apply(case_tac T) apply (auto intro:casts_aux.intros)
 apply(simp add:appendPath_def path_via_def) apply (auto intro:casts_aux.intros)
apply(induct rule:casts_aux.induct)
apply(auto intro!:casts_to.intros simp:path_via_def appendPath_def)
done

inductive
  Casts_aux :: "prog => ty list => val list => val list => bool"
  for P :: prog
where
  "Casts_aux P [] [] []"
| "[|casts_aux P T v v'; Casts_aux P Ts vs vs'|]
  ==> Casts_aux P (T#Ts) (v#vs) (v'#vs')"

lemma Casts_aux_eq:
"(P \<turnstile> Ts Casts vs to vs') = Casts_aux P Ts vs vs'"
apply(rule iffI)
 apply(induct rule:Casts_to.induct)
  apply(rule Casts_aux.intros)
 apply(fastsimp intro:Casts_aux.intros simp:casts_aux_eq)
apply(induct rule:Casts_aux.induct)
 apply(rule Casts_Nil)
apply(fastsimp intro:Casts_Cons simp:casts_aux_eq)
done



text{* Redefine map Val vs *}

inductive map_val :: "expr list => val list => bool"
where
  Nil: "map_val [] []"
| Cons: "map_val xs ys ==> map_val (Val y # xs) (y # ys)"

inductive map_val2 :: "expr list => val list => expr list => bool"
where
  Nil: "map_val2 [] [] []"
| Cons: "map_val2 xs ys zs ==> map_val2 (Val y # xs) (y # ys) zs"
| Throw: "map_val2 (throw e # xs) [] (throw e # xs)"

theorem map_val_conv: "(xs = map Val ys) = map_val xs ys"
(*<*)
proof -
  have "!!ys. xs = map Val ys ==> map_val xs ys"
    apply (induct xs type:list)
     apply (case_tac ys)
      apply simp
      apply (rule map_val.Nil)
     apply simp
    apply (case_tac ys)
     apply simp
    apply simp
    apply (erule conjE)
    apply (rule map_val.Cons)
    apply simp
    done
  moreover have "map_val xs ys ==> xs = map Val ys"
    by (erule map_val.induct) simp+
  ultimately show ?thesis ..
qed
(*>*)

theorem map_val2_conv:
 "(xs = map Val ys @ throw e # zs) = map_val2 xs ys (throw e # zs)"
(*<*)
proof -
  have "!!ys. xs = map Val ys @ throw e # zs ==> map_val2 xs ys (throw e # zs)"
    apply (induct xs type:list)
     apply (case_tac ys)
      apply simp
     apply simp
    apply simp
    apply (case_tac ys)
     apply simp
     apply (rule map_val2.Throw)
    apply simp
    apply (rule map_val2.Cons)
    apply simp
    done
  moreover have "map_val2 xs ys (throw e # zs) ==> xs = map Val ys @ throw e # zs"
    by (erule map_val2.induct) simp+
  ultimately show ?thesis ..
qed
(*>*)

text {* Redefine MethodDefs and FieldDecls *}

(* FIXME: These predicates should be defined inductively in the first place! *)

constdefs
  MethodDefs' :: "prog => cname => mname => path => method => bool"
  "MethodDefs' P C M Cs mthd ≡ (Cs, mthd) ∈ MethodDefs P C M"

  FieldDecls' :: "prog => cname => vname => path => ty => bool"
  "FieldDecls' P C F Cs T ≡ (Cs, T) ∈ FieldDecls P C F"

  MinimalMethodDefs' :: "prog => cname => mname => path => method => bool"
  "MinimalMethodDefs' P C M Cs mthd ≡ (Cs, mthd) ∈ MinimalMethodDefs P C M"

lemma [code_ind params: 3]:
  "Subobjs P C Cs ==> class P (last Cs) = ⌊(Bs,fs,ms)⌋ ==> map_of ms M =  ⌊mthd⌋ ==>
   MethodDefs' P C M Cs mthd"
 by (simp add: MethodDefs_def MethodDefs'_def)

lemma [code_ind params: 3]:
  "Subobjs P C Cs ==> class P (last Cs) = ⌊(Bs,fs,ms)⌋ ==> map_of fs F =  ⌊T⌋ ==>
   FieldDecls' P C F Cs T"
 by (simp add: FieldDecls_def FieldDecls'_def)

lemma [code_ind params: 3]:
  "MethodDefs' P C M Cs mthd ==> 
   ∀(Cs', mthd)∈{(Cs', mthd). MethodDefs' P C M Cs' mthd}. P,C \<turnstile> Cs' \<sqsubseteq> Cs --> Cs' = Cs ==>
   MinimalMethodDefs' P C M Cs mthd"
  by (simp add:MinimalMethodDefs_def MinimalMethodDefs'_def MethodDefs'_def)

lemma ForallMethodDefs_eq:
  "(∀(Cs, mthd)∈MethodDefs P C M. Q Cs) = (∀(Cs, mthd)∈{(Cs, mthd). MethodDefs' P C M Cs mthd}. Q Cs)"
  by (auto simp add: MethodDefs'_def)

lemma ForallFieldDecls_eq:
  "(∀(Cs, T)∈FieldDecls P C F. Q Cs) = (∀(Cs, T)∈{(Cs, T). FieldDecls' P C F Cs T}. Q Cs)"
  by (auto simp add: FieldDecls'_def)

constdefs
  OverriderMethodDefs' :: "prog => subobj => mname => path => method => bool"
  "OverriderMethodDefs' P R M Cs mthd ≡ (Cs, mthd) ∈ OverriderMethodDefs P R M"

lemma OverriderMethodDefs_card_eq:
  "card (OverriderMethodDefs P R M) = card {(Cs, mthd). OverriderMethodDefs' P R M Cs mthd}"
  by (simp add: OverriderMethodDefs'_def)

lemmas codegen_simps = MethodDefs'_def [symmetric] ForallMethodDefs_eq
  FieldDecls'_def [symmetric] ForallFieldDecls_eq OverriderMethodDefs'_def [symmetric]
  OverriderMethodDefs_card_eq


section {* Rewriting lemmas for Semantic rules *}

text {* Cast *}

lemma StaticUpCast_new1:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),(h,l)⟩;
    Subobjs P (last Cs) Cs'; last Cs' = C;
    last Cs = hd Cs'; Cs @ tl Cs' = Ds|]
  ==> P,E \<turnstile> ⟨(|C|)),e,s0⟩ => ⟨ref (a,Ds),(h,l)⟩"
apply(rule StaticUpCast)
  apply assumption
 apply(fastsimp simp:path_via_def)
apply(simp add:appendPath_def)
done

lemma StaticUpCast_new2:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),(h,l)⟩;
    Subobjs P (last Cs) Cs'; last Cs' = C;
    last Cs ≠ hd Cs'|]
  ==> P,E \<turnstile> ⟨(|C|)),e,s0⟩ => ⟨ref (a,Cs'),(h,l)⟩"
apply(rule StaticUpCast)
  apply assumption
 apply(fastsimp simp:path_via_def)
apply(simp add:appendPath_def)
done

lemma StaticDownCast_new: 
  "[|P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Ds),s1⟩; app Cs [C] Ds'; app Ds' Cs' Ds|]
  ==> P,E \<turnstile> ⟨(|C|)),e,s0⟩ => ⟨ref(a,Cs@[C]),s1⟩"
apply (rule StaticDownCast)
apply (simp add: app_eq)
done

lemma StaticCastFail_new:
"[| P,E \<turnstile> ⟨e,s0⟩=> ⟨ref (a,Cs),(h,l)⟩;  ¬ P \<turnstile> (last Cs) \<preceq>* C; C ∉ set Cs|]
  ==> P,E \<turnstile> ⟨(|C|)),e,s0⟩ => ⟨THROW ClassCast,(h,l)⟩"
by (fastsimp intro:StaticCastFail)

lemma StaticUpDynCast_new1:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),(h,l)⟩;
    Subobjs P (last Cs) Cs'; last Cs' = C;
    ∀Cs''∈{Cs''. Subobjs P (last Cs) Cs''}. last Cs'' = C --> Cs' = Cs'';
    last Cs = hd Cs'; Cs @ tl Cs' = Ds|]
  ==> P,E \<turnstile> ⟨Cast C e,s0⟩ => ⟨ref (a,Ds),(h,l)⟩"
apply(rule StaticUpDynCast)
   apply assumption
  apply(unfold path_unique_def path_via_def)
  apply(rule_tac a="Cs'" in ex1I) apply blast
  apply blast
 apply blast
apply(thin_tac "∀x∈?S. ?P x")
apply(simp add:appendPath_def)
done

lemma StaticUpDynCast_new2:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),(h,l)⟩;
    Subobjs P (last Cs) Cs'; last Cs' = C;
    ∀Cs''∈{Cs''. Subobjs P (last Cs) Cs''}. last Cs'' = C --> Cs' = Cs'';
    last Cs ≠ hd Cs'|]
  ==> P,E \<turnstile> ⟨Cast C e,s0⟩ => ⟨ref (a,Cs'),(h,l)⟩"
apply(rule StaticUpDynCast)
   apply assumption
  apply(unfold path_unique_def path_via_def)
  apply(rule_tac a="Cs'" in ex1I) apply blast
  apply blast
 apply blast
apply(thin_tac "∀x∈?S. ?P x")
apply(simp add:appendPath_def)
done

lemma StaticDownDynCast_new: 
  "[|P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Ds),s1⟩; app Cs [C] Ds'; app Ds' Cs' Ds|]
  ==> P,E \<turnstile> ⟨Cast C e,s0⟩ => ⟨ref(a,Cs@[C]),s1⟩"
apply (rule StaticDownDynCast)
apply (simp add: app_eq)
done

lemma DynCast_new:
"[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),(h,l)⟩; h a = Some(D,S);
   Subobjs P D Cs'; last Cs' = C;
    ∀Cs''∈{Cs''. Subobjs P D Cs''}. last Cs'' = C --> Cs' = Cs''|]
  ==> P,E \<turnstile> ⟨Cast C e,s0⟩ => ⟨ref (a,Cs'),(h,l)⟩"
apply(rule DynCast)
apply(unfold path_via_def path_unique_def)
apply blast+
done

lemma DynCastFail_new:
"[| P,E \<turnstile> ⟨e,s0⟩=> ⟨ref (a,Cs),(h,l)⟩; h a = Some(D,S);
  ∀Cs'∈{Cs'. Subobjs P D Cs'}. last Cs' = C --> 
       (∃Cs''∈{Cs''. Subobjs P D Cs''}. last Cs'' = C ∧ Cs' ≠ Cs'');
  ∀Cs'∈{Cs'. Subobjs P (last Cs) Cs'}. last Cs' = C --> 
       (∃Cs''∈{Cs''. Subobjs P (last Cs) Cs''}. last Cs'' = C ∧ Cs' ≠ Cs'');
  C ∉ set Cs |]
  ==> P,E \<turnstile> ⟨Cast C e,s0⟩ => ⟨null,(h,l)⟩"
apply(rule DynCastFail)
    apply assumption
   apply assumption
  apply (fastsimp simp:path_unique_def)
 apply (fastsimp simp:path_unique_def)
apply assumption
done

text {* Assignment *}

lemma LAss_new:
  "[|P,E \<turnstile> ⟨e,s0⟩ => ⟨Val v,(h, l)⟩; E V = ⌊T⌋;
    casts_aux P T v v'; l' = l(V \<mapsto> v')|]
  ==> P,E \<turnstile> ⟨V:=e,s0⟩ => ⟨Val v',(h, l')⟩"
  apply (rule LAss)
  apply assumption+
  apply(simp add:casts_aux_eq)
  apply assumption
  done

text {* Fields *}

lemma FAcc_new1:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs'),(h,l)⟩; h a = Some(D,S);
     last Cs' = hd Cs; Cs' @ tl Cs = Ds; (Ds,fs) ∈ S; fs F = Some v |]
  ==> P,E \<turnstile> ⟨e•F{Cs},s0⟩ => ⟨Val v,(h,l)⟩"
apply(rule FAcc)
apply assumption+
apply(simp add:appendPath_def)
apply assumption+
done

lemma FAcc_new2:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs'),(h,l)⟩; h a = Some(D,S);
     last Cs' ≠ hd Cs; (Cs,fs) ∈ S; fs F = Some v |]
  ==> P,E \<turnstile> ⟨e•F{Cs},s0⟩ => ⟨Val v,(h,l)⟩"
apply(rule FAcc)
apply assumption+
apply(simp add:appendPath_def)
apply assumption+
done

lemma FAss_new1:
  "[| P,E \<turnstile> ⟨e1,s0⟩ => ⟨ref (a,Cs'),s1⟩; P,E \<turnstile> ⟨e2,s1⟩ => ⟨Val v,(h2,l2)⟩;
     h2 a = Some(D,S); P \<turnstile> (last Cs') has least F:T via Cs; 
     casts_aux P T v v'; last Cs' = hd Cs; Cs' @ tl Cs = Ds; 
     (Ds,fs) ∈ S; fs' = fs(F\<mapsto>v'); 
     S' = S - {(Ds,fs)} ∪ {(Ds,fs')}; h2' = h2(a\<mapsto>(D,S'))|]
  ==> P,E \<turnstile> ⟨e1•F{Cs}:=e2,s0⟩ => ⟨Val v',(h2',l2)⟩"
apply(rule FAss)
apply assumption+
apply(simp add:casts_aux_eq)
apply(simp add:appendPath_def)
apply assumption+
done

lemma FAss_new2:
  "[| P,E \<turnstile> ⟨e1,s0⟩ => ⟨ref (a,Cs'),s1⟩; P,E \<turnstile> ⟨e2,s1⟩ => ⟨Val v,(h2,l2)⟩;
     h2 a = Some(D,S); P \<turnstile> (last Cs') has least F:T via Cs; 
     casts_aux P T v v'; last Cs' ≠ hd Cs; (Cs,fs) ∈ S; fs' = fs(F\<mapsto>v'); 
     S' = S - {(Cs,fs)} ∪ {(Cs,fs')}; h2' = h2(a\<mapsto>(D,S'))|]
  ==> P,E \<turnstile> ⟨e1•F{Cs}:=e2,s0⟩ => ⟨Val v',(h2',l2)⟩"
apply(rule FAss)
apply assumption+
apply(simp add:casts_aux_eq)
apply(simp add:appendPath_def)
apply assumption+
done

text {* Call *}

lemma CallParamsThrow_new:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨Val v,s1⟩; P,E \<turnstile> ⟨es,s1⟩ [=>] ⟨evs,s2⟩;
     map_val2 evs vs (throw ex # es') |]
   ==> P,E \<turnstile> ⟨Call e Copt M es,s0⟩ => ⟨throw ex,s2⟩"
apply(rule eval_evals.CallParamsThrow, assumption+)
apply(simp add: map_val2_conv[symmetric])
done

lemma CallNull_new:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨null,s1⟩;  P,E \<turnstile> ⟨es,s1⟩ [=>] ⟨evs,s2⟩; map_val evs vs |]
  ==> P,E \<turnstile> ⟨Call e Copt M es,s0⟩ => ⟨THROW NullPointer,s2⟩"
apply(rule CallNull, assumption+)
apply(simp add: map_val_conv[symmetric])
done

lemma Call_new:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩;  P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩;
     map_val evs vs; h2 a = Some(C,S); 
     P \<turnstile> last Cs has least M = (Ts',T',pns',body') via Ds;
     P \<turnstile> C has least M = (Ts,T,pns,body) via Cs'; length vs = length pns; 
     Casts_aux P Ts vs vs'; l2' = [this\<mapsto>Ref (a,Cs'), pns[\<mapsto>]vs'];
     new_body = (case T' of Class D => (|D|)),body   | _  => body);
     P,E(this\<mapsto>Class(last Cs'), pns[\<mapsto>]Ts) \<turnstile> ⟨new_body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩ |]
  ==> P,E \<turnstile> ⟨e•M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
apply(rule Call, assumption+)
apply(simp add: map_val_conv[symmetric])
apply assumption+
apply(rule dyn_unique)
apply assumption+
apply(simp add:Casts_aux_eq)
apply assumption+
done


lemma Overrider1:
  "P \<turnstile> (ldc R) has least M = mthd' via Cs' ==> 
   MinimalMethodDefs' P (mdc R) M Cs mthd ==>
   last (snd R) = hd Cs' ==> P,mdc R \<turnstile> Cs \<sqsubseteq> (snd R)@tl Cs' ==>
   OverriderMethodDefs' P R M Cs mthd"
apply(simp add:OverriderMethodDefs_def OverriderMethodDefs'_def MinimalMethodDefs'_def appendPath_def)
apply(rule_tac x="Cs'" in exI)
apply clarsimp
apply(cases mthd')
apply blast
done

lemma Overrider2:
  "P \<turnstile> (ldc R) has least M = mthd' via Cs' ==> 
   MinimalMethodDefs' P (mdc R) M Cs mthd ==>
   last (snd R) ≠ hd Cs' ==> P,mdc R \<turnstile> Cs \<sqsubseteq> Cs' ==>
   OverriderMethodDefs' P R M Cs mthd"
apply(simp add:OverriderMethodDefs_def OverriderMethodDefs'_def MinimalMethodDefs'_def appendPath_def)
apply(rule_tac x="Cs'" in exI) 
apply clarsimp
apply(cases mthd')
apply blast
done


lemma ambiguous: "(¬ P \<turnstile> C has least M = mthd via Cs') = 
  (MethodDefs' P C M Cs' mthd --> (∃(Cs'', mthd')∈{(Cs'', mthd'). MethodDefs' P C M Cs'' mthd'}. ¬ P,C \<turnstile> Cs' \<sqsubseteq> Cs''))"
  by (auto simp:LeastMethodDef_def MethodDefs'_def)

lemma CallOverrider_new1:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩;  P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩;
     map_val evs vs; h2 a = Some(C,S);
     P \<turnstile> last Cs has least M = (Ts',T',pns',body') via Ds;
     ∀(Cs',mthd)∈{(Cs',mthd). MethodDefs' P (last Cs) M Cs' mthd}. P,last Cs \<turnstile> Ds \<sqsubseteq> Cs';
     ∀(Cs',mthd)∈{(Cs',mthd). MethodDefs' P C M Cs' mthd}. ∃(Cs'',mthd)∈{(Cs'',mthd). MethodDefs' P C M Cs'' mthd}. ¬ P,C \<turnstile> Cs' \<sqsubseteq> Cs'';
     last Cs = hd Ds; P \<turnstile> (C,Cs@tl Ds) has overrider M = (Ts,T,pns,body) via Cs';
     length vs = length pns; Casts_aux P Ts vs vs'; 
     l2' = [this\<mapsto>Ref (a,Cs'), pns[\<mapsto>]vs']; 
     new_body = (case T' of Class D => (|D|)),body   | _  => body);
     P,E(this\<mapsto>Class(last Cs'), pns[\<mapsto>]Ts) \<turnstile> ⟨new_body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩ |]
  ==> P,E \<turnstile> ⟨e•M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
apply(rule Call,assumption)
apply(simp add: map_val_conv[symmetric])
apply assumption+
apply(rule dyn_ambiguous)
apply(simp add:ambiguous,blast)
apply(simp add:appendPath_def)
apply assumption
apply(simp add:Casts_aux_eq)
apply assumption+
done

lemma CallOverrider_new2:
  "[| P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩;  P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩;
     map_val evs vs; h2 a = Some(C,S);
     P \<turnstile> last Cs has least M = (Ts',T',pns',body') via Ds;
     ∀(Cs',mthd)∈{(Cs',mthd). MethodDefs' P (last Cs) M Cs' mthd}. P,last Cs \<turnstile> Ds \<sqsubseteq> Cs';
     ∀(Cs',mthd)∈{(Cs',mthd). MethodDefs' P C M Cs' mthd}. ∃(Cs'',mthd)∈{(Cs',mthd). MethodDefs' P C M Cs' mthd}. ¬ P,C \<turnstile> Cs' \<sqsubseteq> Cs'';
     last Cs ≠ hd Ds; P \<turnstile> (C,Ds) has overrider M = (Ts,T,pns,body) via Cs';
     length vs = length pns; Casts_aux P Ts vs vs';
     l2' = [this\<mapsto>Ref (a,Cs'), pns[\<mapsto>]vs']; 
     new_body = (case T' of Class D => (|D|)),body   | _  => body);
     P,E(this\<mapsto>Class(last Cs'), pns[\<mapsto>]Ts) \<turnstile> ⟨new_body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩ |]
  ==> P,E \<turnstile> ⟨e•M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
apply(rule Call,assumption)
apply(simp add: map_val_conv[symmetric])
apply assumption+
apply(rule dyn_ambiguous)
apply(simp add:ambiguous,blast)
apply(simp add:appendPath_def)
apply assumption
apply(simp add:Casts_aux_eq)
apply assumption+
done

lemma StaticCall_new1:
  assumes evals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩" and map:"map_val evs vs"
  and path:"Subobjs P (last Cs) Cs''" "last Cs'' = C"
  and unique:"∀Xs∈{Xs. Subobjs P (last Cs) Xs}. last Xs = C --> Cs'' = Xs"
  and eq1:"last Cs = hd Cs''" and eq2:"last Cs'' = hd Cs'"
  and append:"Ds = (Cs@tl Cs'')@tl Cs'" and casts:"Casts_aux P Ts vs vs'"
  and rest:"P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩"  "length vs = length pns"
    "l2' = [this\<mapsto>Ref (a,Ds), pns[\<mapsto>]vs']"
    "P \<turnstile> C has least M = (Ts,T,pns,body) via Cs'"
    "P,E(this\<mapsto>Class(last Ds), pns[\<mapsto>]Ts) \<turnstile> ⟨body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩"
  shows "P,E \<turnstile> ⟨e•(C::)M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
proof -
  from evals map have evalsVals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨map Val vs,(h2,l2)⟩"
    by(simp add: map_val_conv[symmetric])
  from path have path_via:"P \<turnstile> Path (last Cs) to C via Cs''"
    by(simp add:path_via_def)
  from path unique have path_unique:"P \<turnstile> Path (last Cs) to C unique"
    by(auto simp:path_unique_def)
  from path have notempty:"Cs'' ≠ []" by -(rule Subobjs_nonempty)
  have "last(Cs@tl Cs'') = hd Cs'"
  proof(cases "tl Cs'' = []")
    case True 
    with notempty have Cs'':"Cs'' = [hd Cs'']" by(fastsimp dest:hd_Cons_tl)
    hence "last Cs'' = hd Cs''" by(cases Cs'') auto
    with eq1 eq2 True show ?thesis by simp
  next
    case False
    from notempty eq2 have "last(hd Cs''#tl Cs'') = hd Cs'"
      by(fastsimp dest:hd_Cons_tl)
    with False show ?thesis by(simp add:last_append)
  qed
  with eq1 eq2 append have Ds:"Ds = (Cs@pCs'')@pCs'"
    by(simp add:appendPath_def)
  from casts have "P \<turnstile> Ts Casts vs to vs'" by(simp add:Casts_aux_eq)
  with evalsVals path_via path_unique Ds rest show ?thesis
    by -(rule StaticCall)
qed

lemma StaticCall_new2:
  assumes evals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩" and map:"map_val evs vs"
  and path:"Subobjs P (last Cs) Cs''" "last Cs'' = C"
  and unique:"∀Xs∈{Xs. Subobjs P (last Cs) Xs}. last Xs = C --> Cs'' = Xs"
  and eq1:"last Cs = hd Cs''" and eq2:"last Cs'' ≠ hd Cs'"
  and append:"Ds = Cs'" and casts:"Casts_aux P Ts vs vs'"
  and rest:"P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩"  "length vs = length pns"
    "l2' = [this\<mapsto>Ref (a,Ds), pns[\<mapsto>]vs']"
    "P \<turnstile> C has least M = (Ts,T,pns,body) via Cs'"
    "P,E(this\<mapsto>Class(last Ds), pns[\<mapsto>]Ts) \<turnstile> ⟨body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩"
  shows "P,E \<turnstile> ⟨e•(C::)M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
proof -
  from evals map have evalsVals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨map Val vs,(h2,l2)⟩"
    by(simp add: map_val_conv[symmetric])
  from path have path_via:"P \<turnstile> Path (last Cs) to C via Cs''"
    by(simp add:path_via_def)
  from path unique have path_unique:"P \<turnstile> Path (last Cs) to C unique"
    by(auto simp:path_unique_def)
  from path have notempty:"Cs'' ≠ []" by -(rule Subobjs_nonempty)
  have "last(Cs@tl Cs'') ≠ hd Cs'"
  proof(cases "tl Cs'' = []")
    case True 
    with notempty have Cs'':"Cs'' = [hd Cs'']" by(fastsimp dest:hd_Cons_tl)
    hence "last Cs'' = hd Cs''" by(cases Cs'') auto
    with eq1 eq2 True show ?thesis by simp
  next
    case False
    from notempty eq2 have "last(hd Cs''#tl Cs'') ≠ hd Cs'"
      by(fastsimp dest:hd_Cons_tl)
    with False show ?thesis by(simp add:last_append)
  qed
  with eq1 eq2 append have Ds:"Ds = (Cs@pCs'')@pCs'"
    by(simp add:appendPath_def)
  from casts have "P \<turnstile> Ts Casts vs to vs'" by(simp add:Casts_aux_eq)
  with evalsVals path_via path_unique Ds rest show ?thesis
    by -(rule StaticCall)
qed

lemma StaticCall_new3:
  assumes evals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩" and map:"map_val evs vs"
  and path:"Subobjs P (last Cs) Cs''" "last Cs'' = C"
  and unique:"∀Xs∈{Xs. Subobjs P (last Cs) Xs}. last Xs = C --> Cs'' = Xs"
  and eq1:"last Cs ≠ hd Cs''" and eq2:"last Cs'' = hd Cs'"
  and append:"Ds = Cs''@tl Cs'" and casts:"Casts_aux P Ts vs vs'"
  and rest:"P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩"  "length vs = length pns"
    "l2' = [this\<mapsto>Ref (a,Ds), pns[\<mapsto>]vs']"
    "P \<turnstile> C has least M = (Ts,T,pns,body) via Cs'"
    "P,E(this\<mapsto>Class(last Ds), pns[\<mapsto>]Ts) \<turnstile> ⟨body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩"
  shows "P,E \<turnstile> ⟨e•(C::)M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
proof -
  from evals map have evalsVals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨map Val vs,(h2,l2)⟩"
    by(simp add: map_val_conv[symmetric])
  from path have path_via:"P \<turnstile> Path (last Cs) to C via Cs''"
    by(simp add:path_via_def)
  from path unique have path_unique:"P \<turnstile> Path (last Cs) to C unique"
    by(auto simp:path_unique_def)
  from eq1 eq2 append have Ds:"Ds = (Cs@pCs'')@pCs'"
    by(simp add:appendPath_def)
  from casts have "P \<turnstile> Ts Casts vs to vs'" by(simp add:Casts_aux_eq)
  with evalsVals path_via path_unique Ds rest show ?thesis
    by -(rule StaticCall)
qed

lemma StaticCall_new4:
  assumes evals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨evs,(h2,l2)⟩" and map:"map_val evs vs"
  and path:"Subobjs P (last Cs) Cs''" "last Cs'' = C"
  and unique:"∀Xs∈{Xs. Subobjs P (last Cs) Xs}. last Xs = C --> Cs'' = Xs"
  and eq1:"last Cs ≠ hd Cs''" and eq2:"last Cs'' ≠ hd Cs'"
  and append:"Ds = Cs'" and casts:"Casts_aux P Ts vs vs'"
  and rest:"P,E \<turnstile> ⟨e,s0⟩ => ⟨ref (a,Cs),s1⟩"  "length vs = length pns"
    "l2' = [this\<mapsto>Ref (a,Ds), pns[\<mapsto>]vs']"
    "P \<turnstile> C has least M = (Ts,T,pns,body) via Cs'"
    "P,E(this\<mapsto>Class(last Ds), pns[\<mapsto>]Ts) \<turnstile> ⟨body,(h2,l2')⟩ => ⟨e',(h3,l3)⟩"
  shows "P,E \<turnstile> ⟨e•(C::)M(ps),s0⟩ => ⟨e',(h3,l2)⟩"
proof -
  from evals map have evalsVals:"P,E \<turnstile> ⟨ps,s1⟩ [=>] ⟨map Val vs,(h2,l2)⟩"
    by(simp add: map_val_conv[symmetric])
  from path have path_via:"P \<turnstile> Path (last Cs) to C via Cs''"
    by(simp add:path_via_def)
  from path unique have path_unique:"P \<turnstile> Path (last Cs) to C unique"
    by(auto simp:path_unique_def)
  from eq1 eq2 append have Ds:"Ds = (Cs@pCs'')@pCs'"
    by(simp add:appendPath_def)
  from casts have "P \<turnstile> Ts Casts vs to vs'" by(simp add:Casts_aux_eq)
  with evalsVals path_via path_unique Ds rest show ?thesis
    by -(rule StaticCall)
qed

section{* Rewriting lemmas for Type rules *}


lemma WTDynCast_new1:
  "[| P,E \<turnstile> e :: Class D; is_class P C;
    Subobjs P D Cs'; last Cs' = C;
    ∀Cs''∈{Cs''. Subobjs P D Cs''}. last Cs'' = C --> Cs' = Cs''|]
  ==> P,E \<turnstile> Cast C e :: Class C"
  by (rule WTDynCast,auto simp add: path_unique_def)

lemma WTDynCast_new2:
  "[| P,E \<turnstile> e :: Class D; is_class P C;
     ∀Cs''∈{Cs''. Subobjs P D Cs''}. last Cs'' = C --> False|]
  ==> P,E \<turnstile> Cast C e :: Class C"
  by (rule WTDynCast,auto simp add: path_via_def)

lemma WTStaticCast_new1:
  "[| P,E \<turnstile> e :: Class D; is_class P C;
    Subobjs P D Cs'; last Cs' = C;
    ∀Cs''∈{Cs'. Subobjs P D Cs'}. last Cs'' = C --> Cs' = Cs''|]
  ==> P,E \<turnstile> (|C|)),e :: Class C"
  by (rule WTStaticCast,auto simp add: path_unique_def)

lemma WTStaticCast_new2:
"[|P,E \<turnstile> e :: Class D; is_class P C; P \<turnstile> C \<preceq>* D;
  ∀Cs∈{Cs. Subobjs P C Cs}. last Cs = D --> SubobjsR P C Cs |]
  ==> P,E \<turnstile> (|C|)),e :: Class C"
  by (rule WTStaticCast,auto simp:path_via_def)

lemma WTBinOp1: "[| P,E \<turnstile> e1 :: T;  P,E \<turnstile> e2 :: T|]
  ==> P,E \<turnstile> e1 «Eq» e2 :: Boolean"
  apply (rule WTBinOp)
  apply assumption+
  apply simp
  done

lemma WTBinOp2: "[| P,E \<turnstile> e1 :: Integer;  P,E \<turnstile> e2 :: Integer |]
  ==> P,E \<turnstile> e1 «Add» e2 :: Integer"
  apply (rule WTBinOp)
  apply assumption+
  apply simp
  done

lemma WTStaticCall_new:
  "[| P,E \<turnstile> e :: Class C'; Subobjs P C' Cs'; last Cs' = C;
    ∀Cs''∈{Cs''. Subobjs P C' Cs''}. last Cs'' = C --> Cs' = Cs'';
     P \<turnstile> C has least M = (Ts,T,m) via Cs; P,E \<turnstile> es [::] Ts'; P \<turnstile> Ts' [≤] Ts |]
  ==> P,E \<turnstile> e•(C::)M(es) :: T"
  apply(rule WTStaticCall)
  apply assumption
  apply(auto simp:path_unique_def)
  done

lemma [code_ind]:
  "[|Subobjs P C Cs'; last Cs' = D;
    ∀Cs''∈{Cs''. Subobjs P C Cs''}. last Cs'' = D --> Cs' = Cs'' |] 
==> P \<turnstile> Class C ≤ Class D"
by(rule widen_subcls,auto simp:path_unique_def)

lemmas [code_ind] = widen_refl widen_null



section{* Code generation *}

lemmas [code_ind] = 
 Overrider1[simplified LeastMethodDef_def codegen_simps, OF conjI]
 Overrider2[simplified LeastMethodDef_def codegen_simps, OF conjI]

 (* Semantic rules *)
 eval_evals.New eval_evals.NewFail
 StaticUpCast_new1 StaticUpCast_new2 StaticDownCast_new
 eval_evals.StaticCastNull StaticCastFail_new eval_evals.StaticCastThrow
 StaticUpDynCast_new1 StaticUpDynCast_new2 StaticDownDynCast_new
 DynCast_new eval_evals.DynCastNull
 DynCastFail_new eval_evals.DynCastThrow
 eval_evals.Val eval_evals.Var
 eval_evals.BinOp eval_evals.BinOpThrow1 eval_evals.BinOpThrow2
 LAss_new eval_evals.LAssThrow FAcc_new1 FAcc_new2 
 FAss_new1[simplified LeastFieldDecl_def codegen_simps, OF _ _ _ conjI]
 FAss_new2[simplified LeastFieldDecl_def codegen_simps, OF _ _ _ conjI]
 eval_evals.FAssNull eval_evals.FAssThrow1 eval_evals.FAssThrow2
 eval_evals.CallObjThrow CallNull_new CallParamsThrow_new 
 Call_new[simplified LeastMethodDef_def codegen_simps, OF _ _ _ _ conjI conjI]
 CallOverrider_new1[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                    OF _ _ _ _ conjI _ _ _ conjI]
 CallOverrider_new2[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                    OF _ _ _ _ conjI _ _ _ conjI]
 StaticCall_new1[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                 OF _ _ _ _ _ _ _ _ _ _ _ _ conjI]
 StaticCall_new2[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                 OF _ _ _ _ _ _ _ _ _ _ _ _ conjI]
 StaticCall_new3[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                 OF _ _ _ _ _ _ _ _ _ _ _ _ conjI]
 StaticCall_new4[simplified FinalOverriderMethodDef_def LeastMethodDef_def codegen_simps,
                 OF _ _ _ _ _ _ _ _ _ _ _ _ conjI]
 eval_evals.Block eval_evals.Seq eval_evals.SeqThrow
 eval_evals.CondT eval_evals.CondF eval_evals.CondThrow
 eval_evals.WhileF eval_evals.WhileT 
 eval_evals.WhileCondThrow eval_evals.WhileBodyThrow
 eval_evals.Throw eval_evals.ThrowNull eval_evals.ThrowThrow
 eval_evals.Nil eval_evals.Cons eval_evals.ConsThrow

 (* Type rules *)
 WT_WTs.WTNew WTDynCast_new1 WTDynCast_new2
 WTStaticCast_new1 WTStaticCast_new2
 WT_WTs.WTVal WT_WTs.WTVar WTBinOp1 WTBinOp2 WT_WTs.WTLAss
 WT_WTs.WTFAcc[unfolded LeastFieldDecl_def codegen_simps, OF _ conjI]
 WT_WTs.WTFAss[unfolded LeastFieldDecl_def codegen_simps, OF _ conjI]
 WT_WTs.WTCall[unfolded LeastMethodDef_def codegen_simps, OF _ conjI]
 WTStaticCall_new[unfolded LeastMethodDef_def codegen_simps, OF _ _ _ _ conjI]
 WT_WTs.WTBlock WT_WTs.WTSeq WT_WTs.WTCond WT_WTs.WTWhile WT_WTs.WTThrow
 WT_WTs.WTNil WT_WTs.WTCons



lemmas [code_ind_set] = rtrancl.rtrancl_refl converse_rtrancl_into_rtrancl

(* A hack to make set operations work on sets with function types *)

consts_code
  "insert :: ('a × ('b => 'c)) => ('a × ('b => 'c)) set => ('a × ('b => 'c)) set"
    ("(fn x => fn {*Set*} xs => {*Set*} (Library.insert (eq'_fst (op =)) x xs))")
  "Executable_Set.union :: ('a × ('b => 'c)) set => ('a × ('b => 'c)) set => ('a × ('b => 'c)) set"
    ("(fn {*Set*} xs => fn {*Set*} ys => {*Set*} (Library.union (eq'_fst (op =)) xs ys))")
  "minus :: ('a × ('b => 'c)) set => ('a × ('b => 'c)) set => ('a × ('b => 'c)) set"
    ("(fn {*Set*} xs => fn {*Set*} ys => {*Set*} (Library.subtract (eq'_fst (op =)) ys xs))")

consts_code
  "new_Addr"
   ("\<module>new'_addr {* 0::nat *} {* Suc *}
               {* %x. case x of None => True | Some y => False *} {* Some *}")
attach {*
fun new_addr z s alloc some hp =
  let fun nr i = if alloc (hp i) then some i else nr (s i);
  in nr z end;
*}

  "undefined" ("(raise ERROR \"undefined\")")


text{* Definition of program examples *}


lemma [code_unfold]: "x mem xs = ListMem x xs"
  by (simp add: mem_iff ListMem_iff)

text{* {\ldots}and off we go *}

  (* Examples with no prog needed *)
code_module NoProg
contains
  test0 = "[],empty \<turnstile> ⟨{''V'':Integer; ''V'' :=  Val(Intg 5);; Var ''V''},(empty,empty)⟩ => ⟨_,_⟩"
  test1 = "[],empty \<turnstile> ⟨Val(Intg 5),(empty,empty)⟩ => ⟨_,_⟩"
  test2 = "[],empty \<turnstile> ⟨(Val(Intg 5)) «Add» (Val(Intg 6)),(empty,empty)⟩ => ⟨_,_⟩"
  test3 = "[],[''V''\<mapsto>Integer] \<turnstile> ⟨(Var ''V'') «Add» (Val(Intg 6)),
                                       (empty,[''V''\<mapsto>Intg 77])⟩ => ⟨_,_⟩"
  test4 = "[],[''V''\<mapsto>Integer] \<turnstile> ⟨''V'' := Val(Intg 6),(empty,empty)⟩ => ⟨_,_⟩"
  testWhile = "[],[''V''\<mapsto>Integer,''a''\<mapsto>Integer,''b''\<mapsto>Integer,''mult''\<mapsto>Integer]
  \<turnstile> ⟨(''a'' := Val(Intg 3));;(''b'' := Val(Intg 4));;(''mult'' := Val(Intg 0));;
     (''V'' := Val(Intg 1));;
     while (Var ''V'' «Eq» Val(Intg 1))((''mult'' := Var ''mult'' «Add» Var ''b'');;
     (''a'' := Var ''a'' «Add» Val(Intg -1));;
     (''V'' := (if(Var ''a'' «Eq» Val(Intg 0)) Val(Intg 0) else Val(Intg 1)))),
     (empty,empty)⟩ => ⟨_,_⟩"

   testIf = "[],[''a''\<mapsto>Integer, ''b''\<mapsto>Integer, ''c''\<mapsto> Integer, ''cond''\<mapsto>Boolean] \<turnstile> ⟨''a'' := Val(Intg 17);; ''b'' := Val(Intg 13);; ''c'' := Val(Intg 42);; ''cond'' := true;; if (Var ''cond'') (Var ''a'' «Add» Var ''b'') else (Var ''a'' «Add» Var ''c''),(empty,empty)⟩ => ⟨_,_⟩"

V = "''V''"
mult = "''mult''"

ML {* local open NoProg in val Val (Intg 5) = fst (DSeq.hd test1) end *}
ML {* local open NoProg in val Val (Intg 11) = fst (DSeq.hd test2) end *}
ML {* local open NoProg in val Val (Intg 83) = fst (DSeq.hd test3) end *}
ML {* local open NoProg in val Some (Intg 6) = 
      let val (_,(h,l)) = DSeq.hd test4 in l V end end *}
ML {* local open NoProg in val Some (Intg 12) = 
      let val (_,(h,l)) = DSeq.hd testWhile in l mult end end *}
ML {* local open NoProg in val Val (Intg 30) = fst (DSeq.hd testIf) end *}


  (* progOverrider examples *)

constdefs
  -- "Overrider example"

  classBottom :: "cdecl"
  "classBottom == (''Bottom'', [Repeats ''Left'', Repeats ''Right''],
                   [(''x'',Integer)],[])" 

  classLeft :: "cdecl"
  "classLeft == (''Left'', [Repeats ''Top''],[],[(''f'', [Class ''Top'', Integer],Integer, [''V'',''W''],Var this • ''x'' {[''Left'',''Top'']} «Add» Val (Intg 5))])"

  classRight :: "cdecl"
  "classRight == (''Right'', [Shares ''Right2''],[],
    [(''f'', [Class ''Top'', Integer], Integer,[''V'',''W''],Var this • ''x'' {[''Right2'',''Top'']} «Add» Val (Intg 7)),(''g'',[],Class ''Left'',[],new ''Left'')])"

  classRight2 :: "cdecl"
  "classRight2 == (''Right2'', [Repeats ''Top''],[],
    [(''f'', [Class ''Top'', Integer], Integer,[''V'',''W''],Var this • ''x'' {[''Right2'',''Top'']} «Add» Val (Intg 9)),(''g'',[],Class ''Top'',[],new ''Top'')])"

  classTop :: "cdecl"
  "classTop == (''Top'', [], [(''x'',Integer)],[])"

  progOverrider :: "cdecl list"
  "progOverrider == [classBottom, classLeft, classRight, classRight2, classTop]"


code_module ProgOverrider
contains
  dynCastSide = "progOverrider,[''V''\<mapsto>Class ''Right''] \<turnstile>
    ⟨''V'' := new ''Bottom'' ;; Cast ''Left'' (Var ''V''),(empty,empty)⟩ => ⟨_,_⟩"

  dynCastViaSh = "progOverrider,[''V''\<mapsto>Class ''Right2''] \<turnstile> 
    ⟨''V'' := new ''Right'' ;; Cast ''Right'' (Var ''V''),(empty,empty)⟩ => ⟨_,_⟩"

  block = "progOverrider,[''V''\<mapsto>Integer] \<turnstile> ⟨''V'' := Val(Intg 42) ;; {''V'':Class ''Left''; ''V'' := new ''Bottom''} ;; Var ''V'',(empty,empty)⟩ => ⟨_,_⟩"

  staticCall = "progOverrider,[''V''\<mapsto>Class ''Right'',''W''\<mapsto>Class ''Bottom''] \<turnstile>
   ⟨''V'' := new ''Bottom'' ;; ''W'' := new ''Bottom'' ;; 
    ((Cast ''Left'' (Var ''W''))•''x''{[''Left'',''Top'']} := Val(Intg 3));;
    (Var ''W''•(''Left''::)''f''([Var ''V'',Val(Intg 2)])),(empty,empty)⟩ => ⟨_,_⟩"

  call = "progOverrider,[''V''\<mapsto>Class ''Right2'',''W''\<mapsto>Class ''Left''] \<turnstile> 
  ⟨''V'' := new ''Right'' ;; ''W'' := new ''Left'' ;; (Var ''V''•''f''([Var ''W'',Val(Intg 42)])) «Add» (Var ''W''•''f''([Var ''V'',Val(Intg 13)])),(empty,empty)⟩ => ⟨_,_⟩"

  callOverrider = "progOverrider,[''V''\<mapsto>Class ''Right2'',''W''\<mapsto>Class ''Left''] \<turnstile>
  ⟨''V'' := new ''Bottom'';; (Var ''V'' • ''x'' {[''Right2'',''Top'']} := Val(Intg 6));; ''W'' := new ''Left'' ;; Var ''V''•''f''([Var ''W'',Val(Intg 42)]),(empty,empty)⟩ => ⟨_,_⟩"

  callClass = "progOverrider,[''V''\<mapsto>Class ''Right2''] \<turnstile>
  ⟨''V'' := new ''Right'' ;; Var ''V''•''g''([]),(empty,empty)⟩ => ⟨_,_⟩"

  fieldAss = "progOverrider,[''V''\<mapsto>Class ''Right2''] \<turnstile> ⟨''V'' := new ''Right'' ;; 
     (Var ''V''•''x''{[''Right2'',''Top'']} := (Val(Intg 42))) ;; 
     (Var ''V''•''x''{[''Right2'',''Top'']}),(empty,empty)⟩ => ⟨_,_⟩"

  typeNew = "progOverrider,empty \<turnstile> new ''Bottom'' :: _"
  typeDynCast = "progOverrider,empty \<turnstile> Cast ''Left'' (new ''Bottom'') :: _"
  typeStaticCast = "progOverrider,empty \<turnstile> (|''Left''|)), (new ''Bottom'') :: _"
  typeVal = "[],empty \<turnstile> Val(Intg 17) :: _"
  typeVar = "[],[''V'' \<mapsto> Integer] \<turnstile> Var ''V'' :: _"
  typeBinOp = "[],empty \<turnstile> (Val(Intg 5)) «Eq» (Val(Intg 6)) :: _" 
  typeLAss = "progOverrider,[''V'' \<mapsto> Class ''Top''] \<turnstile> ''V'' := (new ''Left'') :: _"
  typeFAcc = "progOverrider,empty \<turnstile> (new ''Right'')•''x''{[''Right2'',''Top'']} :: _"
  typeFAss = "progOverrider,empty \<turnstile> 
                  (new ''Right'')•''x''{[''Right2'',''Top'']} := (Val(Intg 17)) :: _"
  typeStaticCall = "progOverrider,[''V''\<mapsto>Class ''Left''] \<turnstile> ''V'' := new ''Left'' ;; Var ''V''•(''Left''::)''f''([new ''Top'', Val(Intg 13)]) :: _"
  typeCall = "progOverrider,[''V''\<mapsto>Class ''Right2''] \<turnstile> ''V'' := new ''Right'' ;; Var ''V''•''g''([]) :: _"
  typeBlock = "progOverrider,empty \<turnstile> {''V'':Class ''Top''; ''V'' := new ''Left''} :: _"
  typeCond = "[],empty \<turnstile> if (true) Val(Intg 6) else Val(Intg 9) :: _"
  typeWhile = "[],empty \<turnstile> while (false) Val(Intg 17) :: _"
  typeThrow = "progOverrider,empty \<turnstile> throw (new ''Bottom'') :: _"

  typeBig = "progOverrider,[''V''\<mapsto>Class ''Right2'',''W''\<mapsto>Class ''Left''] \<turnstile> 
  ''V'' := new ''Right'' ;; ''W'' := new ''Left'' ;; (Var ''V''•''f''([Var ''W'', Val(Intg 7)])) «Add» (Var ''W''•''f''([Var ''V'', Val(Intg 13)])) :: _"

Bottom = "''Bottom''"
Left = "''Left''"
Right = "''Right''"
Top = "''Top''"


ML {* local open ProgOverrider in val Val(Ref(0,[Bottom,Left])) = 
      fst (DSeq.hd dynCastSide) end *}
ML {* local open ProgOverrider in val Val(Ref(0,[Right])) = 
      fst (DSeq.hd dynCastViaSh) end *}
ML {* local open ProgOverrider in val Val(Intg 42) = fst (DSeq.hd block) end *}
ML {* local open ProgOverrider in val Val(Intg 8)  = fst (DSeq.hd staticCall) end *}
ML {* local open ProgOverrider in val Val(Intg 12) = fst (DSeq.hd call) end *}
ML {* local open ProgOverrider in val Val(Ref(1,[Left,Top])) = 
      fst (DSeq.hd callClass) end *}
ML {* local open ProgOverrider in val Val(Intg 42) = fst (DSeq.hd fieldAss) end *}


(* Typing rules *)
ML {* local open ProgOverrider in val Class Bottom = DSeq.hd typeNew end *}
ML {* local open ProgOverrider in val Class Left   = DSeq.hd typeDynCast end *}
ML {* local open ProgOverrider in val Class Left   = DSeq.hd typeStaticCast end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeVal end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeVar end *}
ML {* local open ProgOverrider in val Boolean      = DSeq.hd typeBinOp end *}
ML {* local open ProgOverrider in val Class Top    = DSeq.hd typeLAss end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeFAcc end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeFAss end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeStaticCall end *}
ML {* local open ProgOverrider in val Class Top    = DSeq.hd typeCall end *}
ML {* local open ProgOverrider in val Class Top    = DSeq.hd typeBlock end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeCond end *}
ML {* local open ProgOverrider in val Void         = DSeq.hd typeThrow end *}
ML {* local open ProgOverrider in val Integer      = DSeq.hd typeBig end *}



  (* progDiamond examples *)

constdefs
  --"Diamond class-name DAG"

  classDiamondBottom :: "cdecl"
  "classDiamondBottom == (''Bottom'', [Repeats ''Left'', Repeats ''Right''],[(''x'',Integer)],
    [(''g'', [],Integer, [],Var this • ''x'' {[''Bottom'']} «Add» Val (Intg 5))])" 

  classDiamondLeft :: "cdecl"
  "classDiamondLeft == (''Left'', [Repeats ''TopRep'',Shares ''TopSh''],[],[])"

  classDiamondRight :: "cdecl"
  "classDiamondRight == (''Right'', [Repeats ''TopRep'',Shares ''TopSh''],[],
    [(''f'', [Integer], Boolean,[''i''], Var ''i'' «Eq» Val (Intg 7))])"

  classDiamondTopRep :: "cdecl"
  "classDiamondTopRep == (''TopRep'', [], [(''x'',Integer)],
    [(''g'', [],Integer, [], Var this • ''x'' {[''TopRep'']} «Add» Val (Intg 10))])"

  classDiamondTopSh :: "cdecl"
  "classDiamondTopSh == (''TopSh'', [], [], 
    [(''f'', [Integer], Boolean,[''i''], Var ''i'' «Eq» Val (Intg 3))])"


  progDiamond :: "cdecl list"
  "progDiamond == [classDiamondBottom, classDiamondLeft, classDiamondRight, classDiamondTopRep, classDiamondTopSh]"


code_module ProgDiamond
contains
  cast1 = "progDiamond,[''V''\<mapsto>Class ''Left''] \<turnstile> ⟨''V'' := new ''Bottom'',
                                                      (empty,empty)⟩ => ⟨_,_⟩"
  cast2 = "progDiamond,[''V''\<mapsto>Class ''TopSh''] \<turnstile> ⟨''V'' := new ''Bottom'',
                                                      (empty,empty)⟩ => ⟨_,_⟩"
  cast3 = "progDiamond,[''V''\<mapsto>Class ''TopRep''] \<turnstile> ⟨''V'' := new ''Bottom'', 
                                                      (empty,empty)⟩ => ⟨_,_⟩"
  typeCast3 = "progDiamond,[''V''\<mapsto>Class ''TopRep''] \<turnstile> ''V'' := new ''Bottom'' :: _"

  fieldAss = "progDiamond,[''V''\<mapsto>Class ''Bottom''] \<turnstile> ⟨''V'' := new ''Bottom'' ;; 
              ((Var ''V'')•''x''{[''Bottom'']} := (Val(Intg 17))) ;; 
              ((Var ''V'')•''x''{[''Bottom'']}),(empty,empty)⟩ => ⟨_,_⟩"

  dynCastNull = "progDiamond,empty \<turnstile> ⟨Cast ''Right'' null,(empty,empty)⟩ => ⟨_,_⟩"

  dynCastViaSh = "progDiamond,[''V''\<mapsto>Class ''TopSh''] \<turnstile> 
    ⟨''V'' := new ''Right'' ;; Cast ''Right'' (Var ''V''),(empty,empty)⟩ => ⟨_,_⟩"


  dynCastFail = "progDiamond,[''V''\<mapsto>Class ''TopRep''] \<turnstile>
    ⟨''V'' := new ''Right'' ;; Cast ''Bottom'' (Var ''V''),(empty,empty)⟩ => ⟨_,_⟩"


  dynCastSide = "progDiamond,[''V''\<mapsto>Class ''Right''] \<turnstile>
    ⟨''V'' := new ''Bottom'' ;; Cast ''Left'' (Var ''V''),(empty,empty)⟩ => ⟨_,_⟩"

Bottom = "''Bottom''"
Left = "''Left''"
TopSh = "''TopSh''"
TopRep = "''TopRep''"



ML {* local open ProgDiamond in val Val(Ref(0,[Bottom,Left])) = 
      fst (DSeq.hd cast1) end *}
ML {* local open ProgDiamond in val Val(Ref(0,[TopSh])) = fst (DSeq.hd cast2) end *}
(* ML {* local open ProgDiamond in val Val(Ref(0,[Bottom,Left,TopRep])) =
       if DSeq.hd typeCast3 = Class TopRep then fst (DSeq.hd cast3) else error "" end *}
 error! cast3 not typeable! *)
ML {* local open ProgDiamond in val Val(Intg 17) = fst (DSeq.hd fieldAss) end *}
ML {* local open ProgDiamond in val Val Null = fst (DSeq.hd dynCastNull) end *}
ML {* local open ProgDiamond in val Val Null = fst (DSeq.hd dynCastFail) end *}
ML {* local open ProgDiamond in val Val(Ref(0,[Bottom,Left])) = 
      fst (DSeq.hd dynCastSide) end *}



  (* failing g++ example *)

constdefs
  -- "failing example"

  classD :: "cdecl"
  "classD == (''D'', [Shares ''A'', Shares ''B'', Repeats ''C''],[],[])"

  classC :: "cdecl"
  "classC == (''C'', [Shares ''A'', Shares ''B''],[],
              [(''f'',[],Integer,[],Val(Intg 42))])"

  classB :: "cdecl"
  "classB == (''B'', [],[],
              [(''f'',[],Integer,[],Val(Intg 17))])"

  classA :: "cdecl"
  "classA == (''A'', [],[],
              [(''f'',[],Integer,[],Val(Intg 13))])"

  ProgFailing :: "cdecl list"
  "ProgFailing == [classA,classB,classC,classD]"

code_module Fail
contains

  callFailGplusplus = "ProgFailing,empty \<turnstile>
    ⟨{''V'':Class ''D''; ''V'' := new ''D'';; Var ''V''•''f''([])},(empty,empty)⟩ 
                                                                       => ⟨_,_⟩"

ML {* local open Fail in val Val(Intg 42) = 
      fst (DSeq.hd callFailGplusplus) end *}

end