diff options
| author | Hugo Herbelin | 2017-11-25 17:19:49 +0100 |
|---|---|---|
| committer | Hugo Herbelin | 2018-07-29 02:40:22 +0200 |
| commit | 60daf674df3d11fa2948bbc7c9a928c09f22d099 (patch) | |
| tree | 533584dd6acd3bde940529e8d3a111eca6fcbdef /vernac/egramcoq.ml | |
| parent | 33d86118c7d1bfba31008b410d81c7f45dbdf092 (diff) | |
Adding support for custom entries in notations.
- New command "Declare Custom Entry bar".
- Entries can have levels.
- Printing is done using a notion of coercion between grammar
entries. This typically corresponds to rules of the form
'Notation "[ x ]" := x (x custom myconstr).' but also
'Notation "{ x }" := x (in custom myconstr, x constr).'.
- Rules declaring idents such as 'Notation "x" := x (in custom myconstr, x ident).'
are natively recognized.
- Rules declaring globals such as 'Notation "x" := x (in custom myconstr, x global).'
are natively recognized.
Incidentally merging ETConstr and ETConstrAsBinder.
Noticed in passing that parsing binder as custom was not done as in
constr.
Probably some fine-tuning still to do (priority of notations,
interactions between scopes and entries, ...). To be tested live
further.
Diffstat (limited to 'vernac/egramcoq.ml')
| -rw-r--r-- | vernac/egramcoq.ml | 107 |
1 files changed, 67 insertions, 40 deletions
diff --git a/vernac/egramcoq.ml b/vernac/egramcoq.ml index 3281b75aaa..65e5f4bede 100644 --- a/vernac/egramcoq.ml +++ b/vernac/egramcoq.ml @@ -54,6 +54,17 @@ let default_pattern_levels = let default_constr_levels = (default_levels, default_pattern_levels) +let find_levels levels = function + | InConstrEntry -> levels, String.Map.find "constr" levels + | InCustomEntry s -> + try levels, String.Map.find s levels + with Not_found -> + String.Map.add s ([],[]) levels, ([],[]) + +let save_levels levels custom lev = + let s = match custom with InConstrEntry -> "constr" | InCustomEntry s -> s in + String.Map.add s lev levels + (* At a same level, LeftA takes precedence over RightA and NoneA *) (* In case, several associativity exists for a level, we make two levels, *) (* first LeftA, then RightA and NoneA together *) @@ -125,24 +136,24 @@ let rec list_mem_assoc_triple x = function let register_empty_levels accu forpat levels = let rec filter accu = function | [] -> ([], accu) - | n :: rem -> + | (where,n) :: rem -> let rem, accu = filter accu rem in - let (clev, plev) = accu in + let accu, (clev, plev) = find_levels accu where in let levels = if forpat then plev else clev in if not (list_mem_assoc_triple n levels) then let nlev, ans = find_position_gen levels true None (Some n) in let nlev = if forpat then (clev, nlev) else (nlev, plev) in - ans :: rem, nlev + (where, ans) :: rem, save_levels accu where nlev else rem, accu in filter accu levels -let find_position accu forpat assoc level = - let (clev, plev) = accu in +let find_position accu custom forpat assoc level = + let accu, (clev, plev) = find_levels accu custom in let levels = if forpat then plev else clev in let nlev, ans = find_position_gen levels false assoc level in let nlev = if forpat then (clev, nlev) else (nlev, plev) in - (ans, nlev) + (ans, save_levels accu custom nlev) (**************************************************************************) (* @@ -231,7 +242,7 @@ type (_, _) entry = | TTName : ('self, lname) entry | TTReference : ('self, qualid) entry | TTBigint : ('self, Constrexpr.raw_natural_number) entry -| TTConstr : prod_info * 'r target -> ('r, 'r) entry +| TTConstr : notation_entry * prod_info * 'r target -> ('r, 'r) entry | TTConstrList : prod_info * Tok.t list * 'r target -> ('r, 'r list) entry | TTPattern : int -> ('self, cases_pattern_expr) entry | TTOpenBinderList : ('self, local_binder_expr list) entry @@ -240,16 +251,31 @@ type (_, _) entry = type _ any_entry = TTAny : ('s, 'r) entry -> 's any_entry (* This computes the name of the level where to add a new rule *) -let interp_constr_entry_key : type r. r target -> int -> r Entry.t * int option = - fun forpat level -> match forpat with +let interp_constr_entry_key : type r. _ -> r target -> int -> r Entry.t * int option = + fun custom forpat level -> + match custom with + | InCustomEntry s -> + (let (entry_for_constr, entry_for_patttern) = find_custom_entries s in + match forpat with + | ForConstr -> entry_for_constr, Some level + | ForPattern -> entry_for_patttern, Some level) + | InConstrEntry -> + match forpat with | ForConstr -> if level = 200 then Constr.binder_constr, None else Constr.operconstr, Some level | ForPattern -> Constr.pattern, Some level -let target_entry : type s. s target -> s Entry.t = function -| ForConstr -> Constr.operconstr -| ForPattern -> Constr.pattern +let target_entry : type s. notation_entry -> s target -> s Entry.t = function +| InConstrEntry -> + (function + | ForConstr -> Constr.operconstr + | ForPattern -> Constr.pattern) +| InCustomEntry s -> + let (entry_for_constr, entry_for_patttern) = find_custom_entries s in + function + | ForConstr -> entry_for_constr + | ForPattern -> entry_for_patttern let is_self from e = match e with | (NumLevel n, BorderProd (Right, _ (* Some(NonA|LeftA) *))) -> false @@ -273,11 +299,11 @@ let make_sep_rules = function let r = mkrule (List.rev tkl) in Arules [r] -let symbol_of_target : type s. _ -> _ -> _ -> s target -> (s, s) symbol = fun p assoc from forpat -> - if is_binder_level from p then Aentryl (target_entry forpat, "200") +let symbol_of_target : type s. _ -> _ -> _ -> _ -> s target -> (s, s) symbol = fun custom p assoc from forpat -> + if custom = InConstrEntry && is_binder_level from p then Aentryl (target_entry InConstrEntry forpat, "200") else if is_self from p then Aself else - let g = target_entry forpat in + let g = target_entry custom forpat in let lev = adjust_level assoc from p in begin match lev with | None -> Aentry g @@ -286,11 +312,11 @@ let symbol_of_target : type s. _ -> _ -> _ -> s target -> (s, s) symbol = fun p end let symbol_of_entry : type s r. _ -> _ -> (s, r) entry -> (s, r) symbol = fun assoc from typ -> match typ with -| TTConstr (p, forpat) -> symbol_of_target p assoc from forpat +| TTConstr (s, p, forpat) -> symbol_of_target s p assoc from forpat | TTConstrList (typ', [], forpat) -> - Alist1 (symbol_of_target typ' assoc from forpat) + Alist1 (symbol_of_target InConstrEntry typ' assoc from forpat) | TTConstrList (typ', tkl, forpat) -> - Alist1sep (symbol_of_target typ' assoc from forpat, make_sep_rules tkl) + Alist1sep (symbol_of_target InConstrEntry typ' assoc from forpat, make_sep_rules tkl) | TTPattern p -> Aentryl (Constr.pattern, string_of_int p) | TTClosedBinderList [] -> Alist1 (Aentry Constr.binder) | TTClosedBinderList tkl -> Alist1sep (Aentry Constr.binder, make_sep_rules tkl) @@ -303,9 +329,8 @@ let interp_entry forpat e = match e with | ETProdName -> TTAny TTName | ETProdReference -> TTAny TTReference | ETProdBigint -> TTAny TTBigint -| ETProdConstr p -> TTAny (TTConstr (p, forpat)) +| ETProdConstr (s,p) -> TTAny (TTConstr (s, p, forpat)) | ETProdPattern p -> TTAny (TTPattern p) -| ETProdOther _ -> assert false (** not used *) | ETProdConstrList (p, tkl) -> TTAny (TTConstrList (p, tkl, forpat)) | ETProdBinderList ETBinderOpen -> TTAny TTOpenBinderList | ETProdBinderList (ETBinderClosed tkl) -> TTAny (TTClosedBinderList tkl) @@ -420,21 +445,23 @@ let target_to_bool : type r. r target -> bool = function | ForConstr -> false | ForPattern -> true -let prepare_empty_levels forpat (pos,p4assoc,name,reinit) = +let prepare_empty_levels forpat (where,(pos,p4assoc,name,reinit)) = let empty = (pos, [(name, p4assoc, [])]) in - if forpat then ExtendRule (Constr.pattern, reinit, empty) - else ExtendRule (Constr.operconstr, reinit, empty) - -let rec pure_sublevels : type a b c. int option -> (a, b, c) rule -> int list = fun level r -> match r with -| Stop -> [] -| Next (rem, Aentryl (_, i)) -> - let i = int_of_string i in - let rem = pure_sublevels level rem in - begin match level with - | Some j when Int.equal i j -> rem - | _ -> i :: rem - end -| Next (rem, _) -> pure_sublevels level rem + ExtendRule (target_entry where forpat, reinit, empty) + +let rec pure_sublevels' custom assoc from forpat level = function +| [] -> [] +| GramConstrNonTerminal (e,_) :: rem -> + let rem = pure_sublevels' custom assoc from forpat level rem in + let push where p rem = + match symbol_of_target custom p assoc from forpat with + | Aentryl (_,i) when level <> Some (int_of_string i) -> (where,int_of_string i) :: rem + | _ -> rem in + (match e with + | ETProdPattern i -> push InConstrEntry (NumLevel i,InternalProd) rem + | ETProdConstr (s,p) -> push s p rem + | _ -> rem) +| (GramConstrTerminal _ | GramConstrListMark _) :: rem -> pure_sublevels' custom assoc from forpat level rem let make_act : type r. r target -> _ -> r gen_eval = function | ForConstr -> fun notation loc env -> @@ -445,17 +472,17 @@ let make_act : type r. r target -> _ -> r gen_eval = function CAst.make ~loc @@ CPatNotation (notation, env, []) let extend_constr state forpat ng = - let n,_,_ = ng.notgram_level in + let custom,n,_,_ = ng.notgram_level in let assoc = ng.notgram_assoc in - let (entry, level) = interp_constr_entry_key forpat n in + let (entry, level) = interp_constr_entry_key custom forpat n in let fold (accu, state) pt = let AnyTyRule r = make_ty_rule assoc n forpat pt in let symbs = ty_erase r in - let pure_sublevels = pure_sublevels level symbs in + let pure_sublevels = pure_sublevels' custom assoc n forpat level pt in let isforpat = target_to_bool forpat in let needed_levels, state = register_empty_levels state isforpat pure_sublevels in - let (pos,p4assoc,name,reinit), state = find_position state isforpat assoc level in - let empty_rules = List.map (prepare_empty_levels isforpat) needed_levels in + let (pos,p4assoc,name,reinit), state = find_position state custom isforpat assoc level in + let empty_rules = List.map (prepare_empty_levels forpat) needed_levels in let empty = { constrs = []; constrlists = []; binders = []; binderlists = [] } in let act = ty_eval r (make_act forpat ng.notgram_notation) empty in let rule = (name, p4assoc, [Rule (symbs, act)]) in @@ -468,7 +495,7 @@ let constr_levels = GramState.field () let extend_constr_notation ng state = let levels = match GramState.get state constr_levels with - | None -> default_constr_levels + | None -> String.Map.add "constr" default_constr_levels String.Map.empty | Some lev -> lev in (* Add the notation in constr *) |
