blob: 5ee644ad11cc00aa84b50f4e9c2d883aa07a8169 [file]
(*
* Copyright 2018, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*)
theory Specialised_Lemma_USum
imports
Read_Table
SpecialisedLemmaTactic
begin
context update_sem_init
begin
ML \<open>
fun bool_of_variant_state @{term Checked} = true
| bool_of_variant_state @{term Unchecked} = false
| bool_of_variant_state x = raise ERROR ("bool_of_variant_state: not a variant_state: " ^ @{make_string} x)
fun variant_state_of_bool true = @{term Checked}
| variant_state_of_bool false = @{term Unchecked}
fun get_checkeds_of_usum_uval ctxt uval =
usum_list_of_types ctxt uval |>
map (fn x => x |> HOLogic.dest_prod |> snd |> HOLogic.dest_prod |> snd |> bool_of_variant_state)
\<close>
ML\<open> (* get_castable_uvals_from *)
local
infix can_be_casted_to
fun (uval1 can_be_casted_to uval2) ctxt heap_info =
(* Check if a pattern matching failure in case with a scrutinee of type uval1 will result in an expression of type uval2 *)
(* Returns NONE if uval1 cannot be casted to uval2.*)
(* Returns (SOME int) if uval1 can be casted to uval2 and we lose the int-th field in the c-struct for
uval1 by copying uval1 to uval2.*)
let
fun uval_to_field_names uval = heap_info_uval_to_field_names heap_info uval;
fun uval_to_field_types uval = heap_info_uval_to_field_types heap_info uval;
val field_names1 = uval_to_field_names uval1;
val field_names2 = uval_to_field_names uval2;
val field_types1 = uval_to_field_types uval1;
val field_types2 = uval_to_field_types uval2;
fun check_diff c1 c2 =
(c1 ~~ c2) |>
map_index I |>
filter (fn (_,(a,b)) => a <> b)
in
if (field_names1 = field_names2) andalso (field_types1 = field_types2)
then case check_diff (get_checkeds_of_usum_uval ctxt uval1) (get_checkeds_of_usum_uval ctxt uval2) of
(* Only if going from unchecked to checked *)
[(ix,(false,true))] => SOME ix
(* If multiple differences, or no differences, we don't need to worry about case *)
| _ => NONE
else NONE
end;
fun get_castable_uvals_from' _ _ (_:uval) [] = []
| get_castable_uvals_from' ctxt heap (from:uval) (to::tos) =
let val some_rmved_field_num = (from can_be_casted_to to) ctxt heap;
val some_pair = case some_rmved_field_num of
SOME ix => SOME (ix, to)
| NONE => NONE
in some_pair :: get_castable_uvals_from' ctxt heap from tos
end;
in
fun get_castable_uvals_from ctxt heap from tos =
get_castable_uvals_from' ctxt heap from (get_usums tos) |> get_somes
end;
\<close>
ML\<open> fun mk_case_prop from_uval to_uval variant_ctor_num file_nm ctxt =
(* field_num is the number of the field that is being tested for matching.*)
let
val struct_field_num = variant_ctor_num + 1
val _ = tracing (" started mk_case_prop for variant_ctor_num " ^ string_of_int variant_ctor_num)
val from_struct_C_nm = get_ty_nm_C from_uval;
val to_struct_C_nm = get_ty_nm_C to_uval;
val _ = tracing (" casting from " ^ from_struct_C_nm ^ " to " ^ to_struct_C_nm)
val heap = Symtab.lookup (HeapInfo.get (Proof_Context.theory_of ctxt)) file_nm
|> Utils.the' "heap in mk_case_prop failed."
|> #heap_info;
val get_struct_info = fn struct_C_nm => Symtab.lookup (heap |> #structs) struct_C_nm
|> Utils.the' "get_struct_info in mk_prop in Specialised_Lemma_USum.thy failed.";
val from_struct_info = get_struct_info from_struct_C_nm;
val to_struct_info = get_struct_info to_struct_C_nm;
val from_field_info = #field_info from_struct_info;
val nth_field_ml_tag_name = from_field_info |> (fn list => List.nth (list, struct_field_num)) |> #name
|> cut_C;
val nth_field_tag_name = nth_field_ml_tag_name |> Utils.encode_isa_string;
val get_tag_names = fn uval => heap_info_uval_to_field_names heap uval |> tl |> map (unsuffix "_C");
val from_tag_nms = get_tag_names from_uval;
val from_tag_checks = get_checkeds_of_usum_uval ctxt from_uval
val to_tag_checks = get_checkeds_of_usum_uval ctxt to_uval
val alternative_tys = map (fn n => Free ("alt_ty" ^ string_of_int n, @{typ "Cogent.type"}))
(1 upto length from_tag_nms)
val tag_ty_bits = from_tag_nms ~~ alternative_tys ~~ from_tag_checks
val to_tag_ty_bits = from_tag_nms ~~ alternative_tys ~~ to_tag_checks
fun mk_triple_tag ((a,b),c) = HOLogic.mk_prod (HOLogic.mk_string a, HOLogic.mk_prod (b, variant_state_of_bool c))
val from_sumT = @{term TSum} $ HOLogic.mk_list @{typ "(string \<times> Cogent.type \<times> variant_state)"}
(map mk_triple_tag tag_ty_bits)
val to_sumT = @{term TSum} $ HOLogic.mk_list @{typ "(string \<times> Cogent.type \<times> variant_state)"}
(map mk_triple_tag to_tag_ty_bits)
val taken_typ = List.nth (alternative_tys, variant_ctor_num)
val from_tag_C = from_field_info |> hd |> #getter; (* tag_C is always the first element of struct.*)
val corres = Syntax.read_term ctxt "corres";
(* Monadic C code in the conclusion.*)
val monadic_c =
let
val TAG_ENUM = Syntax.read_term ctxt ("TAG_ENUM_" ^ nth_field_ml_tag_name);
val match_tag_getter = List.nth (from_field_info, struct_field_num) |> #getter;
in
@{term "\<lambda> from_tag_C TAG_ENUM match_tag_getter.
(condition (\<lambda>_. from_tag_C x' = TAG_ENUM)
(match' (match_tag_getter x'))
(not_match' x'))"}
$ from_tag_C $ TAG_ENUM $ match_tag_getter
end;
fun mk_ass2 tag_list = @{mk_term "\<Gamma>' ! x = Some ?tag_list" tag_list} tag_list;
fun mk_ass6 tag_list = @{mk_term "\<Xi>', [], \<Gamma>1 \<turnstile> Var x : ?tag_list" tag_list} tag_list;
fun mk_ass9 other_tags = @{mk_term "\<Xi>', [], Some ?other_tags # \<Gamma>2 \<turnstile> not_match : t" other_tags} other_tags;
fun mk_ass11 other_tags =
@{mk_term "\<And>r. r = (\<gamma>!x) \<Longrightarrow> val_rel r x' \<Longrightarrow> ?corres srel not_match (not_match' x') \<xi>' (r # \<gamma>) \<Xi>'
(Some (?other_tags) # \<Gamma>2) \<sigma> s" (corres, other_tags)} (corres, other_tags);
val ass1 = @{term "x < length \<Gamma>'"};
val ass2 = mk_ass2 from_sumT;
val ass3 = @{term "[] \<turnstile> \<Gamma>' \<leadsto> \<Gamma>1 | \<Gamma>2"};
val ass4 = @{term "val_rel (\<gamma> ! x) x'"};
(* Ass 5 discharged by instantiating at concrete type *)
val ass6 = mk_ass6 from_sumT
(* Ass 7 discharged by instantiating at concrete type *)
val ass8 = @{term "\<lambda>taken_typ. \<Xi>', [], Some taken_typ # \<Gamma>2 \<turnstile> match : t"} $ taken_typ;
val ass9 = mk_ass9 to_sumT;
val ass10 = @{mk_term "\<And>a a'. val_rel a a' \<Longrightarrow>
?corres srel match (match' a') \<xi>' (a # \<gamma>) \<Xi>' (Some ?match_typ # \<Gamma>2) \<sigma> s"(corres, match_typ)}
(corres, taken_typ);
val ass11= mk_ass11 to_sumT;
val prms = map (HOLogic.mk_Trueprop o strip_atype)
[ass1, ass2, ass3, ass4, ass6, ass8, ass9] @ [ass10, ass11];
val cncl = @{mk_term
"?corres srel (Case (Var x) ?nth_field_tag_name match not_match) ?monadic_c \<xi>' \<gamma> \<Xi>' \<Gamma>' \<sigma> s"
(corres, nth_field_tag_name, monadic_c)} (corres, nth_field_tag_name, monadic_c)
|> HOLogic.mk_Trueprop;
in
mk_meta_imps prms cncl ctxt |> Syntax.check_term ctxt
end
\<close>
ML\<open> (* mk_case_lem_for_uval *)
local
fun mk_case_lem_name (from:uval) field_num ctxt =
let
val cs = get_checkeds_of_usum_uval ctxt from
val cs_str = cs |> map (fn b => if b then "C" else "U") |> String.concat
in
"corres_case_" ^ get_uval_name from ^ "_" ^ Int.toString field_num ^ "th_field_" ^ cs_str
end
fun mk_case_lem_from_to (from:uval) field_num (to:uval) file_nm ctxt =
{ name = mk_case_lem_name from field_num ctxt,
bucket = Case,
prop = mk_case_prop from to field_num file_nm ctxt,
mk_tactic = if true then (fn ctxt => corres_case_tac ctxt 1) else K (Skip_Proof.cheat_tac ctxt 1) };
fun mk_case_lems_from_tos from (num_tos : (int * uval) list) file_nm ctxt = map
(fn num_to => mk_case_lem_from_to from (fst num_to) (snd num_to) file_nm ctxt) num_tos
in
fun mk_case_lems_for_uval file_nm ctxt uvals from =
let
val heap_info = Symtab.lookup (HeapInfo.get (Proof_Context.theory_of ctxt)) file_nm
|> Utils.the' "the' in mk_specialised_case_lemmas_for_uval failed."
|> #heap_info;
val num_tos = get_castable_uvals_from ctxt heap_info from uvals;
val lems = mk_case_lems_from_tos from num_tos file_nm ctxt;
in
lems
end;
end;
\<close>
ML\<open> (* local_setup_specialised_esacs *)
local
fun specialise_esac_thm ctxt trm =
let
val cterm_of = Thm.cterm_of ctxt;
val corres_esac = Proof_Context.get_thm ctxt "corres_esac";
val vars = Term.add_vars (Thm.prop_of corres_esac) [];
(* get_val' is the 5th variable counting from 0.*)
val get_val' = List.nth (vars, 5);
val my_esac = Drule.infer_instantiate ctxt [(("get_val'", 0), cterm_of trm)] corres_esac (* TODO make sure 0 means what I think it means *)
in my_esac end;
fun mk_specialised_esac_lemma file_nm ctxt from_usum =
let
val from_C_nm = get_ty_nm_C from_usum;
val _ = tracing (" mk_specialised_esac_lemma for " ^ from_C_nm)
val thy = Proof_Context.theory_of ctxt;
val is_usum = get_usums [from_usum] |> null |> not;
val with_checks = map_index I (get_checkeds_of_usum_uval ctxt from_usum)
val uncheckeds = List.filter (fn (_,x) => not x) with_checks
in
case uncheckeds of
[(ix,_)] =>
let
fun get_struct_info (hinfo : HeapLiftBase.heap_info)
= Symtab.lookup (#structs hinfo) from_C_nm;
val some_hinfo = (Symtab.lookup (HeapInfo.get thy) file_nm) +> #heap_info;
val some_sinfo = some_hinfo ?> get_struct_info;
val some_finfo = some_sinfo +> #field_info;
fun get_ix_field list = List.nth (list, ix + 1);
val some_fst_getter = some_finfo +> get_ix_field +> #getter;
val _ = if is_usum
then tracing (" " ^ from_C_nm ^ " is for esac.")
else tracing (" " ^ from_C_nm ^ " is not for esac.");
val some_thm = if is_usum
then some_fst_getter +> specialise_esac_thm ctxt
else NONE
in some_thm end
| _ => (tracing (" " ^ from_C_nm ^ " is not for esac."); NONE)
end
in
fun local_setup_specialised_esacs file_nm lthy =
let
val _ = tracing "started local_setup_specialised_esacs"
val thy = Proof_Context.theory_of lthy;
val usums = read_table file_nm thy
|> get_usums
|> get_uvals_for_which_ac_mk_st_info file_nm thy;
fun mk_some_esac_lemma usum = mk_specialised_esac_lemma file_nm lthy usum;
val esac_thms = List.mapPartial mk_some_esac_lemma usums;
val lthy' = Local_Theory.notes [((Binding.name "corres_esacs", []), [(esac_thms, [])])] lthy |> snd
in lthy' end;
end;
\<close>
end
end