| author | wenzelm | 
| Fri, 23 Aug 2013 15:04:00 +0200 | |
| changeset 53166 | 1266b6208a5b | 
| parent 52705 | c12602c1b13b | 
| child 54398 | 100c0eaf63d5 | 
| permissions | -rw-r--r-- | 
| 52265 | 1 | (* Title: HOL/Tools/case_translation.ML | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 2 | Author: Konrad Slind, Cambridge University Computer Laboratory | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 3 | Author: Stefan Berghofer, TU Muenchen | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 4 | Author: Dmitriy Traytel, TU Muenchen | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 5 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 6 | Nested case expressions via a generic data slot for case combinators and constructors. | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 7 | *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 8 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 9 | signature CASE_TRANSLATION = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 10 | sig | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 11 | datatype config = Error | Warning | Quiet | 
| 51678 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 12 | val case_tr: bool -> Proof.context -> term list -> term | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 13 | val lookup_by_constr: Proof.context -> string * typ -> (term * term list) option | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 14 | val lookup_by_constr_permissive: Proof.context -> string * typ -> (term * term list) option | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 15 | val lookup_by_case: Proof.context -> string -> (term * term list) option | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 16 | val make_case: Proof.context -> config -> Name.context -> term -> (term * term) list -> term | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 17 | val print_case_translations: Proof.context -> unit | 
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 18 | val strip_case: Proof.context -> bool -> term -> (term * (term * term) list) option | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 19 | val strip_case_full: Proof.context -> bool -> term -> term | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 20 | val show_cases: bool Config.T | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 21 | val setup: theory -> theory | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 22 | val register: term -> term list -> Context.generic -> Context.generic | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 23 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 24 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 25 | structure Case_Translation: CASE_TRANSLATION = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 26 | struct | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 27 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 28 | (** data management **) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 29 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 30 | datatype data = Data of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 31 |   {constrs: (string * (term * term list)) list Symtab.table,
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 32 | cases: (term * term list) Symtab.table}; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 33 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 34 | fun make_data (constrs, cases) = Data {constrs = constrs, cases = cases};
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 35 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 36 | structure Data = Generic_Data | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 37 | ( | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 38 | type T = data; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 39 | val empty = make_data (Symtab.empty, Symtab.empty); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 40 | val extend = I; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 41 | fun merge | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 42 |     (Data {constrs = constrs1, cases = cases1},
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 43 |      Data {constrs = constrs2, cases = cases2}) =
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 44 | make_data | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 45 | (Symtab.join (K (AList.merge (op =) (K true))) (constrs1, constrs2), | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 46 | Symtab.merge (K true) (cases1, cases2)); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 47 | ); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 48 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 49 | fun map_data f = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 50 |   Data.map (fn Data {constrs, cases} => make_data (f (constrs, cases)));
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 51 | fun map_constrs f = map_data (fn (constrs, cases) => (f constrs, cases)); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 52 | fun map_cases f = map_data (fn (constrs, cases) => (constrs, f cases)); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 53 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 54 | val rep_data = (fn Data args => args) o Data.get o Context.Proof; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 55 | |
| 51684 | 56 | fun T_of_data (comb, constrs : term list) = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 57 | fastype_of comb | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 58 | |> funpow (length constrs) range_type | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 59 | |> domain_type; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 60 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 61 | val Tname_of_data = fst o dest_Type o T_of_data; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 62 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 63 | val constrs_of = #constrs o rep_data; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 64 | val cases_of = #cases o rep_data; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 65 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 66 | fun lookup_by_constr ctxt (c, T) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 67 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 68 | val tab = Symtab.lookup_list (constrs_of ctxt) c; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 69 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 70 | (case body_type T of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 71 | Type (tyco, _) => AList.lookup (op =) tab tyco | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 72 | | _ => NONE) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 73 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 74 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 75 | fun lookup_by_constr_permissive ctxt (c, T) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 76 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 77 | val tab = Symtab.lookup_list (constrs_of ctxt) c; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 78 | val hint = (case body_type T of Type (tyco, _) => SOME tyco | _ => NONE); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 79 | val default = if null tab then NONE else SOME (snd (List.last tab)); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 80 | (*conservative wrt. overloaded constructors*) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 81 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 82 | (case hint of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 83 | NONE => default | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 84 | | SOME tyco => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 85 | (case AList.lookup (op =) tab tyco of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 86 | NONE => default (*permissive*) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 87 | | SOME info => SOME info)) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 88 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 89 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 90 | val lookup_by_case = Symtab.lookup o cases_of; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 91 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 92 | |
| 52154 | 93 | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 94 | (** installation **) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 95 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 96 | fun case_error s = error ("Error in case expression:\n" ^ s);
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 97 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 98 | val name_of = try (dest_Const #> fst); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 99 | |
| 52154 | 100 | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 101 | (* parse translation *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 102 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 103 | fun constrain_Abs tT t = Syntax.const @{syntax_const "_constrainAbs"} $ t $ tT;
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 104 | |
| 51678 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 105 | fun case_tr err ctxt [t, u] = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 106 | let | 
| 52157 | 107 | val consts = Proof_Context.consts_of ctxt; | 
| 108 | fun is_const s = can (Consts.the_constraint consts) (Consts.intern consts s); | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 109 | |
| 52158 
d5fa81343322
more robust variant_free: avoid clash with consts name space (e.g. consts "x", "xa", etc.);
 wenzelm parents: 
52157diff
changeset | 110 | fun variant_free x used = | 
| 
d5fa81343322
more robust variant_free: avoid clash with consts name space (e.g. consts "x", "xa", etc.);
 wenzelm parents: 
52157diff
changeset | 111 | let val (x', used') = Name.variant x used | 
| 
d5fa81343322
more robust variant_free: avoid clash with consts name space (e.g. consts "x", "xa", etc.);
 wenzelm parents: 
52157diff
changeset | 112 | in if is_const x' then variant_free x' used' else (x', used') end; | 
| 
d5fa81343322
more robust variant_free: avoid clash with consts name space (e.g. consts "x", "xa", etc.);
 wenzelm parents: 
52157diff
changeset | 113 | |
| 52157 | 114 | fun abs p tTs t = | 
| 115 |           Syntax.const @{const_syntax case_abs} $
 | |
| 116 | fold constrain_Abs tTs (absfree p t); | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 117 | |
| 51693 | 118 |         fun abs_pat (Const (@{syntax_const "_constrain"}, _) $ t $ tT) tTs =
 | 
| 119 | abs_pat t (tT :: tTs) | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 120 | | abs_pat (Free (p as (x, _))) tTs = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 121 | if is_const x then I else abs p tTs | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 122 | | abs_pat (t $ u) _ = abs_pat u [] #> abs_pat t [] | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 123 | | abs_pat _ _ = I; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 124 | |
| 51680 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 125 | (* replace occurrences of dummy_pattern by distinct variables *) | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 126 |         fun replace_dummies (Const (@{const_syntax dummy_pattern}, T)) used =
 | 
| 52158 
d5fa81343322
more robust variant_free: avoid clash with consts name space (e.g. consts "x", "xa", etc.);
 wenzelm parents: 
52157diff
changeset | 127 | let val (x, used') = variant_free "x" used | 
| 51680 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 128 | in (Free (x, T), used') end | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 129 | | replace_dummies (t $ u) used = | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 130 | let | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 131 | val (t', used') = replace_dummies t used; | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 132 | val (u', used'') = replace_dummies u used'; | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 133 | in (t' $ u', used'') end | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 134 | | replace_dummies t used = (t, used); | 
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 135 | |
| 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 136 |         fun dest_case1 (t as Const (@{syntax_const "_case1"}, _) $ l $ r) =
 | 
| 52154 | 137 | let val (l', _) = replace_dummies l (Term.declare_term_frees t Name.context) in | 
| 138 | abs_pat l' [] | |
| 139 |                   (Syntax.const @{const_syntax case_elem} $ Term_Position.strip_positions l' $ r)
 | |
| 51680 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 140 | end | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 141 | | dest_case1 _ = case_error "dest_case1"; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 142 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 143 |         fun dest_case2 (Const (@{syntax_const "_case2"}, _) $ t $ u) = t :: dest_case2 u
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 144 | | dest_case2 t = [t]; | 
| 51678 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 145 | |
| 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 146 |         val errt = if err then @{term True} else @{term False};
 | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 147 | in | 
| 52154 | 148 |         Syntax.const @{const_syntax case_guard} $ errt $ t $
 | 
| 149 | (fold_rev | |
| 150 |             (fn t => fn u => Syntax.const @{const_syntax case_cons} $ dest_case1 t $ u)
 | |
| 151 | (dest_case2 u) | |
| 152 |             (Syntax.const @{const_syntax case_nil}))
 | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 153 | end | 
| 51678 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 154 | | case_tr _ _ _ = case_error "case_tr"; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 155 | |
| 52143 | 156 | val trfun_setup = Sign.parse_translation [(@{syntax_const "_case_syntax"}, case_tr true)];
 | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 157 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 158 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 159 | (* print translation *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 160 | |
| 51751 
cf039b3c42a7
slightly more aggressive syntax translation for printing case expressions
 traytel parents: 
51693diff
changeset | 161 | fun case_tr' (_ :: x :: t :: ts) = | 
| 52159 | 162 | let | 
| 163 |         fun mk_clause (Const (@{const_syntax case_abs}, _) $ Abs (s, T, t)) xs used =
 | |
| 164 | let val (s', used') = Name.variant s used | |
| 165 | in mk_clause t ((s', T) :: xs) used' end | |
| 166 |           | mk_clause (Const (@{const_syntax case_elem}, _) $ pat $ rhs) xs _ =
 | |
| 167 |               Syntax.const @{syntax_const "_case1"} $
 | |
| 168 | subst_bounds (map Syntax_Trans.mark_bound_abs xs, pat) $ | |
| 169 | subst_bounds (map Syntax_Trans.mark_bound_body xs, rhs) | |
| 170 | | mk_clause _ _ _ = raise Match; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 171 | |
| 52159 | 172 |         fun mk_clauses (Const (@{const_syntax case_nil}, _)) = []
 | 
| 173 |           | mk_clauses (Const (@{const_syntax case_cons}, _) $ t $ u) =
 | |
| 174 | mk_clause t [] (Term.declare_term_frees t Name.context) :: mk_clauses u | |
| 175 | | mk_clauses _ = raise Match; | |
| 176 | in | |
| 177 |         list_comb (Syntax.const @{syntax_const "_case_syntax"} $ x $
 | |
| 178 |           foldr1 (fn (t, u) => Syntax.const @{syntax_const "_case2"} $ t $ u)
 | |
| 179 | (mk_clauses t), ts) | |
| 180 | end | |
| 181 | | case_tr' _ = raise Match; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 182 | |
| 52143 | 183 | val trfun_setup' = Sign.print_translation [(@{const_syntax "case_guard"}, K case_tr')];
 | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 184 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 185 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 186 | (* declarations *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 187 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 188 | fun register raw_case_comb raw_constrs context = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 189 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 190 | val ctxt = Context.proof_of context; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 191 | val case_comb = singleton (Variable.polymorphic ctxt) raw_case_comb; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 192 | val constrs = Variable.polymorphic ctxt raw_constrs; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 193 | val case_key = case_comb |> dest_Const |> fst; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 194 | val constr_keys = map (fst o dest_Const) constrs; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 195 | val data = (case_comb, constrs); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 196 | val Tname = Tname_of_data data; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 197 | val update_constrs = fold (fn key => Symtab.cons_list (key, (Tname, data))) constr_keys; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 198 | val update_cases = Symtab.update (case_key, data); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 199 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 200 | context | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 201 | |> map_constrs update_constrs | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 202 | |> map_cases update_cases | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 203 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 204 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 205 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 206 | (* (Un)check phases *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 207 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 208 | datatype config = Error | Warning | Quiet; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 209 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 210 | exception CASE_ERROR of string * int; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 211 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 212 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 213 | (*Each pattern carries with it a tag i, which denotes the clause it | 
| 52154 | 214 | came from. i = ~1 indicates that the clause was added by pattern | 
| 215 | completion.*) | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 216 | |
| 52159 | 217 | fun add_row_used ((prfx, pats), (tm, _)) = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 218 | fold Term.declare_term_frees (tm :: pats @ map Free prfx); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 219 | |
| 52154 | 220 | (*try to preserve names given by user*) | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 221 | fun default_name "" (Free (name', _)) = name' | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 222 | | default_name name _ = name; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 223 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 224 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 225 | (*Produce an instance of a constructor, plus fresh variables for its arguments.*) | 
| 51675 | 226 | fun fresh_constr colty used c = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 227 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 228 | val (_, T) = dest_Const c; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 229 | val Ts = binder_types T; | 
| 52154 | 230 | val (names, _) = | 
| 231 | fold_map Name.variant | |
| 232 | (Datatype_Prop.make_tnames (map Logic.unvarifyT_global Ts)) used; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 233 | val ty = body_type T; | 
| 51675 | 234 | val ty_theta = Type.raw_match (ty, colty) Vartab.empty | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 235 |       handle Type.TYPE_MATCH => raise CASE_ERROR ("type mismatch", ~1);
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 236 | val c' = Envir.subst_term_types ty_theta c; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 237 | val gvars = map (Envir.subst_term_types ty_theta o Free) (names ~~ Ts); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 238 | in (c', gvars) end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 239 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 240 | (*Go through a list of rows and pick out the ones beginning with a | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 241 | pattern with constructor = name.*) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 242 | fun mk_group (name, T) rows = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 243 | let val k = length (binder_types T) in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 244 | fold (fn (row as ((prfx, p :: ps), rhs as (_, i))) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 245 | fn ((in_group, not_in_group), names) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 246 | (case strip_comb p of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 247 | (Const (name', _), args) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 248 | if name = name' then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 249 | if length args = k then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 250 | ((((prfx, args @ ps), rhs) :: in_group, not_in_group), | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 251 | map2 default_name names args) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 252 |               else raise CASE_ERROR ("Wrong number of arguments for constructor " ^ quote name, i)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 253 | else ((in_group, row :: not_in_group), names) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 254 |         | _ => raise CASE_ERROR ("Not a constructor pattern", i)))
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 255 | rows (([], []), replicate k "") |>> pairself rev | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 256 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 257 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 258 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 259 | (* Partitioning *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 260 | |
| 51675 | 261 | fun partition _ _ _ _ [] = raise CASE_ERROR ("partition: no rows", ~1)
 | 
| 52154 | 262 | | partition used constructors colty res_ty (rows as (((prfx, _ :: ps), _) :: _)) = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 263 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 264 | fun part [] [] = [] | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 265 |           | part [] ((_, (_, i)) :: _) = raise CASE_ERROR ("Not a constructor pattern", i)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 266 | | part (c :: cs) rows = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 267 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 268 | val ((in_group, not_in_group), names) = mk_group (dest_Const c) rows; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 269 | val used' = fold add_row_used in_group used; | 
| 51675 | 270 | val (c', gvars) = fresh_constr colty used' c; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 271 | val in_group' = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 272 | if null in_group (* Constructor not given *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 273 | then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 274 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 275 | val Ts = map fastype_of ps; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 276 | val (xs, _) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 277 | fold_map Name.variant | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 278 | (replicate (length ps) "x") | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 279 | (fold Term.declare_term_frees gvars used'); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 280 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 281 | [((prfx, gvars @ map Free (xs ~~ Ts)), | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 282 |                         (Const (@{const_name undefined}, res_ty), ~1))]
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 283 | end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 284 | else in_group; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 285 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 286 |                 {constructor = c',
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 287 | new_formals = gvars, | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 288 | names = names, | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 289 | group = in_group'} :: part cs not_in_group | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 290 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 291 | in part constructors rows end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 292 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 293 | fun v_to_prfx (prfx, Free v :: pats) = (v :: prfx, pats) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 294 |   | v_to_prfx _ = raise CASE_ERROR ("mk_case: v_to_prfx", ~1);
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 295 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 296 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 297 | (* Translation of pattern terms into nested case expressions. *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 298 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 299 | fun mk_case ctxt used range_ty = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 300 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 301 | val get_info = lookup_by_constr_permissive ctxt; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 302 | |
| 52159 | 303 |     fun expand _ _ _ ((_, []), _) = raise CASE_ERROR ("mk_case: expand", ~1)
 | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 304 | | expand constructors used ty (row as ((prfx, p :: ps), (rhs, tag))) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 305 | if is_Free p then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 306 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 307 | val used' = add_row_used row used; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 308 | fun expnd c = | 
| 51675 | 309 | let val capp = list_comb (fresh_constr ty used' c) | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 310 | in ((prfx, capp :: ps), (subst_free [(p, capp)] rhs, tag)) end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 311 | in map expnd constructors end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 312 | else [row]; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 313 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 314 | val (name, _) = Name.variant "a" used; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 315 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 316 |     fun mk _ [] = raise CASE_ERROR ("no rows", ~1)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 317 | | mk [] (((_, []), (tm, tag)) :: _) = ([tag], tm) (* Done *) | 
| 52159 | 318 | | mk path ((row as ((_, [Free _]), _)) :: _ :: _) = mk path [row] | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 319 | | mk (u :: us) (rows as ((_, _ :: _), _) :: _) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 320 | let val col0 = map (fn ((_, p :: _), (_, i)) => (p, i)) rows in | 
| 52154 | 321 | (case Option.map (apfst head_of) (find_first (not o is_Free o fst) col0) of | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 322 | NONE => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 323 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 324 | val rows' = map (fn ((v, _), row) => row ||> | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 325 | apfst (subst_free [(v, u)]) |>> v_to_prfx) (col0 ~~ rows); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 326 | in mk us rows' end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 327 | | SOME (Const (cname, cT), i) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 328 | (case get_info (cname, cT) of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 329 |                   NONE => raise CASE_ERROR ("Not a datatype constructor: " ^ quote cname, i)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 330 | | SOME (case_comb, constructors) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 331 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 332 | val pty = body_type cT; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 333 | val used' = fold Term.declare_term_frees us used; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 334 | val nrows = maps (expand constructors used' pty) rows; | 
| 52154 | 335 | val subproblems = partition used' constructors pty range_ty nrows; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 336 | val (pat_rect, dtrees) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 337 |                         split_list (map (fn {new_formals, group, ...} =>
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 338 | mk (new_formals @ us) group) subproblems); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 339 | val case_functions = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 340 |                         map2 (fn {new_formals, names, ...} =>
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 341 | fold_rev (fn (x as Free (_, T), s) => fn t => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 342 | Abs (if s = "" then name else s, T, abstract_over (x, t))) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 343 | (new_formals ~~ names)) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 344 | subproblems dtrees; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 345 | val types = map fastype_of (case_functions @ [u]); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 346 | val case_const = Const (name_of case_comb |> the, types ---> range_ty); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 347 | val tree = list_comb (case_const, case_functions @ [u]); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 348 | in (flat pat_rect, tree) end) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 349 | | SOME (t, i) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 350 |                 raise CASE_ERROR ("Not a datatype constructor: " ^ Syntax.string_of_term ctxt t, i))
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 351 | end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 352 |       | mk _ _ = raise CASE_ERROR ("Malformed row matrix", ~1)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 353 | in mk end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 354 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 355 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 356 | (*Repeated variable occurrences in a pattern are not allowed.*) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 357 | fun no_repeat_vars ctxt pat = fold_aterms | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 358 | (fn x as Free (s, _) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 359 | (fn xs => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 360 | if member op aconv xs x then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 361 | case_error (quote s ^ " occurs repeatedly in the pattern " ^ | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 362 | quote (Syntax.string_of_term ctxt pat)) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 363 | else x :: xs) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 364 | | _ => I) pat []; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 365 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 366 | fun make_case ctxt config used x clauses = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 367 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 368 | fun string_of_clause (pat, rhs) = | 
| 52705 
c12602c1b13b
do not apply string_of_term to dummy-typed syntactic constants (ensures that uncheck phases work on well-typed terms)
 traytel parents: 
52690diff
changeset | 369 | Syntax.unparse_term ctxt | 
| 
c12602c1b13b
do not apply string_of_term to dummy-typed syntactic constants (ensures that uncheck phases work on well-typed terms)
 traytel parents: 
52690diff
changeset | 370 |         (Term.list_comb (Syntax.const @{syntax_const "_case1"},
 | 
| 
c12602c1b13b
do not apply string_of_term to dummy-typed syntactic constants (ensures that uncheck phases work on well-typed terms)
 traytel parents: 
52690diff
changeset | 371 | Syntax.uncheck_terms ctxt [pat, rhs])) | 
| 
c12602c1b13b
do not apply string_of_term to dummy-typed syntactic constants (ensures that uncheck phases work on well-typed terms)
 traytel parents: 
52690diff
changeset | 372 | |> Pretty.string_of; | 
| 52690 
2fa3110539a5
more opportunistic string_of_clause, to make double-sure its Syntax.string_of_term uncheck phase does not crash, and thus bomb ambiguous input via failed composition of warning (e.g. HOL/Imperative_HOL/ex/Linked_List.thy: lemma merge_simps);
 wenzelm parents: 
52685diff
changeset | 373 | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 374 | val _ = map (no_repeat_vars ctxt o fst) clauses; | 
| 51680 
8b8cd5a527bc
Handle dummy patterns in parse translation rather than check phase
 berghofe parents: 
51679diff
changeset | 375 | val rows = map_index (fn (i, (pat, rhs)) => (([], [pat]), (rhs, i))) clauses; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 376 | val rangeT = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 377 | (case distinct (op =) (map (fastype_of o snd) clauses) of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 378 | [] => case_error "no clauses given" | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 379 | | [T] => T | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 380 | | _ => case_error "all cases must have the same result type"); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 381 | val used' = fold add_row_used rows used; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 382 | val (tags, case_tm) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 383 | mk_case ctxt used' rangeT [x] rows | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 384 | handle CASE_ERROR (msg, i) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 385 | case_error | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 386 | (msg ^ (if i < 0 then "" else "\nIn clause\n" ^ string_of_clause (nth clauses i))); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 387 | val _ = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 388 | (case subtract (op =) tags (map (snd o snd) rows) of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 389 | [] => () | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 390 | | is => | 
| 52685 
554d684d8520
non-strict "Quiet" mode, to avoid odd crash of code_pred/after_qed due to ill-typed use of string_of_clause (e.g. in JinjaThreads/Common/Decl.thy of AFP/d1bb08f92ce5);
 wenzelm parents: 
52285diff
changeset | 391 | if config = Quiet then () | 
| 
554d684d8520
non-strict "Quiet" mode, to avoid odd crash of code_pred/after_qed due to ill-typed use of string_of_clause (e.g. in JinjaThreads/Common/Decl.thy of AFP/d1bb08f92ce5);
 wenzelm parents: 
52285diff
changeset | 392 | else | 
| 52690 
2fa3110539a5
more opportunistic string_of_clause, to make double-sure its Syntax.string_of_term uncheck phase does not crash, and thus bomb ambiguous input via failed composition of warning (e.g. HOL/Imperative_HOL/ex/Linked_List.thy: lemma merge_simps);
 wenzelm parents: 
52685diff
changeset | 393 | (if config = Error then case_error else warning (*FIXME lack of syntactic context!?*)) | 
| 52685 
554d684d8520
non-strict "Quiet" mode, to avoid odd crash of code_pred/after_qed due to ill-typed use of string_of_clause (e.g. in JinjaThreads/Common/Decl.thy of AFP/d1bb08f92ce5);
 wenzelm parents: 
52285diff
changeset | 394 |               ("The following clauses are redundant (covered by preceding clauses):\n" ^
 | 
| 
554d684d8520
non-strict "Quiet" mode, to avoid odd crash of code_pred/after_qed due to ill-typed use of string_of_clause (e.g. in JinjaThreads/Common/Decl.thy of AFP/d1bb08f92ce5);
 wenzelm parents: 
52285diff
changeset | 395 | cat_lines (map (string_of_clause o nth clauses) is))); | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 396 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 397 | case_tm | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 398 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 399 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 400 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 401 | (* term check *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 402 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 403 | fun decode_clause (Const (@{const_name case_abs}, _) $ Abs (s, T, t)) xs used =
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 404 | let val (s', used') = Name.variant s used | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 405 | in decode_clause t (Free (s', T) :: xs) used' end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 406 |   | decode_clause (Const (@{const_name case_elem}, _) $ t $ u) xs _ =
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 407 | (subst_bounds (xs, t), subst_bounds (xs, u)) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 408 | | decode_clause _ _ _ = case_error "decode_clause"; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 409 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 410 | fun decode_cases (Const (@{const_name case_nil}, _)) = []
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 411 |   | decode_cases (Const (@{const_name case_cons}, _) $ t $ u) =
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 412 | decode_clause t [] (Term.declare_term_frees t Name.context) :: | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 413 | decode_cases u | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 414 | | decode_cases _ = case_error "decode_cases"; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 415 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 416 | fun check_case ctxt = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 417 | let | 
| 51679 
e7316560928b
disallow coercions to interfere with case translations
 traytel parents: 
51678diff
changeset | 418 |     fun decode_case (Const (@{const_name case_guard}, _) $ b $ u $ t) =
 | 
| 51678 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 419 |           make_case ctxt (if b = @{term True} then Error else Warning)
 | 
| 
1e33b81c328a
allow redundant cases in the list comprehension translation
 traytel parents: 
51677diff
changeset | 420 | Name.context (decode_case u) (decode_cases t) | 
| 51676 | 421 | | decode_case (t $ u) = decode_case t $ decode_case u | 
| 422 | | decode_case (Abs (x, T, u)) = | |
| 423 | let val (x', u') = Term.dest_abs (x, T, u); | |
| 424 | in Term.absfree (x', T) (decode_case u') end | |
| 425 | | decode_case t = t; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 426 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 427 | map decode_case | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 428 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 429 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 430 | val term_check_setup = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 431 | Context.theory_map (Syntax_Phases.term_check 1 "case" check_case); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 432 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 433 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 434 | (* Pretty printing of nested case expressions *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 435 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 436 | (* destruct one level of pattern matching *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 437 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 438 | fun dest_case ctxt d used t = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 439 | (case apfst name_of (strip_comb t) of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 440 | (SOME cname, ts as _ :: _) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 441 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 442 | val (fs, x) = split_last ts; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 443 | fun strip_abs i Us t = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 444 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 445 | val zs = strip_abs_vars t; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 446 | val j = length zs; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 447 | val (xs, ys) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 448 | if j < i then (zs @ map (pair "x") (drop j Us), []) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 449 | else chop i zs; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 450 | val u = fold_rev Term.abs ys (strip_abs_body t); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 451 | val xs' = map Free | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 452 | ((fold_map Name.variant (map fst xs) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 453 | (Term.declare_term_names u used) |> fst) ~~ | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 454 | map snd xs); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 455 | val (xs1, xs2) = chop j xs' | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 456 | in (xs', list_comb (subst_bounds (rev xs1, u), xs2)) end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 457 | fun is_dependent i t = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 458 | let val k = length (strip_abs_vars t) - i | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 459 | in k < 0 orelse exists (fn j => j >= k) (loose_bnos (strip_abs_body t)) end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 460 | fun count_cases (_, _, true) = I | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 461 | | count_cases (c, (_, body), false) = AList.map_default op aconv (body, []) (cons c); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 462 |         val is_undefined = name_of #> equal (SOME @{const_name undefined});
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 463 | fun mk_case (c, (xs, body), _) = (list_comb (c, xs), body); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 464 | val get_info = lookup_by_case ctxt; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 465 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 466 | (case get_info cname of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 467 | SOME (_, constructors) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 468 | if length fs = length constructors then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 469 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 470 | val cases = map (fn (Const (s, U), t) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 471 | let | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 472 | val Us = binder_types U; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 473 | val k = length Us; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 474 | val p as (xs, _) = strip_abs k Us t; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 475 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 476 | (Const (s, map fastype_of xs ---> fastype_of x), p, is_dependent k t) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 477 | end) (constructors ~~ fs); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 478 | val cases' = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 479 | sort (int_ord o swap o pairself (length o snd)) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 480 | (fold_rev count_cases cases []); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 481 | val R = fastype_of t; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 482 | val dummy = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 483 | if d then Term.dummy_pattern R | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 484 | else Free (Name.variant "x" used |> fst, R); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 485 | in | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 486 | SOME (x, | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 487 | map mk_case | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 488 | (case find_first (is_undefined o fst) cases' of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 489 | SOME (_, cs) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 490 | if length cs = length constructors then [hd cases] | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 491 | else filter_out (fn (_, (_, body), _) => is_undefined body) cases | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 492 | | NONE => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 493 | (case cases' of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 494 | [] => cases | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 495 | | (default, cs) :: _ => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 496 | if length cs = 1 then cases | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 497 | else if length cs = length constructors then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 498 | [hd cases, (dummy, ([], default), false)] | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 499 | else | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 500 | filter_out (fn (c, _, _) => member op aconv cs c) cases @ | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 501 | [(dummy, ([], default), false)]))) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 502 | end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 503 | else NONE | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 504 | | _ => NONE) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 505 | end | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 506 | | _ => NONE); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 507 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 508 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 509 | (* destruct nested patterns *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 510 | |
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 511 | fun encode_clause recur S T (pat, rhs) = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 512 | fold (fn x as (_, U) => fn t => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 513 |     Const (@{const_name case_abs}, (U --> T) --> T) $ Term.absfree x t)
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 514 | (Term.add_frees pat []) | 
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 515 |       (Const (@{const_name case_elem}, S --> T --> S --> T) $ pat $ recur rhs);
 | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 516 | |
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 517 | fun encode_cases _ S T [] = Const (@{const_name case_nil}, S --> T)
 | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 518 | | encode_cases recur S T (p :: ps) = | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 519 |       Const (@{const_name case_cons}, (S --> T) --> (S --> T) --> S --> T) $
 | 
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 520 | encode_clause recur S T p $ encode_cases recur S T ps; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 521 | |
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 522 | fun encode_case recur (t, ps as (pat, rhs) :: _) = | 
| 52154 | 523 | let | 
| 524 | val tT = fastype_of t; | |
| 525 | val T = fastype_of rhs; | |
| 526 | in | |
| 527 |         Const (@{const_name case_guard}, @{typ bool} --> tT --> (tT --> T) --> T) $
 | |
| 528 |           @{term True} $ t $ (encode_cases recur (fastype_of pat) (fastype_of rhs) ps)
 | |
| 529 | end | |
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 530 | | encode_case _ _ = case_error "encode_case"; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 531 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 532 | fun strip_case' ctxt d (pat, rhs) = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 533 | (case dest_case ctxt d (Term.declare_term_frees pat Name.context) rhs of | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 534 | SOME (exp as Free _, clauses) => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 535 | if Term.exists_subterm (curry (op aconv) exp) pat andalso | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 536 | not (exists (fn (_, rhs') => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 537 | Term.exists_subterm (curry (op aconv) exp) rhs') clauses) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 538 | then | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 539 | maps (strip_case' ctxt d) (map (fn (pat', rhs') => | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 540 | (subst_free [(exp, pat')] pat, rhs')) clauses) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 541 | else [(pat, rhs)] | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 542 | | _ => [(pat, rhs)]); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 543 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 544 | fun strip_case ctxt d t = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 545 | (case dest_case ctxt d Name.context t of | 
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 546 | SOME (x, clauses) => SOME (x, maps (strip_case' ctxt d) clauses) | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 547 | | NONE => NONE); | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 548 | |
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 549 | fun strip_case_full ctxt d t = | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 550 | (case dest_case ctxt d Name.context t of | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 551 | SOME (x, clauses) => | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 552 | encode_case (strip_case_full ctxt d) | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 553 | (strip_case_full ctxt d x, maps (strip_case' ctxt d) clauses) | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 554 | | NONE => | 
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 555 | (case t of | 
| 52154 | 556 | t $ u => strip_case_full ctxt d t $ strip_case_full ctxt d u | 
| 557 | | Abs (x, T, u) => | |
| 51677 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 558 | let val (x', u') = Term.dest_abs (x, T, u); | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 559 | in Term.absfree (x', T) (strip_case_full ctxt d u') end | 
| 
d2b3372e6033
recur in the expression to be matched (do not rely on repetitive execution of a check phase);
 traytel parents: 
51676diff
changeset | 560 | | _ => t)); | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 561 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 562 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 563 | (* term uncheck *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 564 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 565 | val show_cases = Attrib.setup_config_bool @{binding show_cases} (K true);
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 566 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 567 | fun uncheck_case ctxt ts = | 
| 52285 
da42b500a6aa
permissive uncheck -- allow printing of malformed terms (e.g. in error messages);
 wenzelm parents: 
52265diff
changeset | 568 | if Config.get ctxt show_cases | 
| 
da42b500a6aa
permissive uncheck -- allow printing of malformed terms (e.g. in error messages);
 wenzelm parents: 
52265diff
changeset | 569 | then map (fn t => if can Term.type_of t then strip_case_full ctxt true t else t) ts | 
| 
da42b500a6aa
permissive uncheck -- allow printing of malformed terms (e.g. in error messages);
 wenzelm parents: 
52265diff
changeset | 570 | else ts; | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 571 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 572 | val term_uncheck_setup = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 573 | Context.theory_map (Syntax_Phases.term_uncheck 1 "case" uncheck_case); | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 574 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 575 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 576 | (* theory setup *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 577 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 578 | val setup = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 579 | trfun_setup #> | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 580 | trfun_setup' #> | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 581 | term_check_setup #> | 
| 51681 | 582 | term_uncheck_setup #> | 
| 583 |   Attrib.setup @{binding case_translation}
 | |
| 584 | (Args.term -- Scan.repeat1 Args.term >> | |
| 585 | (fn (t, ts) => Thm.declaration_attribute (K (register t ts)))) | |
| 586 | "declaration of case combinators and constructors"; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 587 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 588 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 589 | (* outer syntax commands *) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 590 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 591 | fun print_case_translations ctxt = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 592 | let | 
| 52155 | 593 | val cases = map snd (Symtab.dest (cases_of ctxt)); | 
| 594 | val type_space = Proof_Context.type_space ctxt; | |
| 595 | ||
| 596 | val pretty_term = Syntax.pretty_term ctxt; | |
| 597 | ||
| 598 | fun pretty_data (data as (comb, ctrs)) = | |
| 599 | let | |
| 600 | val name = Tname_of_data data; | |
| 601 | val xname = Name_Space.extern ctxt type_space name; | |
| 602 | val markup = Name_Space.markup type_space name; | |
| 603 | val prt = | |
| 604 | (Pretty.block o Pretty.fbreaks) | |
| 605 | [Pretty.block [Pretty.mark_str (markup, xname), Pretty.str ":"], | |
| 606 | Pretty.block [Pretty.str "combinator:", Pretty.brk 1, pretty_term comb], | |
| 607 | Pretty.block (Pretty.str "constructors:" :: Pretty.brk 1 :: | |
| 608 | Pretty.commas (map pretty_term ctrs))]; | |
| 609 | in (xname, prt) end; | |
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 610 | in | 
| 52155 | 611 | Pretty.big_list "case translations:" (map #2 (sort_wrt #1 (map pretty_data cases))) | 
| 51673 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 612 | |> Pretty.writeln | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 613 | end; | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 614 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 615 | val _ = | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 616 |   Outer_Syntax.improper_command @{command_spec "print_case_translations"}
 | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 617 | "print registered case combinators and constructors" | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 618 | (Scan.succeed (Toplevel.keep (print_case_translations o Toplevel.context_of))) | 
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 619 | |
| 
4dfa00e264d8
separate data used for case translation from the datatype package
 traytel parents: diff
changeset | 620 | end; |