(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open Util open Pp open CErrors open Vernactypes
type vernac_keep_as = VtKeepAxiom | VtKeepDefined | VtKeepOpaque
type vernac_qed_type = VtKeep of vernac_keep_as | VtDrop
type vernac_when =
| VtNow
| VtLater
type vernac_classification = (* Start of a proof *)
| VtStartProof of vernac_start (* Command altering the global state, bad for parallel
processing. *)
| VtSideff of vernac_sideff_type (* End of a proof *)
| VtQed of vernac_qed_type (* A proof step *)
| VtProofStep of {
proof_block_detection : proof_block_name option
} (* Queries are commands assumed to be "pure", that is to say, they
don't modify the interpretation state. *)
| VtQuery (* Commands that change the current proof mode *)
| VtProofMode of Pvernac.proof_mode (* To be removed *)
| VtMeta and vernac_start = opacity_guarantee * Names.Id.t list and vernac_sideff_type = Names.Id.t list * vernac_when and opacity_guarantee =
| GuaranteesOpacity (** Only generates opaque terms at [Qed] *)
| Doesn'tGuaranteeOpacity (** May generate transparent terms even with [Qed].*)
and solving_tac = bool(** a terminator *)
and anon_abstracting_tac = bool(** abstracting anonymously its result *)
and proof_block_name = string(** open type of delimiters *)
type vernac_command = ?loc:Loc.t -> atts:Attributes.vernac_flags -> unit -> typed_vernac
type plugin_args = Genarg.raw_generic_argument list
(* Table of vernac entries *) let vernac_tab =
(Hashtbl.create 211 :
(Vernacexpr.extend_name, bool * (plugin_args -> vernac_command)) Hashtbl.t)
let vinterp_add depr s f = Hashtbl.replace vernac_tab s (depr, f)
let vinterp_map s = try
Hashtbl.find vernac_tab s with Not_found ->
user_err
(str"Cannot find vernac command " ++ str s.ext_entry ++ str".")
let warn_deprecated_command = letopen CWarnings in
create ~name:"deprecated-command" ~category:CWarnings.CoreCategories.deprecated
(fun pr -> str "Deprecated vernacular command: " ++ pr)
(* Interpretation of a vernac command *)
let type_vernac opn converted_args ?loc ~atts = let depr, callback = vinterp_map opn in let () = if depr then let rules = Egramml.get_extend_vernac_rule opn in let pr_gram = function
| Egramml.GramTerminal s -> str s
| Egramml.GramNonTerminal _ -> str "_" in let pr = pr_sequence pr_gram rules in
warn_deprecated_command pr; in
callback converted_args ?loc ~atts
(** VERNAC EXTEND registering *)
type classifier =
Genarg.raw_generic_argument list ->
atts:Attributes.vernac_flags ->
vernac_classification
(** Classifiers *)
module StringPair = struct type t = string * string let compare (s1, s2) (t1, t2) = let c = String.compare s1 t1 in if Int.equal c 0 thenString.compare s2 t2 else c end
module StringPairMap = Map.Make(StringPair)
let classifiers : classifier array StringPairMap.t ref = ref StringPairMap.empty
let get_vernac_classifier e args = letopen Vernacexpr in
(StringPairMap.find (e.ext_plugin, e.ext_entry) !classifiers).(e.ext_index) args
let declare_vernac_classifier name f =
classifiers := StringPairMap.add name f !classifiers
let classify_as_query = VtQuery let classify_as_sideeff = VtSideff ([], VtLater) let classify_as_proofstep = VtProofStep { proof_block_detection = None}
let type_error () = CErrors.anomaly (Pp.str "Ill-typed VERNAC EXTEND")
let rec untype_classifier : type r s. (r, s) ty_sig -> s -> classifier = function
| TyNil -> fun f args -> beginmatch args with
| [] -> f
| _ :: _ -> type_error () end
| TyTerminal (_, ty) -> fun f args -> untype_classifier ty f args
| TyNonTerminal (tu, ty) -> fun f args -> letopen Genarg in beginmatch args with
| [] -> type_error ()
| GenArg (Rawwit tag, v) :: args -> match Genarg.genarg_type_eq tag (Egramml.proj_symbol tu) with
| None -> type_error ()
| Some Refl -> untype_classifier ty (f v) args end
(** Stupid GADTs forces us to duplicate the definition just for typing *) let rec untype_command : type r s. (r, s) ty_sig -> r -> plugin_args -> vernac_command = function
| TyNil -> fun f args -> beginmatch args with
| [] -> f
| _ :: _ -> type_error () end
| TyTerminal (_, ty) -> fun f args -> untype_command ty f args
| TyNonTerminal (tu, ty) -> fun f args -> letopen Genarg in beginmatch args with
| [] -> type_error ()
| GenArg (Rawwit tag, v) :: args -> match genarg_type_eq tag (Egramml.proj_symbol tu) with
| None -> type_error ()
| Some Refl -> untype_command ty (f v) args end
let rec untype_user_symbol : type s a b c. (a, b, c) Extend.ty_user_symbol -> (s, Gramlib.Grammar.norec, a) Procq.Symbol.t = letopen Extend in function
| TUlist1 l -> Procq.Symbol.list1 (untype_user_symbol l)
| TUlist1sep (l, s) -> Procq.Symbol.list1sep (untype_user_symbol l) (Procq.Symbol.tokens [Procq.TPattern (Procq.terminal s)]) false
| TUlist0 l -> Procq.Symbol.list0 (untype_user_symbol l)
| TUlist0sep (l, s) -> Procq.Symbol.list0sep (untype_user_symbol l) (Procq.Symbol.tokens [Procq.TPattern (Procq.terminal s)]) false
| TUopt o -> Procq.Symbol.opt (untype_user_symbol o)
| TUentry a -> Procq.Symbol.nterm (Procq.genarg_grammar (Genarg.ExtraArg a))
| TUentryl (a, i) -> Procq.Symbol.nterml (Procq.genarg_grammar (Genarg.ExtraArg a)) (string_of_int i)
let rec untype_grammar : type r s. (r, s) ty_sig -> 'a Egramml.grammar_prod_item list = function
| TyNil -> []
| TyTerminal (tok, ty) -> Egramml.GramTerminal tok :: untype_grammar ty
| TyNonTerminal (tu, ty) -> let t = Genarg.rawwit (Egramml.proj_symbol tu) in let symb = untype_user_symbol tu in
Egramml.GramNonTerminal (Loc.tag (t, symb)) :: untype_grammar ty
let declare_dynamic_vernac_extend ~command ?entry ~depr cl ty f = let cl = untype_classifier ty cl in let f = untype_command ty f in let r = untype_grammar ty in let ext = { command with Vernacexpr.ext_index = 0 } in
vinterp_add depr ext f;
Egramml.declare_vernac_command_grammar ~allow_override:true ext entry r;
declare_vernac_classifier (ext.ext_plugin, ext.ext_entry) [|cl|];
ext
let is_static_linking_done = reffalse
let static_linking_done () = is_static_linking_done := true
let static_vernac_extend ~plugin ~command ?classifier ?entry ext = let get_classifier (TyML (_, ty, _, cl)) = match cl with
| Some cl -> untype_classifier ty cl
| None -> match classifier with
| Some cl -> fun _ ~atts -> cl ~atts command
| None -> let e = match entry with
| None -> "COMMAND"
| Some e -> Procq.Entry.name e in let msg = Printf.sprintf "\
Vernac entry \"%s\" misses a classifier. \
A classifier is a function that returns an expression \ oftype vernac_classification (see Vernacexpr). You can: \n\
- Use '... EXTEND %s CLASSIFIED AS QUERY ...'if the \
new vernacular command does not alter the system state;\n\
- Use '... EXTEND %s CLASSIFIED AS SIDEFF ...'if the \
new vernacular command alters the system state but not the \
parser nor it starts a proof or ends one;\n\
- Use '... EXTEND %s CLASSIFIED BY f ...' to specify \
a global function f. The function f will be called passing\
\"%s\" as the only argument;\n\
- Add a specific classifier in each clause using the syntax:\n\ '[...] => [ f ] -> [...]'.\n\
Specific classifiers have precedence over global \
classifiers. Only one classifier is called."
command e e e command in
CErrors.user_err (Pp.strbrk msg) in let cl = Array.map_of_list get_classifier ext in let ext_plugin = Option.default "__" plugin in let iter i (TyML (depr, ty, f, _)) = let f = untype_command ty f in let r = untype_grammar ty in let ext = Vernacexpr.{ ext_plugin; ext_entry = command; ext_index = i } in let () = vinterp_add depr ext f in let () = Egramml.declare_vernac_command_grammar ~allow_override:false ext entry r in let () = match plugin with
| None -> let () = if !is_static_linking_done then CErrors.anomaly
Pp.(str "static_vernac_extend in dynlinked code must pass non-None plugin.") in
Egramml.extend_vernac_command_grammar ~undoable:false ext
| Some plugin ->
Mltop.add_init_function plugin (fun () ->
Egramml.extend_vernac_command_grammar ~undoable:true ext) in
() in let () = declare_vernac_classifier (ext_plugin, command) cl in let () = List.iteri iter ext in
()
type'a vernac_argument = {
arg_printer : Environ.env -> Evd.evar_map -> 'a -> Pp.t;
arg_parsing : 'a argument_rule;
}
let vernac_argument_extend ~plugin ~name arg = let wit = Genarg.create_arg name in let entry = match arg.arg_parsing with
| Arg_alias e -> let () = Procq.register_grammar wit e in
e
| Arg_rules rules -> let e = Procq.create_generic_entry2 name (Genarg.rawwit wit) in let plugin_uid = Option.map (fun plugin -> (plugin, "vernacargextend:"^name)) plugin in let () = Egramml.grammar_extend ?plugin_uid e
(Procq.Fresh (Gramlib.Gramext.First, [None, None, rules])) in
e in let pr = arg.arg_printer in let pr x = Genprint.PrinterBasic (fun env sigma -> pr env sigma x) in let () = Genprint.register_vernac_print0 wit pr in
(wit, entry)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.