| author | blanchet | 
| Fri, 23 Aug 2013 16:02:32 +0200 | |
| changeset 53157 | c8369b691d04 | 
| parent 49965 | ee25a04fa06a | 
| child 54407 | e95831757903 | 
| permissions | -rw-r--r-- | 
| 33098 | 1 | (* Title: HOL/Tools/Function/fun.ML | 
| 2 | Author: Alexander Krauss, TU Muenchen | |
| 3 | ||
| 41114 | 4 | Command "fun": Function definitions with pattern splitting/completion | 
| 5 | and automated termination proofs. | |
| 33098 | 6 | *) | 
| 7 | ||
| 8 | signature FUNCTION_FUN = | |
| 9 | sig | |
| 44237 
2a2040c9d898
export Function_Fun.fun_config for user convenience;
 wenzelm parents: 
43329diff
changeset | 10 | val fun_config : Function_Common.function_config | 
| 36523 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 11 | val add_fun : (binding * typ option * mixfix) list -> | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 12 | (Attrib.binding * term) list -> Function_Common.function_config -> | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 13 | local_theory -> Proof.context | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 14 | val add_fun_cmd : (binding * string option * mixfix) list -> | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 15 | (Attrib.binding * string) list -> Function_Common.function_config -> | 
| 44239 
47ecd30e018d
less verbosity for 'function' and 'fun': observe "int" flag more carefully (cf. a32ca9165928);
 wenzelm parents: 
44237diff
changeset | 16 | bool -> local_theory -> Proof.context | 
| 33098 | 17 | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 18 | val setup : theory -> theory | 
| 33098 | 19 | end | 
| 20 | ||
| 21 | structure Function_Fun : FUNCTION_FUN = | |
| 22 | struct | |
| 23 | ||
| 33099 
b8cdd3d73022
function package: more standard names for structures and files
 krauss parents: 
33098diff
changeset | 24 | open Function_Lib | 
| 
b8cdd3d73022
function package: more standard names for structures and files
 krauss parents: 
33098diff
changeset | 25 | open Function_Common | 
| 33098 | 26 | |
| 27 | ||
| 28 | fun check_pats ctxt geq = | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 29 | let | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 30 | fun err str = error (cat_lines ["Malformed definition:", | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 31 | str ^ " not allowed in sequential mode.", | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 32 | Syntax.string_of_term ctxt geq]) | 
| 42361 | 33 | val thy = Proof_Context.theory_of ctxt | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 34 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 35 | fun check_constr_pattern (Bound _) = () | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 36 | | check_constr_pattern t = | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 37 | let | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 38 | val (hd, args) = strip_comb t | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 39 | in | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 40 | (((case Datatype.info_of_constr thy (dest_Const hd) of | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 41 | SOME _ => () | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 42 | | NONE => err "Non-constructor pattern") | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 43 |           handle TERM ("dest_Const", _) => err "Non-constructor patterns");
 | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 44 | map check_constr_pattern args; | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 45 | ()) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 46 | end | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 47 | |
| 39276 
2ad95934521f
improved error message for common mistake (fun f where "g x = ...")
 krauss parents: 
36960diff
changeset | 48 | val (_, qs, gs, args, _) = split_def ctxt (K true) geq | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 49 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 50 | val _ = if not (null gs) then err "Conditional equations" else () | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 51 | val _ = map check_constr_pattern args | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 52 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 53 | (* just count occurrences to check linearity *) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 54 | val _ = if fold (fold_aterms (fn Bound _ => Integer.add 1 | _ => I)) args 0 > length qs | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 55 | then err "Nonlinear patterns" else () | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 56 | in | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 57 | () | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 58 | end | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 59 | |
| 33098 | 60 | fun mk_catchall fixes arity_of = | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 61 | let | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 62 | fun mk_eqn ((fname, fT), _) = | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 63 | let | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 64 | val n = arity_of fname | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 65 | val (argTs, rT) = chop n (binder_types fT) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 66 | |> apsnd (fn Ts => Ts ---> body_type fT) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 67 | |
| 43329 
84472e198515
tuned signature: Name.invent and Name.invent_names;
 wenzelm parents: 
43323diff
changeset | 68 | val qs = map Free (Name.invent Name.context "a" n ~~ argTs) | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 69 | in | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 70 | HOLogic.mk_eq(list_comb (Free (fname, fT), qs), | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 71 |           Const ("HOL.undefined", rT))
 | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 72 | |> HOLogic.mk_Trueprop | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 73 | |> fold_rev Logic.all qs | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 74 | end | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 75 | in | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 76 | map mk_eqn fixes | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 77 | end | 
