aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.depend18
-rw-r--r--Makefile3
-rw-r--r--proofs/macros.ml87
-rw-r--r--proofs/macros.mli22
-rw-r--r--proofs/tacinterp.ml156
-rw-r--r--proofs/tacinterp.mli24
6 files changed, 309 insertions, 1 deletions
diff --git a/.depend b/.depend
index 479b721ed..115808b2f 100644
--- a/.depend
+++ b/.depend
@@ -58,12 +58,16 @@ proofs/evar_refiner.cmi: kernel/environ.cmi kernel/evd.cmi kernel/names.cmi \
proofs/proof_trees.cmi proofs/refiner.cmi kernel/sign.cmi kernel/term.cmi
proofs/logic.cmi: kernel/environ.cmi kernel/evd.cmi kernel/names.cmi \
proofs/proof_trees.cmi kernel/sign.cmi kernel/term.cmi
+proofs/macros.cmi: parsing/ast.cmi parsing/coqast.cmi kernel/names.cmi \
+ proofs/proof_trees.cmi proofs/tacmach.cmi
proofs/pfedit.cmi: library/declare.cmi lib/pp.cmi proofs/proof_trees.cmi \
proofs/refiner.cmi kernel/sign.cmi
proofs/proof_trees.cmi: parsing/coqast.cmi kernel/environ.cmi kernel/evd.cmi \
kernel/names.cmi kernel/sign.cmi lib/stamps.cmi kernel/term.cmi \
lib/util.cmi
proofs/refiner.cmi: proofs/proof_trees.cmi kernel/sign.cmi kernel/term.cmi
+proofs/tacinterp.cmi: parsing/coqast.cmi kernel/names.cmi lib/pp.cmi \
+ proofs/proof_trees.cmi proofs/tacmach.cmi kernel/term.cmi
proofs/tacmach.cmi: kernel/environ.cmi proofs/evar_refiner.cmi \
kernel/names.cmi proofs/proof_trees.cmi kernel/reduction.cmi \
proofs/refiner.cmi kernel/sign.cmi proofs/tacred.cmi kernel/term.cmi
@@ -285,6 +289,14 @@ proofs/logic.cmx: parsing/coqast.cmx library/declare.cmx kernel/environ.cmx \
lib/pp.cmx proofs/proof_trees.cmx kernel/reduction.cmx kernel/sign.cmx \
kernel/term.cmx kernel/typeops.cmx kernel/typing.cmx proofs/typing_ev.cmx \
lib/util.cmx proofs/logic.cmi
+proofs/macros.cmo: parsing/ast.cmi parsing/coqast.cmi library/lib.cmi \
+ library/libobject.cmi library/library.cmi kernel/names.cmi \
+ parsing/pcoq.cmi lib/pp.cmi proofs/proof_trees.cmi library/summary.cmi \
+ kernel/term.cmi lib/util.cmi proofs/macros.cmi
+proofs/macros.cmx: parsing/ast.cmx parsing/coqast.cmx library/lib.cmx \
+ library/libobject.cmx library/library.cmx kernel/names.cmx \
+ parsing/pcoq.cmi lib/pp.cmx proofs/proof_trees.cmx library/summary.cmx \
+ kernel/term.cmx lib/util.cmx proofs/macros.cmi
proofs/proof_trees.cmo: parsing/coqast.cmi kernel/environ.cmi kernel/evd.cmi \
kernel/names.cmi kernel/sign.cmi lib/stamps.cmi kernel/term.cmi \
lib/util.cmi proofs/proof_trees.cmi
@@ -299,6 +311,12 @@ proofs/refiner.cmx: kernel/environ.cmx kernel/evd.cmx kernel/generic.cmx \
kernel/instantiate.cmx proofs/logic.cmx lib/pp.cmx proofs/proof_trees.cmx \
kernel/reduction.cmx kernel/sign.cmx lib/stamps.cmx kernel/term.cmx \
lib/util.cmx proofs/refiner.cmi
+proofs/tacinterp.cmo: parsing/ast.cmi parsing/coqast.cmi proofs/macros.cmi \
+ kernel/names.cmi lib/pp.cmi proofs/proof_trees.cmi proofs/tacmach.cmi \
+ kernel/term.cmi lib/util.cmi proofs/tacinterp.cmi
+proofs/tacinterp.cmx: parsing/ast.cmx parsing/coqast.cmx proofs/macros.cmx \
+ kernel/names.cmx lib/pp.cmx proofs/proof_trees.cmx proofs/tacmach.cmx \
+ kernel/term.cmx lib/util.cmx proofs/tacinterp.cmi
proofs/tacmach.cmo: parsing/ast.cmi kernel/environ.cmi \
proofs/evar_refiner.cmi kernel/evd.cmi kernel/generic.cmi \
kernel/instantiate.cmi proofs/logic.cmi kernel/names.cmi \
diff --git a/Makefile b/Makefile
index 801dc63e6..81fab7c76 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,8 @@ LIBRARY=library/libobject.cmo library/summary.cmo library/lib.cmo \
PROOFS=proofs/typing_ev.cmo proofs/tacred.cmo \
proofs/proof_trees.cmo proofs/logic.cmo \
- proofs/refiner.cmo proofs/evar_refiner.cmo proofs/clenv.cmo
+ proofs/refiner.cmo proofs/evar_refiner.cmo \
+ proofs/macros.cmo proofs/tacinterp.cmo proofs/clenv.cmo
PARSING=parsing/lexer.cmo parsing/coqast.cmo parsing/pcoq.cmo parsing/ast.cmo \
parsing/g_prim.cmo parsing/g_basevernac.cmo parsing/g_vernac.cmo \
diff --git a/proofs/macros.ml b/proofs/macros.ml
new file mode 100644
index 000000000..de6132f36
--- /dev/null
+++ b/proofs/macros.ml
@@ -0,0 +1,87 @@
+
+(* $Id$ *)
+
+open Pp
+open Util
+open Names
+open Term
+open Proof_trees
+open Libobject
+open Library
+open Coqast
+open Pcoq
+open Ast
+
+(* The data stored in the table *)
+
+type macro_data = {
+ mac_args : string list;
+ mac_body : Ast.act }
+
+(* Summary and Object declaration *)
+
+type t = macro_data Stringmap.t
+type frozen_t = macro_data Stringmap.t
+
+let mactab = ref Stringmap.empty
+
+let lookup id = Stringmap.find id !mactab
+
+let _ =
+ let init () = mactab := Stringmap.empty in
+ let freeze () = !mactab in
+ let unfreeze fs = mactab := fs in
+ Summary.declare_summary "tactic-macro"
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init }
+
+let (inMD,outMD) =
+ let add (na,md) = mactab := Stringmap.add na md !mactab in
+ let cache_md (_,(na,md)) = add (na,md) in
+ let specification_md x = x in
+ declare_object ("TACTIC-MACRO-DATA",
+ { cache_function = cache_md;
+ load_function = (fun _ -> ());
+ open_function = (fun _ -> ());
+ specification_function = specification_md })
+
+let add_macro_hint na (ids,body) =
+ if Stringmap.mem na !mactab then errorlabstrm "add_macro_hint"
+ [< 'sTR "There is already a Tactic Macro named "; 'sTR na >];
+ let _ = Lib.add_leaf (id_of_string na) OBJ
+ (inMD(na,{mac_args = ids; mac_body = body})) in
+ ()
+
+let macro_expand macro_loc macro argcoms =
+ let md =
+ try
+ lookup macro
+ with Not_found ->
+ user_err_loc(macro_loc,"macro_expand",
+ [< 'sTR"Tactic macro ";'sTR macro; 'sPC;
+ 'sTR"not defined" >])
+ in
+ let transform =
+ List.map
+ (function
+ | Command c -> c
+ | _ -> user_err_loc(macro_loc,"macro_expand",
+ [<'sTR "The arguments of a tactic macro";
+ 'sPC; 'sTR"must be terms">]))
+ in
+ let argcoms = transform argcoms in
+ if List.length argcoms <> List.length md.mac_args then
+ user_err_loc
+ (macro_loc,"macro_expand",
+ [< 'sTR "Tactic macro "; 'sTR macro; 'sPC;
+ 'sTR "applied to the wrong number of arguments:"; 'sPC;
+ 'iNT (List.length argcoms) ; 'sTR" instead of ";
+ 'iNT (List.length md.mac_args) >]);
+ let astb =
+ List.map2 (fun id argcom -> (id, Vast argcom)) md.mac_args argcoms in
+ match Ast.eval_act macro_loc astb md.mac_body with
+ | Vast ast -> ast
+ | _ -> anomaly "expand_macro : eval_act did not return a Vast"
+
+
diff --git a/proofs/macros.mli b/proofs/macros.mli
new file mode 100644
index 000000000..c62f13c76
--- /dev/null
+++ b/proofs/macros.mli
@@ -0,0 +1,22 @@
+
+(* $Id$ *)
+
+(*i*)
+open Names
+open Tacmach
+open Proof_trees
+(*i*)
+
+(* This file contains the table of macro tactics. The body of the
+ defined tactics is stored as an ast with variables, which are
+ substituted by the real arguments at calling time.
+ User defined tactics are stored in a separate table so that they
+ are sensible to the Reset and Require commands. *)
+
+type macro_data = {
+ mac_args : string list;
+ mac_body : Ast.act }
+
+val add_macro_hint : string -> string list * Ast.act -> unit
+val lookup : string -> macro_data
+val macro_expand : Coqast.loc -> string -> tactic_arg list -> Coqast.t
diff --git a/proofs/tacinterp.ml b/proofs/tacinterp.ml
new file mode 100644
index 000000000..3413b2a61
--- /dev/null
+++ b/proofs/tacinterp.ml
@@ -0,0 +1,156 @@
+
+(* $Id$ *)
+
+open Pp
+open Util
+open Names
+open Term
+open Proof_trees
+open Tacmach
+open Macros
+open Coqast
+open Ast
+
+
+let tactic_tab =
+ (Hashtbl.create 17 : (string, tactic_arg list -> tactic) Hashtbl.t)
+
+let tacinterp_add (s,f) =
+ try
+ Hashtbl.add tactic_tab s f
+ with Failure _ ->
+ errorlabstrm "tacinterp_add"
+ [< 'sTR"Cannot add the tactic " ; 'sTR s ; 'sTR" twice" >]
+
+let overwriting_tacinterp_add (s,f) =
+ if Hashtbl.mem tactic_tab s then begin
+ Hashtbl.remove tactic_tab s;
+ warning ("Overwriting definition of tactic interpreter command "^s)
+ end;
+ Hashtbl.add tactic_tab s f
+
+let tacinterp_init () = Hashtbl.clear tactic_tab
+
+let tacinterp_map s = Hashtbl.find tactic_tab s
+
+let err_msg_tactic_not_found macro_loc macro =
+ user_err_loc
+ (macro_loc,"macro_expand",
+ [< 'sTR"Tactic macro ";'sTR macro; 'sPC; 'sTR"not found" >])
+
+let cvt_bind = function
+ | Node(_,"BINDING", [Num(_,n); Node(_,"COMMAND",[c])]) -> (NoDep n,c)
+ | Node(_,"BINDING", [Nvar(_,s); Node(_,"COMMAND",[c])]) ->
+ let id = id_of_string s in (Dep id,c)
+ | Node(_,"BINDING", [Node(_,"COMMAND",[c])]) -> (Com,c)
+ | x -> errorlabstrm "cvt_bind"
+ [< 'sTR "Not the expected form in binding!"; print_ast x >]
+
+let rec cvt_intro_pattern = function
+ | Node(_,"IDENTIFIER", [Nvar(_,s)]) -> IdPat (id_of_string s)
+ | Node(_,"DISJPATTERN", l) -> DisjPat (List.map cvt_intro_pattern l)
+ | Node(_,"CONJPATTERN", l) -> ConjPat (List.map cvt_intro_pattern l)
+ | Node(_,"LISTPATTERN", l) -> ListPat (List.map cvt_intro_pattern l)
+ | x -> errorlabstrm "cvt_intro_pattern"
+ [< 'sTR "Not the expected form for an introduction pattern!";
+ print_ast x >]
+
+let cvt_letpattern (o,l) = function
+ | Node(_,"HYPPATTERN", Nvar(_,s)::nums) ->
+ (o, (id_of_string s, List.map num_of_ast nums)::l)
+ | Node(_,"CCLPATTERN", nums) ->
+ if o<>None then error "\"Goal\" occurs twice"
+ else (Some (List.map num_of_ast nums), l)
+ | arg ->
+ invalid_arg_loc (Ast.loc arg,"cvt_hyppattern")
+
+let cvt_letpatterns astl = List.fold_left cvt_letpattern (None,[]) astl
+
+let cvt_arg = function
+ | Nvar(_,s) ->
+ Identifier (id_of_string s)
+ | Str(_,s) ->
+ Quoted_string s
+ | Num(_,n) ->
+ Integer n
+ | Node(_,"COMMAND",[c]) ->
+ Command c
+ | Node(_,"BINDINGS",astl) ->
+ Bindings (List.map cvt_bind astl)
+ | Node(_,"REDEXP",[Node(_,redname,args)]) ->
+ Redexp (redname,args)
+ | Node(_,"CLAUSE",cl) ->
+ Clause (List.map (compose id_of_string nvar_of_ast) cl)
+ | Node(_,"TACTIC",[ast]) ->
+ Tacexp ast
+ | Node(_,"FIXEXP", [Nvar(_,s); Num(_,n);Node(_,"COMMAND",[c])]) ->
+ Fixexp (id_of_string s,n,c)
+ | Node(_,"COFIXEXP", [Nvar(_,s); Node(_,"COMMAND",[c])]) ->
+ Cofixexp (id_of_string s,c)
+ | Node(_,"INTROPATTERN", [ast]) ->
+ Intropattern (cvt_intro_pattern ast)
+ | Node(_,"LETPATTERNS", astl) ->
+ let (o,l) = (cvt_letpatterns astl) in Letpatterns (o,l)
+ | x ->
+ anomaly_loc (Ast.loc x, "Tacinterp.cvt_bind",
+ [< 'sTR "Unrecognizable ast node : "; print_ast x >])
+
+let rec interp = function
+ | Node(loc,opn,tl) ->
+ (match (opn, tl) with
+ | ("TACTICLIST",_) -> interp_semi_list tclIDTAC tl
+ | ("DO",[n;tac]) -> tclDO (num_of_ast n) (interp tac)
+ | ("TRY",[tac]) -> tclTRY (interp tac)
+ | ("INFO",[tac]) -> tclINFO (interp tac)
+ | ("REPEAT",[tac]) -> tclREPEAT (interp tac)
+ | ("ORELSE",[tac1;tac2]) -> tclORELSE (interp tac1) (interp tac2)
+ | ("FIRST",l) -> tclFIRST (List.map interp l)
+ | ("TCLSOLVE",l) -> tclSOLVE (List.map interp l)
+ | ("CALL",macro::args) ->
+ interp (macro_expand loc (nvar_of_ast macro)
+ (List.map cvt_arg args))
+ | _ -> interp_atomic loc opn (List.map cvt_arg tl))
+ | ast -> user_err_loc(Ast.loc ast,"Tacinterp.interp",
+ [< 'sTR"A non-ASTnode constructor was found" >])
+
+and interp_atomic loc opn args =
+ try
+ tacinterp_map opn args
+ with Not_found ->
+ try
+ vernac_tactic(opn,args)
+ with e ->
+ Stdpp.raise_with_loc loc e
+
+and interp_semi_list acc = function
+ | (Node(_,"TACLIST",seq))::l ->
+ interp_semi_list (tclTHENS acc (List.map interp seq)) l
+ | t::l -> interp_semi_list (tclTHEN acc (interp t)) l
+ | [] -> acc
+
+
+let is_just_undef_macro ast =
+ match ast with
+ | Node(_,"TACTICLIST",[Node(loc,"CALL",macro::_)]) ->
+ let id = nvar_of_ast macro in
+ (try let _ = Macros.lookup id in None with Not_found -> Some id)
+ | _ -> None
+
+let vernac_interp =
+ let gentac =
+ hide_tactic "Interpret"
+ (fun vargs gl -> match vargs with
+ | [Tacexp com] -> interp com gl
+ | _ -> assert false)
+ in
+ fun com -> gentac [Tacexp com]
+
+let vernac_interp_atomic =
+ let gentac =
+ hide_tactic "InterpretAtomic"
+ (fun argl gl -> match argl with
+ | (Identifier id)::args ->
+ interp_atomic dummy_loc (string_of_id id) args gl
+ | _ -> assert false)
+ in
+ fun opn args -> gentac ((Identifier opn)::args)
diff --git a/proofs/tacinterp.mli b/proofs/tacinterp.mli
new file mode 100644
index 000000000..5dbad5176
--- /dev/null
+++ b/proofs/tacinterp.mli
@@ -0,0 +1,24 @@
+
+(* $Id$ *)
+
+(*i*)
+open Pp
+open Names
+open Proof_trees
+open Tacmach
+open Term
+(*i*)
+
+(* Interpretation of tactics. *)
+
+val tacinterp_add : string * (tactic_arg list -> tactic) -> unit
+val tacinterp_map : string -> tactic_arg list -> tactic
+val tacinterp_init : unit -> unit
+val interp : Coqast.t -> tactic
+val interp_atomic : Coqast.loc -> string -> tactic_arg list -> tactic
+val interp_semi_list : tactic -> Coqast.t list -> tactic
+val vernac_interp : Coqast.t -> tactic
+val vernac_interp_atomic : identifier -> tactic_arg list -> tactic
+val overwriting_tacinterp_add : string * (tactic_arg list -> tactic) -> unit
+val is_just_undef_macro : Coqast.t -> string option
+