1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
(*i camlp4use: "pa_extend.cmo q_MLast.cmo" i*)
(* $Id: tacextend.ml4 11309 2008-08-06 10:30:35Z herbelin $ *)
open Util
open Genarg
open Q_util
open Q_coqast
open Argextend
let loc = Util.dummy_loc
let default_loc = <:expr< Util.dummy_loc >>
type grammar_tactic_production_expr =
| TacTerm of string
| TacNonTerm of Util.loc * Genarg.argument_type * MLast.expr * string option
let rec make_patt = function
| [] -> <:patt< [] >>
| TacNonTerm(loc',_,_,Some p)::l ->
<:patt< [ $lid:p$ :: $make_patt l$ ] >>
| _::l -> make_patt l
let rec make_when loc = function
| [] -> <:expr< True >>
| TacNonTerm(loc',t,_,Some p)::l ->
let l = make_when loc l in
let loc = join_loc loc' loc in
let t = mlexpr_of_argtype loc' t in
<:expr< Genarg.genarg_tag $lid:p$ = $t$ && $l$ >>
| _::l -> make_when loc l
let rec make_let e = function
| [] -> e
| TacNonTerm(loc,t,_,Some p)::l ->
let loc = join_loc loc (MLast.loc_of_expr e) in
let e = make_let e l in
let v = <:expr< Genarg.out_gen $make_wit loc t$ $lid:p$ >> in
let v =
(* Special case for tactics which must be stored in algebraic
form to avoid marshalling closures and to be reprinted *)
if Pcoq.is_tactic_genarg t then
<:expr< ($v$, Tacinterp.eval_tactic $v$) >>
else v in
<:expr< let $lid:p$ = $v$ in $e$ >>
| _::l -> make_let e l
let add_clause s (pt,e) l =
let p = make_patt pt in
let w = Some (make_when (MLast.loc_of_expr e) pt) in
(p, w, make_let e pt)::l
let rec extract_signature = function
| [] -> []
| TacNonTerm (_,t,_,_) :: l -> t :: extract_signature l
| _::l -> extract_signature l
let check_unicity s l =
let l' = List.map (fun (l,_) -> extract_signature l) l in
if not (Util.list_distinct l') then
Pp.warning_with !Pp_control.err_ft
("Two distinct rules of tactic entry "^s^" have the same\n"^
"non-terminals in the same order: put them in distinct tactic entries")
let make_clauses s l =
check_unicity s l;
let default =
(<:patt< _ >>,None,<:expr< failwith "Tactic extension: cannot occur" >>) in
List.fold_right (add_clause s) l [default]
let rec make_args = function
| [] -> <:expr< [] >>
| TacNonTerm(loc,t,_,Some p)::l ->
<:expr< [ Genarg.in_gen $make_wit loc t$ $lid:p$ :: $make_args l$ ] >>
| _::l -> make_args l
let rec make_eval_tactic e = function
| [] -> e
| TacNonTerm(loc,tag,_,Some p)::l when Pcoq.is_tactic_genarg tag ->
let loc = join_loc loc (MLast.loc_of_expr e) in
let e = make_eval_tactic e l in
(* Special case for tactics which must be stored in algebraic
form to avoid marshalling closures and to be reprinted *)
<:expr< let $lid:p$ = ($lid:p$,Tacinterp.eval_tactic $lid:p$) in $e$ >>
| _::l -> make_eval_tactic e l
let rec make_fun e = function
| [] -> e
| TacNonTerm(loc,_,_,Some p)::l ->
<:expr< fun $lid:p$ -> $make_fun e l$ >>
| _::l -> make_fun e l
let mlexpr_of_grammar_production = function
| TacTerm s ->
<:expr< Egrammar.TacTerm $mlexpr_of_string s$ >>
| TacNonTerm (loc,nt,g,sopt) ->
<:expr< Egrammar.TacNonTerm $default_loc$ ($g$,$mlexpr_of_argtype loc nt$) $mlexpr_of_option mlexpr_of_string sopt$ >>
let mlexpr_terminals_of_grammar_production = function
| TacTerm s -> <:expr< Some $mlexpr_of_string s$ >>
| TacNonTerm (loc,nt,g,sopt) -> <:expr< None >>
let mlexpr_of_clause =
mlexpr_of_list (fun (a,b) -> mlexpr_of_list mlexpr_of_grammar_production a)
let rec make_tags loc = function
| [] -> <:expr< [] >>
| TacNonTerm(loc',t,_,Some p)::l ->
let l = make_tags loc l in
let loc = join_loc loc' loc in
let t = mlexpr_of_argtype loc' t in
<:expr< [ $t$ :: $l$ ] >>
| _::l -> make_tags loc l
let make_one_printing_rule se (pt,e) =
let level = mlexpr_of_int 0 in (* only level 0 supported here *)
let loc = MLast.loc_of_expr e in
let prods = mlexpr_of_list mlexpr_terminals_of_grammar_production pt in
<:expr< ($se$, $make_tags loc pt$, ($level$, $prods$)) >>
let make_printing_rule se = mlexpr_of_list (make_one_printing_rule se)
let rec contains_epsilon = function
| List0ArgType _ -> true
| List1ArgType t -> contains_epsilon t
| OptArgType _ -> true
| PairArgType(t1,t2) -> contains_epsilon t1 && contains_epsilon t2
| ExtraArgType("hintbases") -> true
| _ -> false
let is_atomic = function
| TacTerm s :: l when
List.for_all (function
TacTerm _ -> false
| TacNonTerm(_,t,_,_) -> contains_epsilon t) l
-> [s]
| _ -> []
let declare_tactic loc s cl =
let se = mlexpr_of_string s in
let pp = make_printing_rule se cl in
let gl = mlexpr_of_clause cl in
let hide_tac (p,e) =
(* reste a definir les fonctions cachees avec des noms frais *)
let stac = "h_"^s in
let e =
make_fun
<:expr<
Refiner.abstract_extended_tactic $mlexpr_of_string s$ $make_args p$ $make_eval_tactic e p$
>>
p in
<:str_item< value $lid:stac$ = $e$ >>
in
let hidden = if List.length cl = 1 then List.map hide_tac cl else [] in
let atomic_tactics =
mlexpr_of_list mlexpr_of_string
(List.flatten (List.map (fun (al,_) -> is_atomic al) cl)) in
<:str_item<
declare
open Pcoq;
declare $list:hidden$ end;
try
let _=Tacinterp.add_tactic $se$ (fun [ $list:make_clauses s cl$ ]) in
List.iter
(fun s -> Tacinterp.add_primitive_tactic s
(Tacexpr.TacAtom($default_loc$,
Tacexpr.TacExtend($default_loc$,s,[]))))
$atomic_tactics$
with e -> Pp.pp (Cerrors.explain_exn e);
Egrammar.extend_tactic_grammar $se$ $gl$;
List.iter Pptactic.declare_extra_tactic_pprule $pp$;
end
>>
open Pcaml
EXTEND
GLOBAL: str_item;
str_item:
[ [ "TACTIC"; "EXTEND"; s = [ UIDENT | LIDENT ];
OPT "|"; l = LIST1 tacrule SEP "|";
"END" ->
declare_tactic loc s l ] ]
;
tacrule:
[ [ "["; l = LIST1 tacargs; "]"; "->"; "["; e = Pcaml.expr; "]"
->
if match List.hd l with TacNonTerm _ -> true | _ -> false then
(* En attendant la syntaxe de tacticielles *)
failwith "Tactic syntax must start with an identifier";
(l,e)
] ]
;
tacargs:
[ [ e = LIDENT; "("; s = LIDENT; ")" ->
let t, g = Q_util.interp_entry_name loc e "" in
TacNonTerm (loc, t, g, Some s)
| e = LIDENT; "("; s = LIDENT; ","; sep = STRING; ")" ->
let t, g = Q_util.interp_entry_name loc e sep in
TacNonTerm (loc, t, g, Some s)
| s = STRING ->
if s = "" then Util.user_err_loc (loc,"",Pp.str "Empty terminal.");
TacTerm s
] ]
;
END
|