| 33098 | 78 | |
| 79 | fun add_catchall ctxt fixes spec = | |
| 39276 
2ad95934521f
improved error message for common mistake (fun f where "g x = ...")
 krauss parents: 
36960diff
changeset | 80 | let val fqgars = map (split_def ctxt (K true)) spec | 
| 33098 | 81 | val arity_of = map (fn (fname,_,_,args,_) => (fname, length args)) fqgars | 
| 82 | |> AList.lookup (op =) #> the | |
| 83 | in | |
| 84 | spec @ mk_catchall fixes arity_of | |
| 85 | end | |
| 86 | ||
| 48099 
e7e647949c95
fun command: produce hard failure when equations do not contribute to the specification (i.e., are covered by preceding clauses), to avoid confusing inexperienced users
 krauss parents: 
46961diff
changeset | 87 | fun further_checks ctxt origs tss = | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 88 | let | 
| 48099 
e7e647949c95
fun command: produce hard failure when equations do not contribute to the specification (i.e., are covered by preceding clauses), to avoid confusing inexperienced users
 krauss parents: 
46961diff
changeset | 89 | fun fail_redundant t = | 
| 
e7e647949c95
fun command: produce hard failure when equations do not contribute to the specification (i.e., are covered by preceding clauses), to avoid confusing inexperienced users
 krauss parents: 
46961diff
changeset | 90 | error (cat_lines ["Equation is redundant (covered by preceding clauses):", Syntax.string_of_term ctxt t]) | 
| 42947 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 91 | fun warn_missing strs = | 
| 43277 | 92 |       warning (cat_lines ("Missing patterns in function definition:" :: strs))
 | 
