src/HOL/Tools/Function/function_common.ML
changeset 59159 9312710451f5
parent 59058 a78612c67ec0
child 59498 50b60f501b05
equal deleted inserted replaced
59158:05cb83f083b9 59159:9312710451f5
     4 Common definitions and other infrastructure for the function package.
     4 Common definitions and other infrastructure for the function package.
     5 *)
     5 *)
     6 
     6 
     7 signature FUNCTION_DATA =
     7 signature FUNCTION_DATA =
     8 sig
     8 sig
       
     9   type info =
       
    10    {is_partial : bool,
       
    11     defname : string,
       
    12       (*contains no logical entities: invariant under morphisms:*)
       
    13     add_simps : (binding -> binding) -> string -> (binding -> binding) ->
       
    14       Token.src list -> thm list -> local_theory -> thm list * local_theory,
       
    15     fnames : string list,
       
    16     case_names : string list,
       
    17     fs : term list,
       
    18     R : term,
       
    19     dom: term,
       
    20     psimps: thm list,
       
    21     pinducts: thm list,
       
    22     simps : thm list option,
       
    23     inducts : thm list option,
       
    24     termination : thm,
       
    25     cases : thm list,
       
    26     pelims: thm list list,
       
    27     elims: thm list list option}
       
    28 end
       
    29 
       
    30 structure Function_Data : FUNCTION_DATA =
       
    31 struct
     9 
    32 
    10 type info =
    33 type info =
    11  {is_partial : bool,
    34  {is_partial : bool,
    12   defname : string,
    35   defname : string,
    13     (* contains no logical entities: invariant under morphisms: *)
    36     (*contains no logical entities: invariant under morphisms:*)
    14   add_simps : (binding -> binding) -> string -> (binding -> binding) ->
       
    15     Token.src list -> thm list -> local_theory -> thm list * local_theory,
       
    16   fnames : string list,
       
    17   case_names : string list,
       
    18   fs : term list,
       
    19   R : term,
       
    20   dom: term,
       
    21   psimps: thm list,
       
    22   pinducts: thm list,
       
    23   simps : thm list option,
       
    24   inducts : thm list option,
       
    25   termination : thm,
       
    26   cases : thm list,
       
    27   pelims: thm list list,
       
    28   elims: thm list list option}
       
    29 
       
    30 end
       
    31 
       
    32 structure Function_Data : FUNCTION_DATA =
       
    33 struct
       
    34 
       
    35 type info =
       
    36  {is_partial : bool,
       
    37   defname : string,
       
    38     (* contains no logical entities: invariant under morphisms: *)
       
    39   add_simps : (binding -> binding) -> string -> (binding -> binding) ->
    37   add_simps : (binding -> binding) -> string -> (binding -> binding) ->
    40     Token.src list -> thm list -> local_theory -> thm list * local_theory,
    38     Token.src list -> thm list -> local_theory -> thm list * local_theory,
    41   fnames : string list,
    39   fnames : string list,
    42   case_names : string list,
    40   case_names : string list,
    43   fs : term list,
    41   fs : term list,
    62   val mk_acc : typ -> term -> term
    60   val mk_acc : typ -> term -> term
    63   val function_name : string -> string
    61   val function_name : string -> string
    64   val graph_name : string -> string
    62   val graph_name : string -> string
    65   val rel_name : string -> string
    63   val rel_name : string -> string
    66   val dom_name : string -> string
    64   val dom_name : string -> string
    67   val apply_termination_rule : Proof.context -> int -> tactic
    65   val split_def : Proof.context -> (string -> 'a) -> term ->
       
    66     string * (string * typ) list * term list * term list * term
       
    67   val check_defs : Proof.context -> ((string * typ) * 'a) list -> term list -> unit
       
    68   type fixes = ((string * typ) * mixfix) list
       
    69   type 'a spec = (Attrib.binding * 'a list) list
       
    70   datatype function_config = FunctionConfig of
       
    71    {sequential: bool,
       
    72     default: string option,
       
    73     domintros: bool,
       
    74     partials: bool}
       
    75   type preproc = function_config -> Proof.context -> fixes -> term spec ->
       
    76     (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
       
    77   val fname_of : term -> string
       
    78   val mk_case_names : int -> string -> int -> string list
       
    79   val empty_preproc : (Proof.context -> ((string * typ) * mixfix) list -> term list -> 'c) ->
       
    80     preproc
       
    81   val termination_rule_tac : Proof.context -> int -> tactic
       
    82   val store_termination_rule : thm -> Context.generic -> Context.generic
       
    83   val get_functions : Proof.context -> (term * info) Item_Net.T
       
    84   val add_function_data : info -> Context.generic -> Context.generic
       
    85   val termination_prover_tac : Proof.context -> tactic
       
    86   val set_termination_prover : (Proof.context -> tactic) -> Context.generic -> Context.generic
       
    87   val get_preproc: Proof.context -> preproc
       
    88   val set_preproc: preproc -> Context.generic -> Context.generic
    68   datatype function_result = FunctionResult of
    89   datatype function_result = FunctionResult of
    69    {fs: term list,
    90    {fs: term list,
    70     G: term,
    91     G: term,
    71     R: term,
    92     R: term,
    72     dom: term,
    93     dom: term,
    75     cases : thm list,
    96     cases : thm list,
    76     pelims : thm list list,
    97     pelims : thm list list,
    77     termination : thm,
    98     termination : thm,
    78     domintros : thm list option}
    99     domintros : thm list option}
    79   val transform_function_data : info -> morphism -> info
   100   val transform_function_data : info -> morphism -> info
    80   val get_function : Proof.context -> (term * info) Item_Net.T
       
    81   val import_function_data : term -> Proof.context -> info option
   101   val import_function_data : term -> Proof.context -> info option
    82   val import_last_function : Proof.context -> info option
   102   val import_last_function : Proof.context -> info option
    83   val add_function_data : info -> Context.generic -> Context.generic
       
    84   val set_termination_prover : (Proof.context -> tactic) -> Context.generic -> Context.generic
       
    85   val get_termination_prover : Proof.context -> tactic
       
    86   val store_termination_rule : thm -> Context.generic -> Context.generic
       
    87   datatype function_config = FunctionConfig of
       
    88    {sequential: bool,
       
    89     default: string option,
       
    90     domintros: bool,
       
    91     partials: bool}
       
    92   val default_config : function_config
   103   val default_config : function_config
    93   val split_def : Proof.context -> (string -> 'a) -> term ->
       
    94     string * (string * typ) list * term list * term list * term
       
    95   val check_defs : Proof.context -> ((string * typ) * 'a) list -> term list -> unit
       
    96   type fixes = ((string * typ) * mixfix) list
       
    97   type 'a spec = (Attrib.binding * 'a list) list
       
    98   type preproc = function_config -> Proof.context -> fixes -> term spec ->
       
    99     (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
       
   100   val fname_of : term -> string
       
   101   val mk_case_names : int -> string -> int -> string list
       
   102   val empty_preproc : (Proof.context -> ((string * typ) * mixfix) list -> term list -> 'c) -> preproc
       
   103   val get_preproc: Proof.context -> preproc
       
   104   val set_preproc: preproc -> Context.generic -> Context.generic
       
   105   val function_parser : function_config ->
   104   val function_parser : function_config ->
   106     ((function_config * (binding * string option * mixfix) list) * (Attrib.binding * string) list) parser
   105     ((function_config * (binding * string option * mixfix) list) *
       
   106       (Attrib.binding * string) list) parser
   107 end
   107 end
   108 
   108 
   109 structure Function_Common : FUNCTION_COMMON =
   109 structure Function_Common : FUNCTION_COMMON =
   110 struct
   110 struct
   111 
   111 
   112 open Function_Data
   112 open Function_Data
   113 
   113 
   114 local open Function_Lib in
   114 local open Function_Lib in
   115 
   115 
   116 (* Profiling *)
   116 
   117 val profile = Unsynchronized.ref false;
   117 (* profiling *)
       
   118 
       
   119 val profile = Unsynchronized.ref false
   118 
   120 
   119 fun PROFILE msg = if !profile then timeap_msg msg else I
   121 fun PROFILE msg = if !profile then timeap_msg msg else I
   120 
   122 
   121 val acc_const_name = @{const_name Wellfounded.accp}
   123 val acc_const_name = @{const_name Wellfounded.accp}
   122 fun mk_acc domT R =
   124 fun mk_acc domT R =
   123   Const (acc_const_name, (domT --> domT --> HOLogic.boolT) --> domT --> HOLogic.boolT) $ R 
   125   Const (acc_const_name, (domT --> domT --> HOLogic.boolT) --> domT --> HOLogic.boolT) $ R
   124 
   126 
   125 val function_name = suffix "C"
   127 val function_name = suffix "C"
   126 val graph_name = suffix "_graph"
   128 val graph_name = suffix "_graph"
   127 val rel_name = suffix "_rel"
   129 val rel_name = suffix "_rel"
   128 val dom_name = suffix "_dom"
   130 val dom_name = suffix "_dom"
   129 
   131 
   130 (* Termination rules *)
   132 
   131 
   133 (* analyzing function equations *)
   132 (* FIXME just one data slot (record) per program unit *)
   134 
   133 structure TerminationRule = Generic_Data
   135 fun split_def ctxt check_head geq =
       
   136   let
       
   137     fun input_error msg = cat_lines [msg, Syntax.string_of_term ctxt geq]
       
   138     val qs = Term.strip_qnt_vars @{const_name Pure.all} geq
       
   139     val imp = Term.strip_qnt_body @{const_name Pure.all} geq
       
   140     val (gs, eq) = Logic.strip_horn imp
       
   141 
       
   142     val (f_args, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop eq)
       
   143       handle TERM _ => error (input_error "Not an equation")
       
   144 
       
   145     val (head, args) = strip_comb f_args
       
   146 
       
   147     val fname = fst (dest_Free head) handle TERM _ => ""
       
   148     val _ = check_head fname
       
   149   in
       
   150     (fname, qs, gs, args, rhs)
       
   151   end
       
   152 
       
   153 (*check for all sorts of errors in the input*)
       
   154 fun check_defs ctxt fixes eqs =
       
   155   let
       
   156     val fnames = map (fst o fst) fixes
       
   157 
       
   158     fun check geq =
       
   159       let
       
   160         fun input_error msg = error (cat_lines [msg, Syntax.string_of_term ctxt geq])
       
   161 
       
   162         fun check_head fname =
       
   163           member (op =) fnames fname orelse
       
   164           input_error ("Illegal equation head. Expected " ^ commas_quote fnames)
       
   165 
       
   166         val (fname, qs, gs, args, rhs) = split_def ctxt check_head geq
       
   167 
       
   168         val _ = length args > 0 orelse input_error "Function has no arguments:"
       
   169 
       
   170         fun add_bvs t is = add_loose_bnos (t, 0, is)
       
   171         val rvs = (subtract (op =) (fold add_bvs args []) (add_bvs rhs []))
       
   172                     |> map (fst o nth (rev qs))
       
   173 
       
   174         val _ = null rvs orelse input_error
       
   175           ("Variable" ^ plural " " "s " rvs ^ commas_quote rvs ^
       
   176            " occur" ^ plural "s" "" rvs ^ " on right hand side only:")
       
   177 
       
   178         val _ = forall (not o Term.exists_subterm
       
   179           (fn Free (n, _) => member (op =) fnames n | _ => false)) (gs @ args)
       
   180           orelse input_error "Defined function may not occur in premises or arguments"
       
   181 
       
   182         val freeargs = map (fn t => subst_bounds (rev (map Free qs), t)) args
       
   183         val funvars =
       
   184           filter
       
   185             (fn q => exists (exists_subterm (fn (Free q') $ _ => q = q' | _ => false)) freeargs) qs
       
   186         val _ = null funvars orelse (warning (cat_lines
       
   187           ["Bound variable" ^ plural " " "s " funvars ^
       
   188           commas_quote (map fst funvars) ^ " occur" ^ plural "s" "" funvars ^
       
   189           " in function position.", "Misspelled constructor???"]); true)
       
   190       in
       
   191         (fname, length args)
       
   192       end
       
   193 
       
   194     val grouped_args = AList.group (op =) (map check eqs)
       
   195     val _ = grouped_args
       
   196       |> map (fn (fname, ars) =>
       
   197         length (distinct (op =) ars) = 1 orelse
       
   198           error ("Function " ^ quote fname ^
       
   199             " has different numbers of arguments in different equations"))
       
   200 
       
   201     val not_defined = subtract (op =) (map fst grouped_args) fnames
       
   202     val _ = null not_defined
       
   203       orelse error ("No defining equations for function" ^
       
   204         plural " " "s " not_defined ^ commas_quote not_defined)
       
   205 
       
   206     fun check_sorts ((fname, fT), _) =
       
   207       Sorts.of_sort (Sign.classes_of (Proof_Context.theory_of ctxt)) (fT, @{sort type})
       
   208       orelse error (cat_lines
       
   209       ["Type of " ^ quote fname ^ " is not of sort " ^ quote "type" ^ ":",
       
   210        Syntax.string_of_typ (Config.put show_sorts true ctxt) fT])
       
   211 
       
   212     val _ = map check_sorts fixes
       
   213   in
       
   214     ()
       
   215   end
       
   216 
       
   217 
       
   218 (* preprocessors *)
       
   219 
       
   220 type fixes = ((string * typ) * mixfix) list
       
   221 type 'a spec = (Attrib.binding * 'a list) list
       
   222 
       
   223 datatype function_config = FunctionConfig of
       
   224  {sequential: bool,
       
   225   default: string option,
       
   226   domintros: bool,
       
   227   partials: bool}
       
   228 
       
   229 type preproc = function_config -> Proof.context -> fixes -> term spec ->
       
   230   (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
       
   231 
       
   232 val fname_of = fst o dest_Free o fst o strip_comb o fst o HOLogic.dest_eq o
       
   233   HOLogic.dest_Trueprop o Logic.strip_imp_concl o snd o dest_all_all
       
   234 
       
   235 fun mk_case_names i "" k = mk_case_names i (string_of_int (i + 1)) k
       
   236   | mk_case_names _ _ 0 = []
       
   237   | mk_case_names _ n 1 = [n]
       
   238   | mk_case_names _ n k = map (fn i => n ^ "_" ^ string_of_int i) (1 upto k)
       
   239 
       
   240 fun empty_preproc check (_: function_config) (ctxt: Proof.context) (fixes: fixes) spec =
       
   241   let
       
   242     val (bnds, tss) = split_list spec
       
   243     val ts = flat tss
       
   244     val _ = check ctxt fixes ts
       
   245     val fnames = map (fst o fst) fixes
       
   246     val indices = map (fn eq => find_index (curry op = (fname_of eq)) fnames) ts
       
   247 
       
   248     fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1)
       
   249       (indices ~~ xs) |> map (map snd)
       
   250 
       
   251     (* using theorem names for case name currently disabled *)
       
   252     val cnames = map_index (fn (i, _) => mk_case_names i "" 1) bnds |> flat
       
   253   in
       
   254     (ts, curry op ~~ bnds o Library.unflat tss, sort, cnames)
       
   255   end
       
   256 
       
   257 
       
   258 (* context data *)
       
   259 
       
   260 structure Data = Generic_Data
   134 (
   261 (
   135   type T = thm list
   262   type T =
   136   val empty = []
   263     thm list *
       
   264     (term * info) Item_Net.T *
       
   265     (Proof.context -> tactic) *
       
   266     preproc
       
   267   val empty: T =
       
   268    ([],
       
   269     Item_Net.init (op aconv o apply2 fst) (single o fst),
       
   270     fn _ => error "Termination prover not configured",
       
   271     empty_preproc check_defs)
   137   val extend = I
   272   val extend = I
   138   val merge = Thm.merge_thms
   273   fun merge
   139 );
   274    ((termination_rules1, functions1, termination_prover1, preproc1),
   140 
   275     (termination_rules2, functions2, _, _)) : T =
   141 val get_termination_rules = TerminationRule.get
   276    (Thm.merge_thms (termination_rules1, termination_rules2),
   142 val store_termination_rule = TerminationRule.map o cons
   277     Item_Net.merge (functions1, functions2),
   143 val apply_termination_rule = resolve_tac o get_termination_rules o Context.Proof
   278     termination_prover1,
   144 
   279     preproc1)
   145 
   280 )
   146 (* Function definition result data *)
   281 
       
   282 val termination_rule_tac = resolve_tac o #1 o Data.get o Context.Proof
       
   283 val store_termination_rule = Data.map o @{apply 4(1)} o cons
       
   284 
       
   285 val get_functions = #2 o Data.get o Context.Proof
       
   286 fun add_function_data (info : info as {fs, termination, ...}) =
       
   287   (Data.map o @{apply 4(2)}) (fold (fn f => Item_Net.update (f, info)) fs)
       
   288   #> store_termination_rule termination
       
   289 
       
   290 fun termination_prover_tac ctxt = #3 (Data.get (Context.Proof ctxt)) ctxt
       
   291 val set_termination_prover = Data.map o @{apply 4(3)} o K
       
   292 
       
   293 val get_preproc = #4 o Data.get o Context.Proof
       
   294 val set_preproc = Data.map o @{apply 4(4)} o K
       
   295 
       
   296 
       
   297 (* function definition result data *)
   147 
   298 
   148 datatype function_result = FunctionResult of
   299 datatype function_result = FunctionResult of
   149  {fs: term list,
   300  {fs: term list,
   150   G: term,
   301   G: term,
   151   R: term,
   302   R: term,
   171         inducts = Option.map fact inducts, termination = thm termination,
   322         inducts = Option.map fact inducts, termination = thm termination,
   172         defname = name defname, is_partial=is_partial, cases = fact cases,
   323         defname = name defname, is_partial=is_partial, cases = fact cases,
   173         elims = Option.map (map fact) elims, pelims = map fact pelims }
   324         elims = Option.map (map fact) elims, pelims = map fact pelims }
   174     end
   325     end
   175 
   326 
   176 (* FIXME just one data slot (record) per program unit *)
       
   177 structure FunctionData = Generic_Data
       
   178 (
       
   179   type T = (term * info) Item_Net.T;
       
   180   val empty : T = Item_Net.init (op aconv o apply2 fst) (single o fst);
       
   181   val extend = I;
       
   182   fun merge tabs : T = Item_Net.merge tabs;
       
   183 )
       
   184 
       
   185 val get_function = FunctionData.get o Context.Proof;
       
   186 
       
   187 fun lift_morphism thy f =
   327 fun lift_morphism thy f =
   188   let
   328   let
   189     fun term t = Thm.term_of (Drule.cterm_rule f (Thm.cterm_of thy t))
   329     fun term t = Thm.term_of (Drule.cterm_rule f (Thm.cterm_of thy t))
   190   in
   330   in
   191     Morphism.morphism "lift_morphism"
   331     Morphism.morphism "lift_morphism"
   203 
   343 
   204     fun match (trm, data) =
   344     fun match (trm, data) =
   205       SOME (transform_function_data data (inst_morph (Thm.match (cterm_of thy trm, ct))))
   345       SOME (transform_function_data data (inst_morph (Thm.match (cterm_of thy trm, ct))))
   206       handle Pattern.MATCH => NONE
   346       handle Pattern.MATCH => NONE
   207   in
   347   in
   208     get_first match (Item_Net.retrieve (get_function ctxt) t)
   348     get_first match (Item_Net.retrieve (get_functions ctxt) t)
   209   end
   349   end
   210 
   350 
   211 fun import_last_function ctxt =
   351 fun import_last_function ctxt =
   212   case Item_Net.content (get_function ctxt) of
   352   (case Item_Net.content (get_functions ctxt) of
   213     [] => NONE
   353     [] => NONE
   214   | (t, _) :: _ =>
   354   | (t, _) :: _ =>
   215     let
   355       let val ([t'], ctxt') = Variable.import_terms true [t] ctxt
   216       val ([t'], ctxt') = Variable.import_terms true [t] ctxt
   356       in import_function_data t' ctxt' end)
   217     in
   357 
   218       import_function_data t' ctxt'
   358 
   219     end
   359 (* configuration management *)
   220 
   360 
   221 fun add_function_data (data : info as {fs, termination, ...}) =
   361 datatype function_opt =
   222   FunctionData.map (fold (fn f => Item_Net.update (f, data)) fs)
   362     Sequential
   223   #> store_termination_rule termination
       
   224 
       
   225 
       
   226 (* Default Termination Prover *)
       
   227 
       
   228 (* FIXME just one data slot (record) per program unit *)
       
   229 structure TerminationProver = Generic_Data
       
   230 (
       
   231   type T = Proof.context -> tactic
       
   232   val empty = (fn _ => error "Termination prover not configured")
       
   233   val extend = I
       
   234   fun merge (a, _) = a
       
   235 )
       
   236 
       
   237 val set_termination_prover = TerminationProver.put
       
   238 fun get_termination_prover ctxt = TerminationProver.get (Context.Proof ctxt) ctxt
       
   239 
       
   240 
       
   241 (* Configuration management *)
       
   242 datatype function_opt
       
   243   = Sequential
       
   244   | Default of string
   363   | Default of string
   245   | DomIntros
   364   | DomIntros
   246   | No_Partials
   365   | No_Partials
   247 
   366 
   248 datatype function_config = FunctionConfig of
   367 fun apply_opt Sequential (FunctionConfig {sequential = _, default, domintros, partials}) =
   249  {sequential: bool,
   368       FunctionConfig
   250   default: string option,
   369         {sequential = true, default = default, domintros = domintros, partials = partials}
   251   domintros: bool,
   370   | apply_opt (Default d) (FunctionConfig {sequential, default = _, domintros, partials}) =
   252   partials: bool}
   371       FunctionConfig
   253 
   372         {sequential = sequential, default = SOME d, domintros = domintros, partials = partials}
   254 fun apply_opt Sequential (FunctionConfig {sequential, default, domintros, partials}) =
   373   | apply_opt DomIntros (FunctionConfig {sequential, default, domintros = _, partials}) =
   255     FunctionConfig {sequential=true, default=default, domintros=domintros, partials=partials}
   374       FunctionConfig
   256   | apply_opt (Default d) (FunctionConfig {sequential, default, domintros, partials}) =
   375         {sequential = sequential, default = default, domintros = true, partials = partials}
   257     FunctionConfig {sequential=sequential, default=SOME d, domintros=domintros, partials=partials}
   376   | apply_opt No_Partials (FunctionConfig {sequential, default, domintros, partials = _}) =
   258   | apply_opt DomIntros (FunctionConfig {sequential, default, domintros, partials}) =
   377       FunctionConfig
   259     FunctionConfig {sequential=sequential, default=default, domintros=true, partials=partials}
   378         {sequential = sequential, default = default, domintros = domintros, partials = false}
   260   | apply_opt No_Partials (FunctionConfig {sequential, default, domintros, partials}) =
       
   261     FunctionConfig {sequential=sequential, default=default, domintros=domintros, partials=false}
       
   262 
   379 
   263 val default_config =
   380 val default_config =
   264   FunctionConfig { sequential=false, default=NONE,
   381   FunctionConfig { sequential=false, default=NONE,
   265     domintros=false, partials=true}
   382     domintros=false, partials=true}
   266 
       
   267 
       
   268 (* Analyzing function equations *)
       
   269 
       
   270 fun split_def ctxt check_head geq =
       
   271   let
       
   272     fun input_error msg = cat_lines [msg, Syntax.string_of_term ctxt geq]
       
   273     val qs = Term.strip_qnt_vars @{const_name Pure.all} geq
       
   274     val imp = Term.strip_qnt_body @{const_name Pure.all} geq
       
   275     val (gs, eq) = Logic.strip_horn imp
       
   276 
       
   277     val (f_args, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop eq)
       
   278       handle TERM _ => error (input_error "Not an equation")
       
   279 
       
   280     val (head, args) = strip_comb f_args
       
   281 
       
   282     val fname = fst (dest_Free head) handle TERM _ => ""
       
   283     val _ = check_head fname
       
   284   in
       
   285     (fname, qs, gs, args, rhs)
       
   286   end
       
   287 
       
   288 (* Check for all sorts of errors in the input *)
       
   289 fun check_defs ctxt fixes eqs =
       
   290   let
       
   291     val fnames = map (fst o fst) fixes
       
   292 
       
   293     fun check geq =
       
   294       let
       
   295         fun input_error msg = error (cat_lines [msg, Syntax.string_of_term ctxt geq])
       
   296 
       
   297         fun check_head fname =
       
   298           member (op =) fnames fname orelse
       
   299           input_error ("Illegal equation head. Expected " ^ commas_quote fnames)
       
   300 
       
   301         val (fname, qs, gs, args, rhs) = split_def ctxt check_head geq
       
   302 
       
   303         val _ = length args > 0 orelse input_error "Function has no arguments:"
       
   304 
       
   305         fun add_bvs t is = add_loose_bnos (t, 0, is)
       
   306         val rvs = (subtract (op =) (fold add_bvs args []) (add_bvs rhs []))
       
   307                     |> map (fst o nth (rev qs))
       
   308 
       
   309         val _ = null rvs orelse input_error
       
   310           ("Variable" ^ plural " " "s " rvs ^ commas_quote rvs ^
       
   311            " occur" ^ plural "s" "" rvs ^ " on right hand side only:")
       
   312 
       
   313         val _ = forall (not o Term.exists_subterm
       
   314           (fn Free (n, _) => member (op =) fnames n | _ => false)) (gs @ args)
       
   315           orelse input_error "Defined function may not occur in premises or arguments"
       
   316 
       
   317         val freeargs = map (fn t => subst_bounds (rev (map Free qs), t)) args
       
   318         val funvars = filter (fn q => exists (exists_subterm (fn (Free q') $ _ => q = q' | _ => false)) freeargs) qs
       
   319         val _ = null funvars orelse (warning (cat_lines
       
   320           ["Bound variable" ^ plural " " "s " funvars ^
       
   321           commas_quote (map fst funvars) ^ " occur" ^ plural "s" "" funvars ^
       
   322           " in function position.", "Misspelled constructor???"]); true)
       
   323       in
       
   324         (fname, length args)
       
   325       end
       
   326 
       
   327     val grouped_args = AList.group (op =) (map check eqs)
       
   328     val _ = grouped_args
       
   329       |> map (fn (fname, ars) =>
       
   330         length (distinct (op =) ars) = 1
       
   331         orelse error ("Function " ^ quote fname ^
       
   332           " has different numbers of arguments in different equations"))
       
   333 
       
   334     val not_defined = subtract (op =) (map fst grouped_args) fnames
       
   335     val _ = null not_defined
       
   336       orelse error ("No defining equations for function" ^
       
   337         plural " " "s " not_defined ^ commas_quote not_defined)
       
   338 
       
   339     fun check_sorts ((fname, fT), _) =
       
   340       Sorts.of_sort (Sign.classes_of (Proof_Context.theory_of ctxt)) (fT, @{sort type})
       
   341       orelse error (cat_lines
       
   342       ["Type of " ^ quote fname ^ " is not of sort " ^ quote "type" ^ ":",
       
   343        Syntax.string_of_typ (Config.put show_sorts true ctxt) fT])
       
   344 
       
   345     val _ = map check_sorts fixes
       
   346   in
       
   347     ()
       
   348   end
       
   349 
       
   350 (* Preprocessors *)
       
   351 
       
   352 type fixes = ((string * typ) * mixfix) list
       
   353 type 'a spec = (Attrib.binding * 'a list) list
       
   354 type preproc = function_config -> Proof.context -> fixes -> term spec ->
       
   355   (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
       
   356 
       
   357 val fname_of = fst o dest_Free o fst o strip_comb o fst o HOLogic.dest_eq o
       
   358   HOLogic.dest_Trueprop o Logic.strip_imp_concl o snd o dest_all_all
       
   359 
       
   360 fun mk_case_names i "" k = mk_case_names i (string_of_int (i + 1)) k
       
   361   | mk_case_names _ n 0 = []
       
   362   | mk_case_names _ n 1 = [n]
       
   363   | mk_case_names _ n k = map (fn i => n ^ "_" ^ string_of_int i) (1 upto k)
       
   364 
       
   365 fun empty_preproc check (_: function_config) (ctxt: Proof.context) (fixes: fixes) spec =
       
   366   let
       
   367     val (bnds, tss) = split_list spec
       
   368     val ts = flat tss
       
   369     val _ = check ctxt fixes ts
       
   370     val fnames = map (fst o fst) fixes
       
   371     val indices = map (fn eq => find_index (curry op = (fname_of eq)) fnames) ts
       
   372 
       
   373     fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1) 
       
   374       (indices ~~ xs) |> map (map snd)
       
   375 
       
   376     (* using theorem names for case name currently disabled *)
       
   377     val cnames = map_index (fn (i, _) => mk_case_names i "" 1) bnds |> flat
       
   378   in
       
   379     (ts, curry op ~~ bnds o Library.unflat tss, sort, cnames)
       
   380   end
       
   381 
       
   382 (* FIXME just one data slot (record) per program unit *)
       
   383 structure Preprocessor = Generic_Data
       
   384 (
       
   385   type T = preproc
       
   386   val empty : T = empty_preproc check_defs
       
   387   val extend = I
       
   388   fun merge (a, _) = a
       
   389 )
       
   390 
       
   391 val get_preproc = Preprocessor.get o Context.Proof
       
   392 val set_preproc = Preprocessor.map o K
       
   393 
       
   394 
       
   395 
   383 
   396 local
   384 local
   397   val option_parser = Parse.group (fn () => "option")
   385   val option_parser = Parse.group (fn () => "option")
   398     ((Parse.reserved "sequential" >> K Sequential)
   386     ((Parse.reserved "sequential" >> K Sequential)
   399      || ((Parse.reserved "default" |-- Parse.term) >> Default)
   387      || ((Parse.reserved "default" |-- Parse.term) >> Default)