src/HOL/Tools/case_translation.ML
author traytel
Fri, 05 Apr 2013 22:08:42 +0200
changeset 51674 2b1498a2ce85
parent 51673 4dfa00e264d8
child 51675 18bbc78888aa
permissions -rw-r--r--
special constant to prevent eta-contraction of the check-phase syntax of case translations
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
     1
(*  Title:      Tools/case_translation.ML
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
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    12
  val case_tr: Proof.context -> term list -> term
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
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    18
  val strip_case: Proof.context -> bool -> term -> term
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    19
  val show_cases: bool Config.T
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    20
  val setup: theory -> theory
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    21
  val register: term -> term list -> Context.generic -> Context.generic
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    22
end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    23
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    24
structure Case_Translation: CASE_TRANSLATION =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    25
struct
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    26
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    27
(** data management **)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    28
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    29
datatype data = Data of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    30
  {constrs: (string * (term * term list)) list Symtab.table,
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    31
   cases: (term * term list) Symtab.table};
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    32
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    33
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
    34
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    35
structure Data = Generic_Data
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    36
(
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    37
  type T = data;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    38
  val empty = make_data (Symtab.empty, Symtab.empty);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    39
  val extend = I;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    40
  fun merge
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    41
    (Data {constrs = constrs1, cases = cases1},
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    42
     Data {constrs = constrs2, cases = cases2}) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    43
    make_data
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    44
      (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
    45
      Symtab.merge (K true) (cases1, cases2));
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    46
);
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
fun map_data f =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    49
  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
    50
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
    51
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
    52
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    53
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
    54
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    55
fun T_of_data (comb, constrs) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    56
  fastype_of comb
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    57
  |> funpow (length constrs) range_type
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    58
  |> domain_type;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    59
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    60
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
    61
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    62
val constrs_of = #constrs o rep_data;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    63
val cases_of = #cases o rep_data;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    64
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    65
fun lookup_by_constr ctxt (c, T) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    66
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    67
    val tab = Symtab.lookup_list (constrs_of ctxt) c;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    68
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    69
    (case body_type T of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    70
      Type (tyco, _) => AList.lookup (op =) tab tyco
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    71
    | _ => NONE)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    72
  end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    73
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    74
fun lookup_by_constr_permissive ctxt (c, T) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    75
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    76
    val tab = Symtab.lookup_list (constrs_of ctxt) c;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    77
    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
    78
    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
    79
    (*conservative wrt. overloaded constructors*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    80
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    81
    (case hint of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    82
      NONE => default
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    83
    | SOME tyco =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    84
        (case AList.lookup (op =) tab tyco of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    85
          NONE => default (*permissive*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    86
        | SOME info => SOME info))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    87
  end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    88
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    89
val lookup_by_case = Symtab.lookup o cases_of;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    90
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
(** installation **)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    93
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    94
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
    95
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    96
val name_of = try (dest_Const #> fst);
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
(* parse translation *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
    99
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   100
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
   101
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   102
fun case_tr ctxt [t, u] =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   103
      let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   104
        val thy = Proof_Context.theory_of ctxt;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   105
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   106
        fun is_const s =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   107
          Sign.declared_const thy (Proof_Context.intern_const ctxt s);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   108
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   109
        fun abs p tTs t = Syntax.const @{const_syntax case_abs} $
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   110
          fold constrain_Abs tTs (absfree p t);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   111
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   112
        fun abs_pat (Const ("_constrain", _) $ t $ tT) tTs = abs_pat t (tT :: tTs)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   113
          | abs_pat (Free (p as (x, _))) tTs =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   114
              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
   115
          | 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
   116
          | abs_pat _ _ = I;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   117
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   118
        fun dest_case1 (Const (@{syntax_const "_case1"}, _) $ l $ r) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   119
              abs_pat l []
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   120
                (Syntax.const @{const_syntax case_elem} $ Term_Position.strip_positions l $ r)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   121
          | dest_case1 _ = case_error "dest_case1";
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   122
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   123
        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
   124
          | dest_case2 t = [t];
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   125
      in
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   126
        Syntax.const @{const_syntax case_guard} $ (fold_rev
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   127
          (fn t => fn u =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   128
             Syntax.const @{const_syntax case_cons} $ dest_case1 t $ u)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   129
          (dest_case2 u)
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   130
          (Syntax.const @{const_syntax case_nil}) $ t)
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   131
      end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   132
  | case_tr _ _ = case_error "case_tr";
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   133
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   134
val trfun_setup =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   135
  Sign.add_advanced_trfuns ([],
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   136
    [(@{syntax_const "_case_syntax"}, case_tr)],
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   137
    [], []);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   138
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   139
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   140
(* print translation *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   141
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   142
fun case_tr' [tx] =
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   143
      let
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   144
        val (t, x) = Term.dest_comb tx;
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   145
        fun mk_clause (Const (@{const_syntax case_abs}, _) $ Abs (s, T, t)) xs used =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   146
              let val (s', used') = Name.variant s used
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   147
              in mk_clause t ((s', T) :: xs) used' end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   148
          | mk_clause (Const (@{const_syntax case_elem}, _) $ pat $ rhs) xs _ =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   149
              Syntax.const @{syntax_const "_case1"} $
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   150
                subst_bounds (map Syntax_Trans.mark_bound_abs xs, pat) $
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   151
                subst_bounds (map Syntax_Trans.mark_bound_body xs, rhs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   152
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   153
        fun mk_clauses (Const (@{const_syntax case_nil}, _)) = []
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   154
          | mk_clauses (Const (@{const_syntax case_cons}, _) $ t $ u) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   155
              mk_clause t [] (Term.declare_term_frees t Name.context) ::
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   156
              mk_clauses u
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   157
      in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   158
        Syntax.const @{syntax_const "_case_syntax"} $ x $
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   159
          foldr1 (fn (t, u) => Syntax.const @{syntax_const "_case2"} $ t $ u)
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   160
            (mk_clauses t)
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   161
      end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   162
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   163
val trfun_setup' = Sign.add_trfuns
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   164
  ([], [], [(@{const_syntax "case_guard"}, case_tr')], []);
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   165
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   166
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   167
(* declarations *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   168
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   169
fun register raw_case_comb raw_constrs context =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   170
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   171
    val ctxt = Context.proof_of context;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   172
    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
   173
    val constrs = Variable.polymorphic ctxt raw_constrs;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   174
    val case_key = case_comb |> dest_Const |> fst;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   175
    val constr_keys = map (fst o dest_Const) constrs;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   176
    val data = (case_comb, constrs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   177
    val Tname = Tname_of_data data;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   178
    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
   179
    val update_cases = Symtab.update (case_key, data);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   180
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   181
    context
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   182
    |> map_constrs update_constrs
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   183
    |> map_cases update_cases
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   184
  end;
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
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   187
(* (Un)check phases *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   188
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   189
datatype config = Error | Warning | Quiet;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   190
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   191
exception CASE_ERROR of string * int;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   192
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   193
fun match_type ctxt pat ob =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   194
  Sign.typ_match (Proof_Context.theory_of ctxt) (pat, ob) Vartab.empty;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   195
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   196
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   197
(*Each pattern carries with it a tag i, which denotes the clause it
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   198
came from. i = ~1 indicates that the clause was added by pattern
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   199
completion.*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   200
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   201
fun add_row_used ((prfx, pats), (tm, tag)) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   202
  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
   203
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   204
(* try to preserve names given by user *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   205
fun default_name "" (Free (name', _)) = name'
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   206
  | default_name name _ = name;
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
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   209
(*Produce an instance of a constructor, plus fresh variables for its arguments.*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   210
fun fresh_constr ctxt colty used c =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   211
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   212
    val (_, T) = dest_Const c;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   213
    val Ts = binder_types T;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   214
    val (names, _) = fold_map Name.variant
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   215
      (Datatype_Prop.make_tnames (map Logic.unvarifyT_global Ts)) used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   216
    val ty = body_type T;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   217
    val ty_theta = match_type ctxt ty colty
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   218
      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
   219
    val c' = Envir.subst_term_types ty_theta c;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   220
    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
   221
  in (c', gvars) end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   222
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   223
(*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
   224
  pattern with constructor = name.*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   225
fun mk_group (name, T) rows =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   226
  let val k = length (binder_types T) in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   227
    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
   228
      fn ((in_group, not_in_group), names) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   229
        (case strip_comb p of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   230
          (Const (name', _), args) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   231
            if name = name' then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   232
              if length args = k then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   233
                ((((prfx, args @ ps), rhs) :: in_group, not_in_group),
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   234
                 map2 default_name names args)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   235
              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
   236
            else ((in_group, row :: not_in_group), names)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   237
        | _ => raise CASE_ERROR ("Not a constructor pattern", i)))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   238
    rows (([], []), replicate k "") |>> pairself rev
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   239
  end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   240
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   241
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   242
(* Partitioning *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   243
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   244
fun partition _ _ _ _ _ [] = raise CASE_ERROR ("partition: no rows", ~1)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   245
  | partition ctxt used constructors colty res_ty
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   246
        (rows as (((prfx, _ :: ps), _) :: _)) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   247
      let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   248
        fun part [] [] = []
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   249
          | 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
   250
          | part (c :: cs) rows =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   251
              let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   252
                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
   253
                val used' = fold add_row_used in_group used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   254
                val (c', gvars) = fresh_constr ctxt colty used' c;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   255
                val in_group' =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   256
                  if null in_group  (* Constructor not given *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   257
                  then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   258
                    let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   259
                      val Ts = map fastype_of ps;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   260
                      val (xs, _) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   261
                        fold_map Name.variant
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   262
                          (replicate (length ps) "x")
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   263
                          (fold Term.declare_term_frees gvars used');
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   264
                    in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   265
                      [((prfx, gvars @ map Free (xs ~~ Ts)),
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   266
                        (Const (@{const_name undefined}, res_ty), ~1))]
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   267
                    end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   268
                  else in_group;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   269
              in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   270
                {constructor = c',
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   271
                 new_formals = gvars,
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   272
                 names = names,
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   273
                 group = in_group'} :: part cs not_in_group
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   274
              end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   275
      in part constructors rows end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   276
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   277
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
   278
  | 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
   279
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   280
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   281
(* Translation of pattern terms into nested case expressions. *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   282
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   283
fun mk_case ctxt used range_ty =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   284
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   285
    val get_info = lookup_by_constr_permissive ctxt;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   286
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   287
    fun expand constructors used ty ((_, []), _) = raise CASE_ERROR ("mk_case: expand", ~1)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   288
      | 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
   289
          if is_Free p then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   290
            let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   291
              val used' = add_row_used row used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   292
              fun expnd c =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   293
                let val capp = list_comb (fresh_constr ctxt ty used' c)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   294
                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
   295
            in map expnd constructors end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   296
          else [row];
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   297
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   298
    val (name, _) = Name.variant "a" used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   299
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   300
    fun mk _ [] = raise CASE_ERROR ("no rows", ~1)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   301
      | mk [] (((_, []), (tm, tag)) :: _) = ([tag], tm) (* Done *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   302
      | mk path (rows as ((row as ((_, [Free _]), _)) :: _ :: _)) = mk path [row]
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   303
      | mk (u :: us) (rows as ((_, _ :: _), _) :: _) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   304
          let val col0 = map (fn ((_, p :: _), (_, i)) => (p, i)) rows in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   305
            (case Option.map (apfst head_of)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   306
                (find_first (not o is_Free o fst) col0) of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   307
              NONE =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   308
                let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   309
                  val rows' = map (fn ((v, _), row) => row ||>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   310
                    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
   311
                in mk us rows' end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   312
            | SOME (Const (cname, cT), i) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   313
                (case get_info (cname, cT) of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   314
                  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
   315
                | SOME (case_comb, constructors) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   316
                    let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   317
                      val pty = body_type cT;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   318
                      val used' = fold Term.declare_term_frees us used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   319
                      val nrows = maps (expand constructors used' pty) rows;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   320
                      val subproblems =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   321
                        partition ctxt used' constructors pty range_ty nrows;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   322
                      val (pat_rect, dtrees) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   323
                        split_list (map (fn {new_formals, group, ...} =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   324
                          mk (new_formals @ us) group) subproblems);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   325
                      val case_functions =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   326
                        map2 (fn {new_formals, names, ...} =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   327
                          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
   328
                            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
   329
                              (new_formals ~~ names))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   330
                        subproblems dtrees;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   331
                      val types = map fastype_of (case_functions @ [u]);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   332
                      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
   333
                      val tree = list_comb (case_const, case_functions @ [u]);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   334
                    in (flat pat_rect, tree) end)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   335
            | SOME (t, i) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   336
                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
   337
          end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   338
      | mk _ _ = raise CASE_ERROR ("Malformed row matrix", ~1)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   339
  in mk end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   340
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   341
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   342
(* replace occurrences of dummy_pattern by distinct variables *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   343
fun replace_dummies (Const (@{const_name dummy_pattern}, T)) used =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   344
      let val (x, used') = Name.variant "x" used
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   345
      in (Free (x, T), used') end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   346
  | replace_dummies (t $ u) used =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   347
      let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   348
        val (t', used') = replace_dummies t used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   349
        val (u', used'') = replace_dummies u used';
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   350
      in (t' $ u', used'') end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   351
  | replace_dummies t used = (t, used);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   352
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   353
(*Repeated variable occurrences in a pattern are not allowed.*)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   354
fun no_repeat_vars ctxt pat = fold_aterms
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   355
  (fn x as Free (s, _) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   356
      (fn xs =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   357
        if member op aconv xs x then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   358
          case_error (quote s ^ " occurs repeatedly in the pattern " ^
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   359
            quote (Syntax.string_of_term ctxt pat))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   360
        else x :: xs)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   361
    | _ => I) pat [];
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   362
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   363
fun make_case ctxt config used x clauses =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   364
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   365
    fun string_of_clause (pat, rhs) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   366
      Syntax.string_of_term ctxt (Syntax.const @{syntax_const "_case1"} $ pat $ rhs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   367
    val _ = map (no_repeat_vars ctxt o fst) clauses;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   368
    val (rows, used') = used |>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   369
      fold (fn (pat, rhs) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   370
        Term.declare_term_frees pat #> Term.declare_term_frees rhs) clauses |>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   371
      fold_map (fn (i, (pat, rhs)) => fn used =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   372
        let val (pat', used') = replace_dummies pat used
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   373
        in ((([], [pat']), (rhs, i)), used') end)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   374
          (map_index I clauses);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   375
    val rangeT =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   376
      (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
   377
        [] => case_error "no clauses given"
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   378
      | [T] => T
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   379
      | _ => 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
   380
    val used' = fold add_row_used rows used;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   381
    val (tags, case_tm) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   382
      mk_case ctxt used' rangeT [x] rows
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   383
        handle CASE_ERROR (msg, i) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   384
          case_error
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   385
            (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
   386
    val _ =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   387
      (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
   388
        [] => ()
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   389
      | is =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   390
          (case config of Error => case_error | Warning => warning | Quiet => fn _ => ())
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   391
            ("The following clauses are redundant (covered by preceding clauses):\n" ^
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   392
              cat_lines (map (string_of_clause o nth clauses) is)));
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   393
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   394
    case_tm
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   395
  end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   396
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   397
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   398
(* term check *)
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
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
   401
      let val (s', used') = Name.variant s used
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   402
      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
   403
  | 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
   404
      (subst_bounds (xs, t), subst_bounds (xs, u))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   405
  | decode_clause _ _ _ = case_error "decode_clause";
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   406
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   407
fun decode_cases (Const (@{const_name case_nil}, _)) = []
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   408
  | decode_cases (Const (@{const_name case_cons}, _) $ t $ u) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   409
      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
   410
      decode_cases u
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   411
  | decode_cases _ = case_error "decode_cases";
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   412
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   413
fun check_case ctxt =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   414
  let
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   415
    fun decode_case (Const (@{const_name case_guard}, _) $ (t $ u)) =
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   416
        make_case ctxt Error Name.context (decode_case u) (decode_cases t)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   417
    | decode_case (t $ u) = decode_case t $ decode_case u
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   418
    | decode_case (Abs (x, T, u)) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   419
        let val (x', u') = Term.dest_abs (x, T, u);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   420
        in Term.absfree (x', T) (decode_case u') end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   421
    | decode_case t = t;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   422
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   423
    map decode_case
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   424
  end;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   425
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   426
val term_check_setup =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   427
  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
   428
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
(* Pretty printing of nested case expressions *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   431
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   432
(* destruct one level of pattern matching *)
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
fun dest_case ctxt d used t =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   435
  (case apfst name_of (strip_comb t) of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   436
    (SOME cname, ts as _ :: _) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   437
      let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   438
        val (fs, x) = split_last ts;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   439
        fun strip_abs i Us t =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   440
          let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   441
            val zs = strip_abs_vars t;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   442
            val j = length zs;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   443
            val (xs, ys) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   444
              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
   445
              else chop i zs;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   446
            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
   447
            val xs' = map Free
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   448
              ((fold_map Name.variant (map fst xs)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   449
                  (Term.declare_term_names u used) |> fst) ~~
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   450
               map snd xs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   451
            val (xs1, xs2) = chop j xs'
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   452
          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
   453
        fun is_dependent i t =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   454
          let val k = length (strip_abs_vars t) - i
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   455
          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
   456
        fun count_cases (_, _, true) = I
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   457
          | 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
   458
        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
   459
        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
   460
        val get_info = lookup_by_case ctxt;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   461
      in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   462
        (case get_info cname of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   463
          SOME (_, constructors) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   464
            if length fs = length constructors then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   465
              let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   466
                val cases = map (fn (Const (s, U), t) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   467
                  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   468
                    val Us = binder_types U;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   469
                    val k = length Us;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   470
                    val p as (xs, _) = strip_abs k Us t;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   471
                  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   472
                    (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
   473
                  end) (constructors ~~ fs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   474
                val cases' =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   475
                  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
   476
                    (fold_rev count_cases cases []);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   477
                val R = fastype_of t;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   478
                val dummy =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   479
                  if d then Term.dummy_pattern R
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   480
                  else Free (Name.variant "x" used |> fst, R);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   481
              in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   482
                SOME (x,
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   483
                  map mk_case
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   484
                    (case find_first (is_undefined o fst) cases' of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   485
                      SOME (_, cs) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   486
                        if length cs = length constructors then [hd cases]
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   487
                        else filter_out (fn (_, (_, body), _) => is_undefined body) cases
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   488
                    | NONE =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   489
                        (case cases' of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   490
                          [] => cases
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   491
                        | (default, cs) :: _ =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   492
                            if length cs = 1 then cases
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   493
                            else if length cs = length constructors then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   494
                              [hd cases, (dummy, ([], default), false)]
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   495
                            else
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   496
                              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
   497
                                [(dummy, ([], default), false)])))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   498
              end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   499
            else NONE
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   500
        | _ => NONE)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   501
      end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   502
  | _ => NONE);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   503
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   504
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   505
(* destruct nested patterns *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   506
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   507
fun encode_clause S T (pat, rhs) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   508
  fold (fn x as (_, U) => fn t =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   509
    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
   510
      (Term.add_frees pat [])
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   511
      (Const (@{const_name case_elem}, S --> T --> S --> T) $ pat $ rhs);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   512
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   513
fun encode_cases S T [] = Const (@{const_name case_nil}, S --> T)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   514
  | encode_cases S T (p :: ps) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   515
      Const (@{const_name case_cons}, (S --> T) --> (S --> T) --> S --> T) $
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   516
        encode_clause S T p $ encode_cases S T ps;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   517
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   518
fun encode_case (t, ps as (pat, rhs) :: _) =
51674
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   519
    let
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   520
      val T = fastype_of rhs;
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   521
    in
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   522
      Const (@{const_name case_guard}, T --> T) $
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   523
        (encode_cases (fastype_of pat) (fastype_of rhs) ps $ t)
2b1498a2ce85 special constant to prevent eta-contraction of the check-phase syntax of case translations
traytel
parents: 51673
diff changeset
   524
    end
51673
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   525
  | encode_case _ = case_error "encode_case";
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   526
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   527
fun strip_case' ctxt d (pat, rhs) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   528
  (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
   529
    SOME (exp as Free _, clauses) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   530
      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
   531
        not (exists (fn (_, rhs') =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   532
          Term.exists_subterm (curry (op aconv) exp) rhs') clauses)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   533
      then
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   534
        maps (strip_case' ctxt d) (map (fn (pat', rhs') =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   535
          (subst_free [(exp, pat')] pat, rhs')) clauses)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   536
      else [(pat, rhs)]
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   537
  | _ => [(pat, rhs)]);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   538
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   539
fun strip_case ctxt d t =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   540
  (case dest_case ctxt d Name.context t of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   541
    SOME (x, clauses) => encode_case (x, maps (strip_case' ctxt d) clauses)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   542
  | NONE =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   543
    (case t of
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   544
      (t $ u) => strip_case ctxt d t $ strip_case ctxt d u
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   545
    | (Abs (x, T, u)) =>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   546
        let val (x', u') = Term.dest_abs (x, T, u);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   547
        in Term.absfree (x', T) (strip_case ctxt d u') end
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   548
    | _ => t));
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   549
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   550
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   551
(* term uncheck *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   552
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   553
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
   554
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   555
fun uncheck_case ctxt ts =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   556
  if Config.get ctxt show_cases then map (strip_case ctxt true) ts else ts;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   557
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   558
val term_uncheck_setup =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   559
  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
   560
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
(* theory setup *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   563
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   564
val setup =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   565
  trfun_setup #>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   566
  trfun_setup' #>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   567
  term_check_setup #>
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   568
  term_uncheck_setup;
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   569
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   570
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   571
(* outer syntax commands *)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   572
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   573
fun print_case_translations ctxt =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   574
  let
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   575
    val cases = Symtab.dest (cases_of ctxt);
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   576
    fun show_case (_, data as (comb, ctrs)) =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   577
      Pretty.big_list
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   578
        (Pretty.string_of (Pretty.block [Pretty.str (Tname_of_data data), Pretty.str ":"]))
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   579
        [Pretty.block [Pretty.brk 3, Pretty.block
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   580
          [Pretty.str "combinator:", Pretty.brk 1, Pretty.quote (Syntax.pretty_term ctxt comb)]],
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   581
        Pretty.block [Pretty.brk 3, Pretty.block
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   582
          [Pretty.str "constructors:", Pretty.brk 1,
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   583
             Pretty.list "" "" (map (Pretty.quote o Syntax.pretty_term ctxt) ctrs)]]];
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   584
  in
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   585
    Pretty.big_list "Case translations:" (map show_case cases)
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   586
    |> Pretty.writeln
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   587
  end;
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
val _ =
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   590
  Outer_Syntax.improper_command @{command_spec "print_case_translations"}
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   591
    "print registered case combinators and constructors"
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   592
    (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
   593
4dfa00e264d8 separate data used for case translation from the datatype package
traytel
parents:
diff changeset
   594
end;