Theory PCompiler

(*  Title:      JinjaThread/Compiler/PCompiler.thy
    Author:     Tobias Nipkow, Andreas Lochbihler
*)

section ‹Program Compilation›

theory PCompiler
imports
  "../Common/WellForm"
  "../Common/BinOp"
  "../Common/Conform"
begin

definition compM :: "(mname  ty list  ty  'a  'b)  'a mdecl'  'b mdecl'"
where "compM f  λ(M, Ts, T, m). (M, Ts, T, map_option (f M Ts T) m)"

definition compC :: "(cname  mname  ty list  ty  'a  'b)  'a cdecl  'b cdecl"
where "compC f    λ(C,D,Fdecls,Mdecls). (C,D,Fdecls, map (compM (f C)) Mdecls)"

primrec compP :: "(cname  mname  ty list  ty  'a  'b)  'a prog  'b prog"
where "compP f (Program P) = Program (map (compC f) P)"

text‹Compilation preserves the program structure.  Therfore lookup
functions either commute with compilation (like method lookup) or are
preserved by it (like the subclass relation).›

lemma map_of_map4:
  "map_of (map (λ(x,a,b,c).(x,a,b,f x a b c)) ts) =
  (λx. map_option (λ(a,b,c).(a,b,f x a b c)) (map_of ts x))"
apply(induct ts)
 apply simp
apply(rule ext)
apply fastforce
done

lemma class_compP:
  "class P C = Some (D, fs, ms)
   class (compP f P) C = Some (D, fs, map (compM (f C)) ms)"
by(cases P)(simp add:class_def compP_def compC_def map_of_map4)

lemma class_compPD:
  "class (compP f P) C = Some (D, fs, cms)
   ms. class P C = Some(D,fs,ms)  cms = map (compM (f C)) ms"
by(cases P)(clarsimp simp add:class_def compP_def compC_def map_of_map4)


lemma [simp]: "is_class (compP f P) C = is_class P C"
(*<*)by(auto simp:is_class_def dest: class_compP class_compPD)(*>*)


lemma [simp]: "class (compP f P) C = map_option (λc. snd(compC f (C,c))) (class P C)"
(*<*)
apply(cases P)
apply(simp add:compC_def class_def map_of_map4)
apply(simp add:split_def)
done
(*>*)

lemma sees_methods_compP:
  "P  C sees_methods Mm 
  compP f P  C sees_methods (λM. map_option (λ((Ts,T,m),D). ((Ts,T,map_option (f D M Ts T) m),D)) (Mm M))"
(*<*)
apply(erule Methods.induct)
 apply(rule sees_methods_Object)
  apply(erule class_compP)
 apply(rule ext)
 apply(simp add:compM_def map_of_map4 option.map_comp)
 apply(case_tac "map_of ms M")
  apply simp
 apply fastforce
apply(rule sees_methods_rec)
   apply(erule class_compP)
  apply assumption
 apply assumption
apply(rule ext)
apply(simp add:map_add_def compM_def map_of_map4 option.map_comp split:option.split)
done
(*>*)


lemma sees_method_compP:
  "P  C sees M: TsT = m in D 
  compP f P  C sees M: TsT = map_option (f D M Ts T) m in D"
(*<*)by(fastforce elim:sees_methods_compP simp add:Method_def)(*>*)


lemma [simp]:
  "P  C sees M: TsT = m in D 
  method (compP f P) C M = (D,Ts,T,map_option (f D M Ts T) m)"
(*<*)
apply(drule sees_method_compP)
apply(simp add:method_def)
apply(rule the_equality)
 apply simp
apply(fastforce dest:sees_method_fun)
done
(*>*)


lemma sees_methods_compPD:
  " cP  C sees_methods Mm'; cP = compP f P  
  Mm. P  C sees_methods Mm 
        Mm' = (λM. map_option (λ((Ts,T,m),D). ((Ts,T,map_option (f D M Ts T) m),D)) (Mm M))"
(*<*)
apply(erule Methods.induct)
 apply(clarsimp simp:compC_def)
 apply(rule exI)
 apply(rule conjI, erule sees_methods_Object)
 apply(rule refl)
 apply(rule ext)
 apply(simp add:compM_def map_of_map4 option.map_comp)
 apply(case_tac "map_of b M")
  apply simp
 apply fastforce