| 42947 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 93 | |
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 94 | val (tss', added) = chop (length origs) tss | 
| 33098 | 95 | |
| 42947 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 96 | val _ = case chop 3 (flat added) of | 
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 97 | ([], []) => () | 
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 98 | | (eqs, []) => warn_missing (map (Syntax.string_of_term ctxt) eqs) | 
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 99 | | (eqs, rest) => warn_missing (map (Syntax.string_of_term ctxt) eqs | 
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 100 |          @ ["(" ^ string_of_int (length rest) ^ " more)"])
 | 
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 101 | |
| 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 102 | val _ = (origs ~~ tss') | 
| 48099 
e7e647949c95
fun command: produce hard failure when equations do not contribute to the specification (i.e., are covered by preceding clauses), to avoid confusing inexperienced users
 krauss parents: 
46961diff
changeset | 103 | |> map (fn (t, ts) => if null ts then fail_redundant t else ()) | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 104 | in | 
| 42947 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 105 | () | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 106 | end | 
| 33098 | 107 | |
| 33099 
b8cdd3d73022
function package: more standard names for structures and files
 krauss parents: 
33098diff
changeset | 108 | fun sequential_preproc (config as FunctionConfig {sequential, ...}) ctxt fixes spec =
 | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 109 | if sequential then | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 110 | let | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 111 | val (bnds, eqss) = split_list spec | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 112 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 113 | val eqs = map the_single eqss | 
| 33098 | 114 | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 115 | val feqs = eqs | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 116 | |> tap (check_defs ctxt fixes) (* Standard checks *) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 117 | |> tap (map (check_pats ctxt)) (* More checks for sequential mode *) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 118 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 119 | val compleqs = add_catchall ctxt fixes feqs (* Completion *) | 
| 33098 | 120 | |
| 42947 
fcb6250bf6b4
fun command produces warning when patterns are incomplete (somewhat analogous to primrec)
 krauss parents: 
42793diff
changeset | 121 | val spliteqs = Function_Split.split_all_equations ctxt compleqs | 
| 48099 
e7e647949c95
fun command: produce hard failure when equations do not contribute to the specification (i.e., are covered by preceding clauses), to avoid confusing inexperienced users
 krauss parents: 
46961diff
changeset | 122 | |> tap (further_checks ctxt feqs) | 
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 123 | |
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 124 | fun restore_spec thms = | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 125 | bnds ~~ take (length bnds) (unflat spliteqs thms) | 
| 33098 | 126 | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 127 | val spliteqs' = flat (take (length bnds) spliteqs) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 128 | val fnames = map (fst o fst) fixes | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 129 | val indices = map (fn eq => find_index (curry op = (fname_of eq)) fnames) spliteqs' | 
| 33098 | 130 | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 131 | fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1) (indices ~~ xs) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 132 | |> map (map snd) | 
| 33098 | 133 | |
| 134 | ||
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 135 | val bnds' = bnds @ replicate (length spliteqs - length bnds) Attrib.empty_binding | 
| 33098 | 136 | |
| 34232 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 137 | (* using theorem names for case name currently disabled *) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 138 | val case_names = map_index (fn (i, (_, es)) => mk_case_names i "" (length es)) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 139 | (bnds' ~~ spliteqs) |> flat | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 140 | in | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 141 | (flat spliteqs, restore_spec, sort, case_names) | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 142 | end | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 143 | else | 
| 
36a2a3029fd3
new year's resolution: reindented code in function package
 krauss parents: 
33957diff
changeset | 144 | Function_Common.empty_preproc check_defs config ctxt fixes spec | 
| 33098 | 145 | |
| 146 | val setup = | |
| 33099 
b8cdd3d73022
function package: more standard names for structures and files
 krauss parents: 
33098diff
changeset | 147 | Context.theory_map (Function_Common.set_preproc sequential_preproc) | 
| 33098 | 148 | |
| 149 | ||
| 41417 | 150 | val fun_config = FunctionConfig { sequential=true, default=NONE,
 | 
| 41846 
b368a7aee46a
removed support for tail-recursion from function package (now implemented by partial_function)
 krauss parents: 
41417diff
changeset | 151 | domintros=false, partials=false } | 
| 33098 | 152 | |
| 44239 
47ecd30e018d
less verbosity for 'function' and 'fun': observe "int" flag more carefully (cf. a32ca9165928);
 wenzelm parents: 
44237diff
changeset | 153 | fun gen_add_fun add lthy = | 
| 36523 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 154 | let | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 155 | fun pat_completeness_auto ctxt = | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 156 | Pat_Completeness.pat_completeness_tac ctxt 1 | 
| 42793 | 157 | THEN auto_tac ctxt | 
| 36523 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 158 | fun prove_termination lthy = | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 159 | Function.prove_termination NONE | 
| 49965 | 160 | (Function_Common.get_termination_prover lthy) lthy | 
| 36523 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 161 | in | 
| 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 162 | lthy | 
| 44239 
47ecd30e018d
less verbosity for 'function' and 'fun': observe "int" flag more carefully (cf. a32ca9165928);
 wenzelm parents: 
44237diff
changeset | 163 | |> add pat_completeness_auto |> snd | 
| 36547 
2a9d0ec8c10d
return updated info record after termination proof
 krauss parents: 
36523diff
changeset | 164 | |> prove_termination |> snd | 
| 36523 
a294e4ebe0a3
clarified signature; simpler implementation in terms of function's tactic interface
 krauss parents: 
36521diff
changeset | 165 | end | 
| 33098 | 166 | |
| 44239 
47ecd30e018d
less verbosity for 'function' and 'fun': observe "int" flag more carefully (cf. a32ca9165928);
 wenzelm parents: 
44237diff
changeset | 167 | fun add_fun a b c = gen_add_fun (Function.add_function a b c) | 
| 
47ecd30e018d
less verbosity for 'function' and 'fun': observe "int" flag more carefully (cf. a32ca9165928);
 wenzelm parents: 
44237diff
changeset | 168 | fun add_fun_cmd a b c int = gen_add_fun (fn tac => Function.add_function_cmd a b c tac int) | 
| 33098 | 169 | |
| 170 | ||
| 171 | ||
| 172 | val _ = | |
| 46961 
5c6955f487e5
outer syntax command definitions based on formal command_spec derived from theory header declarations;
 wenzelm parents: 
45639diff
changeset | 173 |   Outer_Syntax.local_theory' @{command_spec "fun"}
 | 
| 
5c6955f487e5
outer syntax command definitions based on formal command_spec derived from theory header declarations;
 wenzelm parents: 
45639diff
changeset | 174 | "define general recursive functions (short version)" | 
| 
5c6955f487e5
outer syntax command definitions based on formal command_spec derived from theory header declarations;
 wenzelm parents: 
45639diff
changeset | 175 | (function_parser fun_config | 
| 
5c6955f487e5
outer syntax command definitions based on formal command_spec derived from theory header declarations;
 wenzelm parents: 
45639diff
changeset | 176 | >> (fn ((config, fixes), statements) => add_fun_cmd fixes statements config)) | 
| 33098 | 177 | |
| 178 | end |