apply(clarsimp simp:compC_def)
apply(rule exI, rule conjI)
apply(erule (2) sees_methods_rec)
 apply(rule refl)
apply(rule ext)
apply(simp add:map_add_def compM_def map_of_map4 option.map_comp split:option.split)
done
(*>*)


lemma sees_method_compPD:
  "compP f P  C sees M: TsT = fm in D 
  m. P  C sees M: TsT = m in D  map_option (f D M Ts T) m = fm"
(*<*)
apply(simp add:Method_def)
apply clarify
apply(drule sees_methods_compPD[OF _ refl])
apply clarsimp
apply blast
done
(*>*)

lemma sees_method_native_compP [simp]:
  "compP f P  C sees M:Ts  T = Native in D  P  C sees M:Ts  T = Native in D"
by(auto dest: sees_method_compPD sees_method_compP)

lemma [simp]: "subcls1(compP f P) = subcls1 P"
by(fastforce simp add: is_class_def compC_def intro:subcls1I order_antisym dest:subcls1D)

lemma [simp]: "is_type (compP f P) T = is_type P T"
by(induct T)(auto cong: ty.case_cong)

lemma is_type_compP [simp]: "is_type (compP f P) = is_type P"
by auto

lemma compP_widen[simp]:
  "(compP f P  T  T') = (P  T  T')"
by(induct T' arbitrary: T)(simp_all add: widen_Class widen_Array)

lemma [simp]: "(compP f P  Ts [≤] Ts') = (P  Ts [≤] Ts')"
(*<*)
apply(induct Ts)
 apply simp
apply(cases Ts')
apply(auto simp:fun_of_def)
done
(*>*)

lemma is_lub_compP [simp]:
  "is_lub (compP f P) = is_lub P"
by(auto intro!: ext elim!: is_lub.cases intro: is_lub.intros)

lemma [simp]:
  fixes f :: "cname  mname  ty list  ty  'a  'b"
  shows "(compP f P  C has_fields FDTs) = (P  C has_fields FDTs)"
(*<*)
 (is "?A = ?B")
proof
  { fix cP::"'b prog" assume "cP  C has_fields FDTs"
    hence "cP = compP f P  P  C has_fields FDTs"
    proof induct
      case has_fields_Object
      thus ?case by(fast intro:Fields.has_fields_Object dest:class_compPD)
    next
      case has_fields_rec
      thus ?case by(fast intro:Fields.has_fields_rec dest:class_compPD)
    qed
  } note lem = this
  assume ?A
  with lem show ?B by blast
next
  assume ?B
  thus ?A
  proof induct
    case has_fields_Object
    thus ?case by(fast intro:Fields.has_fields_Object class_compP)
  next
    case has_fields_rec
    thus ?case by(fast intro:Fields.has_fields_rec class_compP)
  qed
qed
(*>*)


lemma [simp]: "fields (compP f P) C = fields P C"
(*<*)by(simp add:fields_def)(*>*)


lemma [simp]: "(compP f P  C sees F:T (fm) in D) = (P  C sees F:T (fm) in D)"
(*<*)by(simp add:sees_field_def)(*>*)


lemma [simp]: "field (compP f P) F D = field P F D"
(*<*)by(simp add:field_def)(*>*)


subsection‹Invariance of @{term wf_prog} under compilation›

lemma [iff]: "distinct_fst (classes (compP f P)) = distinct_fst (classes P)"
(*<*)
apply(cases P)
apply(simp add:distinct_fst_def compP_def compC_def)
apply(rename_tac list)
apply(induct_tac list)
apply (auto simp:image_iff)
done
(*>*)


lemma [iff]: "distinct_fst (map (compM f) ms) = distinct_fst ms"
(*<*)
apply(simp add:distinct_fst_def compM_def)
apply(induct ms)
apply (auto simp:image_iff)
done
(*>*)


lemma [iff]: "wf_syscls (compP f P) = wf_syscls P"
unfolding wf_syscls_def by auto

lemma [iff]: "wf_fdecl (compP f P) = wf_fdecl P"
(*<*)by(simp add:wf_fdecl_def)(*>*)


lemma set_compP:
 "(class (compP f P) C = (D,fs,ms'))  
  (ms. class P C = (D,fs,ms)  ms' = map (compM (f C)) ms)"
by(cases P)(auto simp add: compC_def image_iff map_of_map4)

lemma compP_has_method: "compP f P  C has M  P  C has M"
unfolding has_method_def
by(fastforce dest: sees_method_compPD intro: sees_method_compP)

lemma is_native_compP [simp]: "is_native (compP f P) = is_native P"
by(auto simp add: fun_eq_iff is_native.simps)

lemma τexternal_compP [simp]:
  "τexternal (compP f P) = τexternal P"
by(auto intro!: ext simp add: τexternal_def)

context heap_base begin

lemma heap_clone_compP [simp]: 
  "heap_clone (compP f P) = heap_clone P"
by(intro ext)(auto elim!: heap_clone.cases intro: heap_clone.intros)

lemma red_external_compP [simp]:
  "compP f P,t  aM(vs), h -ta→ext va, h'  P,t  aM(vs), h -ta→ext va, h'"
by(auto elim!: red_external.cases intro: red_external.intros)

lemma τexternal'_compP [simp]:
  "τexternal' (compP f P) = τexternal' P"
by(simp add: τexternal'_def [abs_def])

end

lemma wf_overriding_compP [simp]: "wf_overriding (compP f P) D (compM (f C) m) = wf_overriding P D m"
by(cases m)(fastforce intro: sees_method_compP[where f=f] dest: sees_method_compPD[where f=f] simp add: compM_def)

lemma wf_cdecl_compPI:
  assumes wf1_imp_wf2: 
    "C M Ts T m.  wf_mdecl wf1 P C (M,Ts,T,m); P  C sees M:TsT = m in C 
     wf_mdecl wf2 (compP f P) C (M,Ts,T, f C M Ts T m)"
  and wfcP1: "C rest. class P C = rest  wf_cdecl wf1 P (C, rest)"
  and xcomp: "class (compP f P) C = rest'"
  and wf: "wf_prog p P"
  shows "wf_cdecl wf2 (compP f P) (C, rest')"
proof -
  obtain D fs ms' where x: "rest' = (D, fs, ms')" by(cases rest')
  with xcomp obtain ms where xsrc: "class P C = (D,fs,ms)"
    and ms': "ms' = map (compM (f C)) ms"
    by(auto simp add: set_compP compC_def)
  from xsrc wfcP1 have wf1: "wf_cdecl wf1 P (C,D,fs,ms)" by blast
  { fix field
    assume "field  set fs"
    with wf1 have "wf_fdecl (compP f P) field" by(simp add: wf_cdecl_def) 
  }
  moreover from wf1 have "distinct_fst fs" by(simp add: wf_cdecl_def)
  moreover
  { fix m
    assume mset': "m  set ms'"
    obtain M Ts' T' body' where m: "m = (M, Ts', T', body')" by(cases m)
    with ms' obtain body where mf: "body' = map_option (f C M Ts' T') body"
      and mset: "(M, Ts', T', body)  set ms" using mset'
      by(clarsimp simp add: image_iff compM_def)
    moreover from mset xsrc wfcP1 have "wf_mdecl wf1 P C (M,Ts',T',body)"
      by(fastforce simp add: wf_cdecl_def)
    moreover from wf xsrc mset x have "P  C sees M:Ts'T' = body in C"
      by(auto intro: mdecl_visible)
    ultimately have "wf_mdecl wf2 (compP f P) C m" using m
      by(cases body)(simp add: wf_mdecl_def, auto intro: wf1_imp_wf2) }
  moreover from wf1 have "distinct_fst ms" by(simp add: wf_cdecl_def)
  with ms' have "distinct_fst ms'" by(auto)
  moreover
  { assume CObj: "C  Object"
    with xsrc wfcP1
    have part1: "is_class (compP f P) D" "¬ compP f P  D * C"
      by(auto simp add: wf_cdecl_def)
    { fix m
      assume mset': "m  set ms'"
      obtain M Ts T body' where m: "m = (M, Ts, T, body')" by(cases m)
      with mset' ms' obtain body where mf: "body' = map_option (f C M Ts T) body"
        and mset: "(M, Ts, T, body)  set ms"
        by(clarsimp simp add: image_iff compM_def)
      from wf1 CObj mset
      have "wf_overriding P D (M, Ts, T, body)" by(auto simp add: wf_cdecl_def simp del: wf_overriding.simps)
      hence "wf_overriding (compP f P) D m" unfolding m mf
        by(subst (asm) wf_overriding_compP[symmetric, where f=f and C=C])(simp del: wf_overriding.simps wf_overriding_compP add: compM_def) }
    note this part1 }
  moreover
  { assume "C = Thread"
    with wf1 ms' have "m. (run, [], Void, m)  set ms'"
      by(fastforce simp add: wf_cdecl_def image_iff compM_def)+ }
  ultimately show ?thesis unfolding x wf_cdecl_def by blast
qed

lemma wf_prog_compPI:
assumes lift: 
  "C M Ts T m. 
     P  C sees M:TsT = m in C; wf_mdecl wf1 P C (M,Ts,T,m) 
     wf_mdecl wf2 (compP f P) C (M,Ts,T, f C M Ts T m)"
and wf: "wf_prog wf1 P"
shows "wf_prog wf2 (compP f P)"
using wf
apply (clarsimp simp add:wf_prog_def2)
apply(rule wf_cdecl_compPI[OF lift], assumption+)
apply(auto intro: wf)
done

lemma wf_cdecl_compPD:
  assumes wf1_imp_wf2: 
    "C M Ts T m.  wf_mdecl wf1 (compP f P) C (M,Ts,T,f C M Ts T m); compP f P  C sees M:TsT = f C M Ts T m in C 
     wf_mdecl wf2 P C (M,Ts,T, m)"
  and wfcP1: "C rest. class (compP f P) C = rest  wf_cdecl wf1 (compP f P) (C, rest)"
  and xcomp: "class P C = rest"
  and wf: "wf_prog wf_md (compP f P)"
  shows "wf_cdecl wf2 P (C, rest)"
proof -
  obtain D fs ms' where x: "rest = (D, fs, ms')" by(cases rest)
  with xcomp have xsrc: "class (compP f P) C = (D,fs,map (compM (f C)) ms')"
    by(auto simp add: set_compP compC_def)
  from xsrc wfcP1 have wf1: "wf_cdecl wf1 (compP f P) (C,D,fs,map (compM (f C)) ms')" by blast
  { fix field
    assume "field  set fs"
    with wf1 have "wf_fdecl P field" by(simp add: wf_cdecl_def) 
  }
  moreover from wf1 have "distinct_fst fs" by(simp add: wf_cdecl_def)
  moreover
  { fix m
    assume mset': "m  set ms'"
    obtain M Ts' T' body' where m: "m = (M, Ts', T', body')" by(cases m)
    hence mset: "(M, Ts', T', map_option (f C M Ts' T') body')  set (map (compM (f C)) ms')" using mset'
      by(auto simp add: image_iff compM_def intro: rev_bexI)
    moreover from wf xsrc mset x have "compP f P  C sees M:Ts'T' = map_option (f C M Ts' T') body' in C"
      by(auto intro: mdecl_visible)
    moreover from mset wfcP1[rule_format, OF xsrc]
    have "wf_mdecl wf1 (compP f P) C (M,Ts',T',map_option (f C M Ts' T') body')"
      by(auto simp add: wf_cdecl_def)
    ultimately have "wf_mdecl wf2 P C m" using m
      by(cases body')(simp add: wf_mdecl_def, auto intro: wf1_imp_wf2) }
  moreover from wf1 have "distinct_fst ms'" by(simp add: wf_cdecl_def)
  moreover
  { assume CObj: "C  Object"
    with xsrc wfcP1
    have part1: "is_class P D" "¬ P  D * C"
      by(auto simp add: wf_cdecl_def)
    { fix m
      assume mset': "m  set ms'"
      with wf1 CObj have "wf_overriding (compP f P) D (compM (f C) m)"
        by(simp add: wf_cdecl_def del: wf_overriding_compP)
      hence "wf_overriding P D m" by simp }
    note this part1 }
  moreover
  { assume "C = Thread"
    with wf1 have "m. (run, [], Void, m)  set ms'"
      by(fastforce simp add: wf_cdecl_def image_iff compM_def)+ }
  ultimately show ?thesis unfolding x wf_cdecl_def by blast
qed

lemma wf_prog_compPD:
assumes wf: "wf_prog wf1 (compP f P)"
and lift: 
  "C M Ts T m. 
     compP f P  C sees M:TsT = f C M Ts T m in C; wf_mdecl wf1 (compP f P) C (M,Ts,T, f C M Ts T m) 
     wf_mdecl wf2 P C (M,Ts,T,m)"
shows "wf_prog wf2 P"
using wf
apply(clarsimp simp add:wf_prog_def2)
apply(rule wf_cdecl_compPD[OF lift], assumption+) 
apply(auto intro: wf)
done

lemma WT_binop_compP [simp]: "compP f P  T1«bop»T2 :: T  P  T1«bop»T2 :: T"
by(cases bop)(fastforce)+

lemma WTrt_binop_compP [simp]: "compP f P  T1«bop»T2 : T  P  T1«bop»T2 : T"
by(cases bop)(fastforce)+

lemma binop_relevant_class_compP [simp]: "binop_relevant_class bop (compP f P) = binop_relevant_class bop P"
by(cases bop) simp_all

lemma is_class_compP [simp]:
  "is_class (compP f P) = is_class P"
by(simp add: is_class_def fun_eq_iff)

lemma has_field_compP [simp]:
  "compP f P  C has F:T (fm) in D  P  C has F:T (fm) in D"
by(auto simp add: has_field_def)

context heap_base begin

lemma compP_addr_loc_type [simp]:
  "addr_loc_type (compP f P) = addr_loc_type P"
by(auto elim!: addr_loc_type.cases intro: addr_loc_type.intros intro!: ext)

lemma conf_compP [simp]:
  "compP f P,h  v :≤ T  P,h  v :≤ T"
by(simp add: conf_def)

lemma compP_conf: "conf (compP f P) = conf P"
by(auto simp add: conf_def intro!: ext)

lemma compP_confs: "compP f P,h  vs [:≤] Ts  P,h  vs [:≤] Ts"
by(simp add: compP_conf)

lemma tconf_compP [simp]: "compP f P, h  t √t  P,h  t √t"
by(auto simp add: tconf_def)

lemma wf_start_state_compP [simp]:
  "wf_start_state (compP f P) = wf_start_state P"
by(auto 4 6 simp add: fun_eq_iff wf_start_state.simps compP_conf dest: sees_method_compP[where f=f] sees_method_compPD[where f=f])

end

lemma compP_addr_conv:
  "addr_conv addr2thread_id thread_id2addr typeof_addr (compP f P) = addr_conv addr2thread_id thread_id2addr typeof_addr P"
unfolding addr_conv_def
by simp

lemma compP_heap:
  "heap addr2thead_id thread_id2addr allocate typeof_addr heap_write (compP f P) =
  heap addr2thead_id thread_id2addr allocate typeof_addr heap_write P"
unfolding heap_def compP_addr_conv heap_axioms_def
by auto

lemma compP_heap_conf:
  "heap_conf addr2thead_id thread_id2addr empty_heap allocate typeof_addr heap_write hconf (compP f P) =
   heap_conf addr2thead_id thread_id2addr empty_heap allocate typeof_addr heap_write hconf P"
unfolding heap_conf_def heap_conf_axioms_def compP_heap
unfolding heap_base.compP_conf heap_base.compP_addr_loc_type is_type_compP is_class_compP
by(rule refl)

lemma compP_heap_conf_read:
  "heap_conf_read addr2thead_id thread_id2addr empty_heap allocate typeof_addr heap_read heap_write hconf (compP f P) =
   heap_conf_read addr2thead_id thread_id2addr empty_heap allocate typeof_addr heap_read heap_write hconf P"
unfolding heap_conf_read_def heap_conf_read_axioms_def
unfolding compP_heap_conf heap_base.compP_conf heap_base.compP_addr_loc_type 
by(rule refl)

text ‹compiler composition›

lemma compM_compM:
  "compM f (compM g md) = compM (λM Ts T. f M Ts T  g M Ts T) md"
by(cases md)(simp add: compM_def option.map_comp o_def)

lemma compC_compC:
  "compC f (compC g cd) = compC (λC M Ts T. f C M Ts T  g C M Ts T) cd"
by(simp add: compC_def split_beta compM_compM)

lemma compP_compP:
  "compP f (compP g P) = compP (λC M Ts T. f C M Ts T  g C M Ts T) P"
by(cases P)(simp add: compC_compC)

end