diff options
Diffstat (limited to 'toplevel/metasyntax.ml')
-rw-r--r-- | toplevel/metasyntax.ml | 1100 |
1 files changed, 312 insertions, 788 deletions
diff --git a/toplevel/metasyntax.ml b/toplevel/metasyntax.ml index 4c554209..92ce6e36 100644 --- a/toplevel/metasyntax.ml +++ b/toplevel/metasyntax.ml @@ -6,120 +6,27 @@ (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) -(* $Id: metasyntax.ml,v 1.105.2.12 2006/01/04 20:31:16 herbelin Exp $ *) +(* $Id: metasyntax.ml 7822 2006-01-08 17:14:56Z herbelin $ *) open Pp open Util open Names open Topconstr -open Coqast -open Ast open Ppextend open Extend -open Esyntax open Libobject -open Library open Summary open Constrintern open Vernacexpr open Pcoq open Rawterm open Libnames - -let interp_global_rawconstr_with_vars vars c = - interp_rawconstr_gen false Evd.empty (Global.env()) false (vars,[]) c - -(**********************************************************************) -(* Parsing via ast (used in Zsyntax) *) - -(* This updates default parsers for Grammar actions and Syntax *) -(* patterns by inserting globalization *) -(* Done here to get parsing/g_*.ml4 non dependent from kernel *) -let constr_to_ast a = - Termast.ast_of_rawconstr (interp_rawconstr Evd.empty (Global.env()) a) - -(* This installs default quotations parsers to escape the ast parser *) -(* "constr" is used by default in quotations found in the ast parser *) -let constr_parser_with_glob = Pcoq.map_entry constr_to_ast Constr.constr - -let _ = define_ast_quotation true "constr" constr_parser_with_glob +open Lexer +open Egrammar +open Notation (**********************************************************************) -(* Globalisation for constr_expr *) - -let globalize_ref vars ref = - match Constrintern.interp_reference (vars,[]) ref with - | RRef (loc,VarRef a) -> Ident (loc,a) - | RRef (loc,a) -> Qualid (loc,qualid_of_sp (Nametab.sp_of_global a)) - | RVar (loc,x) -> Ident (loc,x) - | _ -> anomaly "globalize_ref: not a reference" - -let globalize_ref_term vars ref = - match Constrintern.interp_reference (vars,[]) ref with - | RRef (loc,VarRef a) -> CRef (Ident (loc,a)) - | RRef (loc,a) -> CRef (Qualid (loc,qualid_of_sp (Nametab.sp_of_global a))) - | RVar (loc,x) -> CRef (Ident (loc,x)) - | c -> Constrextern.extern_rawconstr Idset.empty c - -let rec globalize_constr_expr vars = function - | CRef ref -> globalize_ref_term vars ref - | CAppExpl (_,(p,ref),l) -> - let f = - map_constr_expr_with_binders globalize_constr_expr - (fun x e -> e) vars - in - CAppExpl (dummy_loc,(p,globalize_ref vars ref), List.map f l) - | c -> - map_constr_expr_with_binders globalize_constr_expr (fun id e -> id::e) - vars c - -let without_translation f x = - let old = Options.do_translate () in - let oldv7 = !Options.v7 in - Options.make_translate false; - try let r = f x in Options.make_translate old; Options.v7:=oldv7; r - with e -> Options.make_translate old; Options.v7:=oldv7; raise e - -let _ = set_constr_globalizer - (fun vars e -> for_grammar (without_translation (globalize_constr_expr vars)) e) - -(**********************************************************************) -(** For old ast printer *) - -(* Pretty-printer state summary *) -let _ = - declare_summary "syntax" - { freeze_function = Esyntax.freeze; - unfreeze_function = Esyntax.unfreeze; - init_function = Esyntax.init; - survive_module = false; - survive_section = false } - -(* Pretty-printing objects = syntax_entry *) -let cache_syntax (_,ppobj) = Esyntax.add_ppobject ppobj - -let subst_syntax (_,subst,ppobj) = - Extend.subst_syntax_command Ast.subst_astpat subst ppobj - -let (inPPSyntax,outPPSyntax) = - declare_object {(default_object "PPSYNTAX") with - open_function = (fun i o -> if i=1 then cache_syntax o); - cache_function = cache_syntax; - subst_function = subst_syntax; - classify_function = (fun (_,o) -> Substitute o); - export_function = (fun x -> Some x) } - -(* Syntax extension functions (registered in the environnement) *) - -(* Checking the pretty-printing rules against free meta-variables. - * Note that object are checked before they are added in the environment. - * Syntax objects in compiled modules are not re-checked. *) - -let add_syntax_obj whatfor sel = -(* if not !Options.v7_only then*) - Lib.add_anonymous_leaf (inPPSyntax (interp_syntax_entry whatfor sel)) - -(* Tokens *) +(* Tokens *) let cache_token (_,s) = Pcoq.lexer.Token.using ("", s) @@ -134,69 +41,40 @@ let (inToken, outToken) = let add_token_obj s = Lib.add_anonymous_leaf (inToken s) (**********************************************************************) -(* Grammars (especially Tactic Notation) *) +(* Tactic Notation *) let make_terminal_status = function | VTerm s -> Some s | VNonTerm _ -> None -let qualified_nterm current_univ = function - | NtQual (univ, en) -> (univ, en) - | NtShort en -> (current_univ, en) - -let rec make_tags = function - | VTerm s :: l -> make_tags l +let rec make_tags lev = function + | VTerm s :: l -> make_tags lev l | VNonTerm (loc, nt, po) :: l -> - let (u,nt) = qualified_nterm "tactic" nt in - let (etyp, _) = Egrammar.interp_entry_name u nt in - etyp :: make_tags l + let (etyp, _) = Egrammar.interp_entry_name lev "tactic" nt in + etyp :: make_tags lev l | [] -> [] -let declare_pprule = function - (* Pretty-printing rules only for Grammar (Tactic Notation) *) - | Egrammar.TacticGrammar (_,pp) -> - let f (s,t,p) = - Pptactic.declare_extra_tactic_pprule true s (t,p); - Pptactic.declare_extra_tactic_pprule false s (t,p) in - List.iter f pp - | _ -> () +let cache_tactic_notation (_,(pa,pp)) = + Egrammar.extend_grammar (Egrammar.TacticGrammar pa); + Pptactic.declare_extra_tactic_pprule pp -let cache_grammar (_,a) = - Egrammar.extend_grammar a; - declare_pprule a +let subst_tactic_parule subst (key,n,p,(d,tac)) = + (key,n,p,(d,Tacinterp.subst_tactic subst tac)) -let subst_grammar (_,subst,a) = - Egrammar.subst_all_grammar_command subst a +let subst_tactic_notation (_,subst,(pa,pp)) = + (subst_tactic_parule subst pa,pp) -let (inGrammar, outGrammar) = - declare_object {(default_object "GRAMMAR") with - open_function = (fun i o -> if i=1 then cache_grammar o); - cache_function = cache_grammar; - subst_function = subst_grammar; +let (inTacticGrammar, outTacticGrammar) = + declare_object {(default_object "TacticGrammar") with + open_function = (fun i o -> if i=1 then cache_tactic_notation o); + cache_function = cache_tactic_notation; + subst_function = subst_tactic_notation; classify_function = (fun (_,o) -> Substitute o); export_function = (fun x -> Some x)} -(**********************************************************************) -(* V7 Grammar *) - -open Genarg - -let check_entry_type (u,n) = - if u = "tactic" or u = "vernac" then error "tactic and vernac not supported"; - match entry_type (get_univ u) n with - | None -> Pcoq.create_entry_if_new (get_univ u) n ConstrArgType - | Some (ConstrArgType | IdentArgType | RefArgType) -> () - | _ -> error "Cannot arbitrarily extend non constr/ident/ref entries" - -let add_grammar_obj univ entryl = - let u = create_univ_if_new univ in - let g = interp_grammar_command univ check_entry_type entryl in - Lib.add_anonymous_leaf (inGrammar (Egrammar.Grammar g)) - -(**********************************************************************) -(* V8 Grammar *) - -(* Tactic notations *) +let cons_production_parameter l = function + | VTerm _ -> l + | VNonTerm (_,_,ido) -> option_cons ido l let rec tactic_notation_key = function | VTerm id :: _ -> id @@ -207,41 +85,49 @@ let rec next_key_away key t = if Pptactic.exists_extra_tactic_pprule key t then next_key_away (key^"'") t else key -let locate_tactic_body dir (s,(s',prods as x),e) = - let tags = make_tags prods in - let s = if s="" then next_key_away (tactic_notation_key prods) tags else s in - (s,x,(dir,e)),(s,tags,(s',List.map make_terminal_status prods)) - -let add_tactic_grammar g = - let dir = Lib.cwd () in - let pa,pp = List.split (List.map (locate_tactic_body dir) g) in - Lib.add_anonymous_leaf (inGrammar (Egrammar.TacticGrammar (pa,pp))) - -(* Printing grammar entries *) +let add_tactic_notation (n,prods,e) = + let tags = make_tags n prods in + let key = next_key_away (tactic_notation_key prods) tags in + let pprule = (key,tags,(n,List.map make_terminal_status prods)) in + let ids = List.fold_left cons_production_parameter [] prods in + let tac = Tacinterp.glob_tactic_env ids (Global.env()) e in + let parule = (key,n,prods,(Lib.cwd(),tac)) in + Lib.add_anonymous_leaf (inTacticGrammar (parule,pprule)) -let print_grammar univ entry = - if !Options.v7 then - let u = get_univ univ in - let typ = explicitize_entry (fst u) entry in - let te,_,_ = get_constr_entry false typ in - Gram.Entry.print te - else - match entry with - | "constr" | "operconstr" | "binder_constr" -> - msgnl (str "Entry constr is"); - Gram.Entry.print Pcoq.Constr.constr; - msgnl (str "and lconstr is"); - Gram.Entry.print Pcoq.Constr.lconstr; - msgnl (str "where binder_constr is"); - Gram.Entry.print Pcoq.Constr.binder_constr; - msgnl (str "and operconstr is"); - Gram.Entry.print Pcoq.Constr.operconstr; - | "pattern" -> - Gram.Entry.print Pcoq.Constr.pattern - | "tactic" -> - Gram.Entry.print Pcoq.Tactic.simple_tactic - | _ -> error "Unknown or unprintable grammar entry" +(**********************************************************************) +(* Printing grammar entries *) + +let print_grammar univ = function + | "constr" | "operconstr" | "binder_constr" -> + msgnl (str "Entry constr is"); + Gram.Entry.print Pcoq.Constr.constr; + msgnl (str "and lconstr is"); + Gram.Entry.print Pcoq.Constr.lconstr; + msgnl (str "where binder_constr is"); + Gram.Entry.print Pcoq.Constr.binder_constr; + msgnl (str "and operconstr is"); + Gram.Entry.print Pcoq.Constr.operconstr; + | "pattern" -> + Gram.Entry.print Pcoq.Constr.pattern + | "tactic" -> + msgnl (str "Entry tactic_expr is"); + Gram.Entry.print Pcoq.Tactic.tactic_expr; + msgnl (str "Entry simple_tactic is"); + Gram.Entry.print Pcoq.Tactic.simple_tactic; + | "vernac" -> + msgnl (str "Entry vernac is"); + Gram.Entry.print Pcoq.Vernac_.vernac; + msgnl (str "Entry command is"); + Gram.Entry.print Pcoq.Vernac_.command; + msgnl (str "Entry syntax is"); + Gram.Entry.print Pcoq.Vernac_.syntax; + msgnl (str "Entry gallina is"); + Gram.Entry.print Pcoq.Vernac_.gallina; + msgnl (str "Entry gallina_ext is"); + Gram.Entry.print Pcoq.Vernac_.gallina_ext; + | _ -> error "Unknown or unprintable grammar entry" +(**********************************************************************) (* Parse a format (every terminal starting with a letter or a single quote (except a single quote alone) must be quoted) *) @@ -342,12 +228,12 @@ let parse_format (loc,str) = Stdpp.raise_with_loc loc e (***********************) -(* Analysing notations *) - -open Symbols +(* Analyzing notations *) type symbol_token = WhiteSpace of int | String of string +(* Decompose the notation string into tokens *) + let split_notation_string str = let push_token beg i l = if beg = i then l else @@ -376,6 +262,43 @@ let split_notation_string str = in loop 0 0 +(* Interpret notations with a recursive component *) + +let rec find_pattern xl = function + | Break n as x :: l, Break n' :: l' when n=n' -> + find_pattern (x::xl) (l,l') + | Terminal s as x :: l, Terminal s' :: l' when s = s' -> + find_pattern (x::xl) (l,l') + | [NonTerminal x], NonTerminal x' :: l' -> + (x,x',xl),l' + | [NonTerminal _], Terminal s :: _ | Terminal s :: _, _ -> + error ("The token "^s^" occurs on one side of \"..\" but not on the other side") + | [NonTerminal _], Break s :: _ | Break s :: _, _ -> + error ("A break occurs on one side of \"..\" but not on the other side") + | ((SProdList _ | NonTerminal _) :: _ | []), _ -> + error ("The special symbol \"..\" must occur in a configuration of the form\n\"x symbs .. symbs y\"") + +let rec interp_list_parser hd = function + | [] -> [], List.rev hd + | NonTerminal id :: tl when id = ldots_var -> + let ((x,y,sl),tl') = find_pattern [] (hd,tl) in + let yl,tl'' = interp_list_parser [] tl' in + (* We remember the second copy of each recursive part variable to *) + (* remove it afterwards *) + y::yl, SProdList (x,sl) :: tl'' + | (Terminal _ | Break _) as s :: tl -> + if hd = [] then + let yl,tl' = interp_list_parser [] tl in + yl, s :: tl' + else + interp_list_parser (s::hd) tl + | NonTerminal _ as x :: tl -> + let yl,tl' = interp_list_parser [x] tl in + yl, List.rev_append hd tl' + | SProdList _ :: _ -> anomaly "Unexpected SProdList in interp_list_parser" + +(* Find non-terminal tokens of notation *) + let unquote_notation_token s = let n = String.length s in if n > 2 & s.[0] = '\'' & s.[n-1] = '\'' then String.sub s 1 (n-2) else s @@ -410,38 +333,12 @@ let rec raw_analyse_notation_tokens = function let (vars,l) = raw_analyse_notation_tokens sl in (vars, Break n :: l) -let rec find_pattern xl = function - | Break n as x :: l, Break n' :: l' when n=n' -> - find_pattern (x::xl) (l,l') - | Terminal s as x :: l, Terminal s' :: l' when s = s' -> - find_pattern (x::xl) (l,l') - | [NonTerminal x], NonTerminal x' :: l' -> - (x,x',xl),l' - | [NonTerminal _], Terminal s :: _ | Terminal s :: _, _ -> - error ("The token "^s^" occurs on one side of \"..\" but not on the other side") - | [NonTerminal _], Break s :: _ | Break s :: _, _ -> - error ("A break occurs on one side of \"..\" but not on the other side") - | ((SProdList _ | NonTerminal _) :: _ | []), _ -> - error ("The special symbol \"..\" must occur in a configuration of the form\n\"x symbs .. symbs y\"") - -let rec interp_list_parser hd = function - | [] -> [], List.rev hd - | NonTerminal id :: tl when id = ldots_var -> - let ((x,y,sl),tl') = find_pattern [] (hd,tl) in - let yl,tl'' = interp_list_parser [] tl' in - (* We remember the second copy of each recursive part variable to *) - (* remove it afterwards *) - y::yl, SProdList (x,sl) :: tl'' - | (Terminal _ | Break _) as s :: tl -> - if hd = [] then - let yl,tl' = interp_list_parser [] tl in - yl, s :: tl' - else - interp_list_parser (s::hd) tl - | NonTerminal _ as x :: tl -> - let yl,tl' = interp_list_parser [x] tl in - yl, List.rev_append hd tl' - | SProdList _ :: _ -> anomaly "Unexpected SProdList in interp_list_parser" +let is_numeral symbs = + match List.filter (function Break _ -> false | _ -> true) symbs with + | ([Terminal "-"; Terminal x] | [Terminal x]) -> + (try let _ = Bigint.of_string x in true with _ -> false) + | _ -> + false let analyse_notation_tokens l = let vars,l = raw_analyse_notation_tokens l in @@ -450,7 +347,8 @@ let analyse_notation_tokens l = let remove_vars = List.fold_right List.remove_assoc -(* Build the syntax and grammar rules *) +(**********************************************************************) +(* Build pretty-printing rules *) type printing_precedence = int * parenRelation type parsing_precedence = int option @@ -460,15 +358,10 @@ let prec_assoc = function | Gramext.LeftA -> (E,L) | Gramext.NonA -> (L,L) -(* For old ast printer *) -let meta_pattern m = Pmeta(m,Tany) - -type white_status = Juxtapose | Separate of int | NextIsTerminal - let precedence_of_entry_type from = function | ETConstr (NumLevel n,BorderProd (_,None)) -> n, Prec n - | ETConstr (NumLevel n,BorderProd (left,Some a)) -> - n, let (lp,rp) = prec_assoc a in if left then lp else rp + | ETConstr (NumLevel n,BorderProd (b,Some a)) -> + n, let (lp,rp) = prec_assoc a in if b=Left then lp else rp | ETConstr (NumLevel n,InternalProd) -> n, Prec n | ETConstr (NextLevel,_) -> from, L | ETOther ("constr","annot") -> 10, Prec 10 @@ -506,57 +399,15 @@ let is_operator s = s.[0] = '-' or s.[0] = '/' or s.[0] = '<' or s.[0] = '>' or s.[0] = '@' or s.[0] = '\\' or s.[0] = '&' or s.[0] = '~') -type previous_prod_status = NoBreak | CanBreak - let rec is_non_terminal = function | NonTerminal _ | SProdList _ -> true | _ -> false -let add_break n l = UNP_BRK (n,1) :: l - -(* For old ast printer *) -let make_hunks_ast symbols etyps from = - let rec make ws = function - | NonTerminal m :: prods -> - let _,lp = precedence_of_entry_type from (List.assoc m etyps) in - let u = PH (meta_pattern (string_of_id m), None, lp) in - if prods <> [] && is_non_terminal (List.hd prods) then - u :: add_break 1 (make CanBreak prods) - else - u :: make CanBreak prods - - | Terminal s :: prods when List.exists is_non_terminal prods -> - let protect = - is_letter s.[0] || - (is_non_terminal (List.hd prods) && - (is_letter (s.[String.length s -1])) || - (is_digit (s.[String.length s -1]))) in - if is_comma s || is_right_bracket s then - RO s :: add_break 0 (make NoBreak prods) - else if (is_operator s || is_left_bracket s) && ws = CanBreak then - add_break (if protect then 1 else 0) - (RO (if protect then s^" " else s) :: make CanBreak prods) - else - if protect then - (if ws = CanBreak then add_break 1 else (fun x -> x)) - (RO (s^" ") :: make CanBreak prods) - else - RO s :: make CanBreak prods - - | Terminal s :: prods -> - RO s :: make NoBreak prods - - | Break n :: prods -> - add_break n (make NoBreak prods) - - | SProdList _ :: _ -> - anomaly "Recursive notations not supported in old syntax" - - | [] -> [] +let add_break n l = UnpCut (PpBrk(n,0)) :: l - in make NoBreak symbols +(* Heuristics for building default printing rules *) -let add_break n l = UnpCut (PpBrk(n,0)) :: l +type previous_prod_status = NoBreak | CanBreak let make_hunks etyps symbols from = let vars,typs = List.split etyps in @@ -621,6 +472,8 @@ let make_hunks etyps symbols from = in make NoBreak symbols +(* Build default printing rules from explicit format *) + let error_format () = error "The format does not match the notation" let rec split_format_at_ldots hd = function @@ -656,12 +509,12 @@ let read_recursive_format sl fmt = let slfmt, fmt = get_head fmt in slfmt, get_tail (slfmt, fmt) -let hunks_of_format (from,(vars,typs) as vt) symfmt = +let hunks_of_format (from,(vars,typs)) symfmt = let rec aux = function | symbs, (UnpTerminal s' as u) :: fmt when s' = String.make (String.length s') ' ' -> let symbs, l = aux (symbs,fmt) in symbs, u :: l - | Terminal s :: symbs, (UnpTerminal s' as u) :: fmt + | Terminal s :: symbs, (UnpTerminal s') :: fmt when s = unquote_notation_token s' -> let symbs, l = aux (symbs,fmt) in symbs, UnpTerminal s :: l | NonTerminal s :: symbs, UnpTerminal s' :: fmt when s = id_of_string s' -> @@ -689,36 +542,31 @@ let hunks_of_format (from,(vars,typs) as vt) symfmt = | [], l -> l | _ -> error_format () -let string_of_prec (n,p) = - (string_of_int n)^(match p with E -> "E" | L -> "L" | _ -> "") +(**********************************************************************) +(* Build parsing rules *) let assoc_of_type n (_,typ) = precedence_of_entry_type n typ -let string_of_assoc = function - | Some(Gramext.RightA) -> "RIGHTA" - | Some(Gramext.LeftA) | None -> "LEFTA" - | Some(Gramext.NonA) -> "NONA" - let is_not_small_constr = function ETConstr _ -> true | ETOther("constr","binder_constr") -> true | _ -> false -let rec define_keywords = function +let rec define_keywords_aux = function NonTerm(_,Some(_,e)) as n1 :: Term("IDENT",k) :: l - when not !Options.v7 && is_not_small_constr e -> + when is_not_small_constr e -> prerr_endline ("Defining '"^k^"' as keyword"); Lexer.add_token("",k); - n1 :: Term("",k) :: define_keywords l - | n :: l -> n :: define_keywords l + n1 :: Term("",k) :: define_keywords_aux l + | n :: l -> n :: define_keywords_aux l | [] -> [] let define_keywords = function - Term("IDENT",k)::l when not !Options.v7 -> + Term("IDENT",k)::l -> prerr_endline ("Defining '"^k^"' as keyword"); Lexer.add_token("",k); - Term("",k) :: define_keywords l - | l -> define_keywords l + Term("",k) :: define_keywords_aux l + | l -> define_keywords_aux l let make_production etyps symbols = let prod = @@ -728,12 +576,12 @@ let make_production etyps symbols = let typ = List.assoc m etyps in NonTerm (typ, Some (m,typ)) :: l | Terminal s -> - Term (Extend.terminal s) :: l + Term (terminal s) :: l | Break _ -> l | SProdList (x,sl) -> let sl = List.flatten - (List.map (function Terminal s -> [Extend.terminal s] + (List.map (function Terminal s -> [terminal s] | Break _ -> [] | _ -> anomaly "Found a non terminal token in recursive notation separator") sl) in let y = match List.assoc x etyps with @@ -766,44 +614,8 @@ let recompute_assoc typs = | _, Some Gramext.RightA -> Some Gramext.RightA | _ -> None -let make_grammar_rule n typs symbols ntn perm = - let assoc = recompute_assoc typs in - let prod = make_production typs symbols in - (n,assoc,ntn,prod, perm) - -(* For old ast printer *) -let metas_of sl = - List.fold_right - (fun it metatl -> match it with - | NonTerminal m -> m::metatl - | _ -> metatl) - sl [] - -(* For old ast printer *) -let make_pattern symbols ast = - let env = List.map (fun m -> (string_of_id m,ETast)) (metas_of symbols) in - fst (to_pat env ast) - -(* For old ast printer *) -let make_syntax_rule n name symbols typs ast ntn sc = - [{syn_id = name; - syn_prec = n; - syn_astpat = make_pattern symbols ast; - syn_hunks = - [UNP_SYMBOLIC(sc,ntn,UNP_BOX (PpHOVB 1,make_hunks_ast symbols typs n))]}] - -let make_pp_rule (n,typs,symbols,fmt) = - match fmt with - | None -> [UnpBox (PpHOVB 0, make_hunks typs symbols n)] - | Some fmt -> - [UnpBox (PpHOVB 0, - hunks_of_format (n,List.split typs) (symbols,parse_format fmt))] - (**************************************************************************) -(* Syntax extenstion: common parsing/printing rules and no interpretation *) - -(* v7 and translator : prec is for v7 (None if V8Notation), prec8 is for v8 *) -(* v8 : prec is for v8, prec8 is the same *) +(* Registration of syntax extensions (parsing/printing, no interpretation)*) let pr_arg_level from = function | (n,L) when n=from -> str "at next level" @@ -813,66 +625,38 @@ let pr_arg_level from = function | (n,_) -> str "Unknown level" let pr_level ntn (from,args) = - let lopen = ntn.[0] = '_' and ropen = ntn.[String.length ntn - 1] = '_' in -(* - let ppassoc, args = match args with - | [] -> mt (), [] - | (nl,lpr)::l when nl=from & fst (list_last l)=from -> - let (_,rpr),l = list_sep_last l in - match lpr, snd (list_last l) with - | L,E -> Gramext.RightA, l - | E,L -> Gramext.LeftA, l - | L,L -> Gramext.NoneA, l - | _ -> args -*) str "at level " ++ int from ++ spc () ++ str "with arguments" ++ spc() ++ prlist_with_sep pr_coma (pr_arg_level from) args -(* In v8: prec = Some prec8 is for both parsing and printing *) -(* In v7 and translator: - prec is for parsing (None if V8Notation), - prec8 for v8 printing (v7 printing is via ast) *) -let cache_syntax_extension (_,(_,((prec,prec8),ntn,gr,se))) = +let error_incompatible_level ntn oldprec prec = + errorlabstrm "" + (str ("Notation "^ntn^" is already defined") ++ spc() ++ + pr_level ntn oldprec ++ + spc() ++ str "while it is now required to be" ++ spc() ++ + pr_level ntn prec) + +let cache_one_syntax_extension (prec,ntn,gr,pp) = try - let oldprec, oldprec8 = Symbols.level_of_notation ntn in - if prec8 <> oldprec8 & (Options.do_translate () or not !Options.v7) then - errorlabstrm "" - (str ((if Options.do_translate () then "For new syntax, notation " - else "Notation ") - ^ntn^" is already defined") ++ spc() ++ pr_level ntn oldprec8 ++ - spc() ++ str "while it is now required to be" ++ spc() ++ - pr_level ntn prec8) - else - (* Inconsistent v8 notations but not while translating; forget... *) - (); - (* V8 notations are consistent (from both translator or v8) *) - if prec <> None & !Options.v7 then begin - (* Update the V7 parsing rule *) - if oldprec <> None & out_some oldprec <> out_some prec then - (* None of them is V8Notation and they are different: warn *) - Options.if_verbose - warning ("Notation "^ntn^ - " was already assigned a different level or sublevels"); - if oldprec = None or out_some oldprec <> out_some prec then - Egrammar.extend_grammar (Egrammar.Notation (out_some prec,out_some gr)) - end + let oldprec = Notation.level_of_notation ntn in + if prec <> oldprec then error_incompatible_level ntn oldprec prec with Not_found -> (* Reserve the notation level *) - Symbols.declare_notation_level ntn (prec,prec8); + Notation.declare_notation_level ntn prec; (* Declare the parsing rule *) - option_iter (fun gr -> - Egrammar.extend_grammar (Egrammar.Notation (out_some prec,gr))) gr; + Egrammar.extend_grammar (Egrammar.Notation (prec,gr)); (* Declare the printing rule *) - Symbols.declare_notation_printing_rule ntn (se,fst prec8) + Notation.declare_notation_printing_rule ntn (pp,fst prec) + +let cache_syntax_extension (_,(_,sy_rules)) = + List.iter cache_one_syntax_extension sy_rules -let subst_notation_grammar subst x = x +let subst_parsing_rule subst x = x let subst_printing_rule subst x = x -let subst_syntax_extension (_,subst,(local,(prec,ntn,gr,se))) = - (local,(prec,ntn, - option_app (subst_notation_grammar subst) gr, - subst_printing_rule subst se)) +let subst_syntax_extension (_,subst,(local,sy)) = + (local, List.map (fun (prec,ntn,gr,pp) -> + (prec,ntn, subst_parsing_rule subst gr, subst_printing_rule subst pp)) sy) let classify_syntax_definition (_,(local,_ as o)) = if local then Dispose else Substitute o @@ -888,6 +672,11 @@ let (inSyntaxExtension, outSyntaxExtension) = classify_function = classify_syntax_definition; export_function = export_syntax_definition} +(**************************************************************************) +(* Precedences *) + +(* Interpreting user-provided modifiers *) + let interp_modifiers modl = let onlyparsing = ref false in let rec interp assoc level etyps format = function @@ -896,23 +685,22 @@ let interp_modifiers modl = | SetEntryType (s,typ) :: l -> let id = id_of_string s in if List.mem_assoc id etyps then - error (s^" is already assigned to an entry or constr level") - else interp assoc level ((id,typ)::etyps) format l + error (s^" is already assigned to an entry or constr level"); + interp assoc level ((id,typ)::etyps) format l | SetItemLevel ([],n) :: l -> interp assoc level etyps format l | SetItemLevel (s::idl,n) :: l -> let id = id_of_string s in if List.mem_assoc id etyps then - error (s^" is already assigned to an entry or constr level") - else - let typ = ETConstr (n,()) in - interp assoc level ((id,typ)::etyps) format (SetItemLevel (idl,n)::l) + error (s^" is already assigned to an entry or constr level"); + let typ = ETConstr (n,()) in + interp assoc level ((id,typ)::etyps) format (SetItemLevel (idl,n)::l) | SetLevel n :: l -> - if level <> None then error "A level is given more than once" - else interp assoc (Some n) etyps format l + if level <> None then error "A level is given more than once"; + interp assoc (Some n) etyps format l | SetAssoc a :: l -> - if assoc <> None then error "An associativity is given more than once" - else interp (Some a) level etyps format l + if assoc <> None then error "An associativity is given more than once"; + interp (Some a) level etyps format l | SetOnlyParsing :: l -> onlyparsing := true; interp assoc level etyps format l @@ -921,21 +709,15 @@ let interp_modifiers modl = interp assoc level etyps (Some s) l in interp None None [] None modl -let merge_modifiers a n l = - (match a with None -> [] | Some a -> [SetAssoc a]) @ - (match n with None -> [] | Some n -> [SetLevel n]) @ l - -let interp_infix_modifiers modl = - let (assoc,level,t,b,fmt) = interp_modifiers modl in +let check_infix_modifiers modifiers = + let (assoc,level,t,b,fmt) = interp_modifiers modifiers in if t <> [] then - error "explicit entry level or type unexpected in infix notation"; - (assoc,level,b,fmt) + error "explicit entry level or type unexpected in infix notation" + +let no_syntax_modifiers modifiers = + modifiers = [] or modifiers = [SetOnlyParsing] -(* 2nd list of types has priority *) -let rec merge_entry_types etyps' = function - | [] -> etyps' - | (x,_ as e)::etyps -> - e :: merge_entry_types (List.remove_assoc x etyps') etyps +(* Compute precedences from modifiers (or find default ones) *) let set_entry_type etyps (x,typ) = let typ = try @@ -948,7 +730,7 @@ let set_entry_type etyps (x,typ) = with Not_found -> ETConstr typ in (x,typ) -let check_rule_reversibility l = +let check_rule_productivity l = if List.for_all (function NonTerminal _ -> true | _ -> false) l then error "A notation must include at least one symbol" @@ -956,17 +738,6 @@ let is_not_printable = function | AVar _ -> warning "This notation won't be used for printing as it is bound to a \nsingle variable"; true | _ -> false -let find_precedence_v7 lev etyps symbols = - (match symbols with - | NonTerminal x :: _ -> - (try match List.assoc x etyps with - | ETConstr _ -> - error "The level of the leftmost non-terminal cannot be changed" - | _ -> () - with Not_found -> ()) - | _ -> ()); - if lev = None then 1 else out_some lev - let find_precedence lev etyps symbols = match symbols with | NonTerminal x :: _ -> @@ -1000,7 +771,7 @@ let find_precedence lev etyps symbols = out_some lev let check_curly_brackets_notation_exists () = - try let _ = Symbols.level_of_notation "{ _ }" in () + try let _ = Notation.level_of_notation "{ _ }" in () with Not_found -> error "Notations involving patterns of the form \"{ _ }\" are treated \n\ specially and require that the notation \"{ _ }\" is already reserved" @@ -1028,95 +799,59 @@ let remove_curly_brackets l = | x :: l -> x :: aux false l in aux true l -let compute_syntax_data forv7 (df,modifiers) = +let compute_syntax_data (df,modifiers) = let (assoc,n,etyps,onlyparse,fmt) = interp_modifiers modifiers in (* Notation defaults to NONA *) let assoc = match assoc with None -> Some Gramext.NonA | a -> a in let toks = split_notation_string df in let (recvars,vars,symbols) = analyse_notation_tokens toks in let ntn_for_interp = make_notation_key symbols in - let symbols = remove_curly_brackets symbols in - let notation = make_notation_key symbols in - check_rule_reversibility symbols; - let n = - if !Options.v7 then find_precedence_v7 n etyps symbols - else find_precedence n etyps symbols in - let innerlevel = NumLevel (if forv7 then 10 else 200) in + let symbols' = remove_curly_brackets symbols in + let need_squash = (symbols <> symbols') in + let ntn_for_grammar = make_notation_key symbols' in + check_rule_productivity symbols'; + let n = find_precedence n etyps symbols' in + let innerlevel = NumLevel 200 in let typs = find_symbols - (NumLevel n,BorderProd(true,assoc)) + (NumLevel n,BorderProd(Left,assoc)) (innerlevel,InternalProd) - (NumLevel n,BorderProd(false,assoc)) - symbols in + (NumLevel n,BorderProd(Right,assoc)) + symbols' in (* To globalize... *) let typs = List.map (set_entry_type etyps) typs in - let ppdata = (n,typs,symbols,fmt) in let prec = (n,List.map (assoc_of_type n) typs) in - ((onlyparse,recvars,vars, - ntn_for_interp,notation),prec,ppdata,(Lib.library_dp(),df)) - -(* Uninterpreted (reserved) notations *) -let add_syntax_extension local mv mv8 = - (* from v7: - if mv8 <> None: tells the translator how to print in v8 - if mv <> None: tells how to parse and, how to print in v7 - mv = None = mv8 does not occur - from v8 (mv8 is always None and mv is always Some) - mv tells how to parse and print in v8 - *) - let data8 = option_app (compute_syntax_data false) mv8 in - let data = option_app (compute_syntax_data !Options.v7) mv in - let prec,gram_rule = match data with - | None -> None, None (* Case of V8Notation from v7 *) - | Some ((_,_,_,_,notation),prec,(n,typs,symbols,_),_) -> - Some prec, Some (make_grammar_rule n typs symbols notation None) in - match data, data8 with - | None, None -> (* Nothing to do: V8Notation while not translating *) () - | _, Some d | Some d, None -> - let ((_,_,_,_,ntn),ppprec,ppdata,_) = d in (* tells how to print *) - let ntn' = match data with Some ((_,_,_,_,ntn),_,_,_) -> ntn | _ -> ntn in - let pp_rule = make_pp_rule ppdata in - Lib.add_anonymous_leaf - (inSyntaxExtension (local,((prec,ppprec),ntn',gram_rule,pp_rule))) + let sy_data = (ntn_for_grammar,prec,need_squash,(n,typs,symbols',fmt)) in + let df' = (Lib.library_dp(),df) in + let i_data = (onlyparse,recvars,vars,(ntn_for_interp,df')) in + (i_data,sy_data) (**********************************************************************) -(* Distfix, Infix, Symbols *) - -(* A notation comes with a grammar rule, a pretty-printing rule, an - identifiying pattern called notation and an associated scope *) -let load_notation _ (_,(_,_,ntn,scope,pat,onlyparse,_,_)) = - option_iter Symbols.declare_scope scope - -let open_notation i (_,(_,oldse,ntn,scope,pat,onlyparse,pp8only,df)) = - if i=1 then begin - let b,oldpp8only = Symbols.exists_notation_in_scope scope ntn pat in - (* Declare the old printer rule and its interpretation *) - if (not b or oldpp8only) & oldse <> None then - Esyntax.add_ppobject {sc_univ="constr";sc_entries=out_some oldse}; +(* Registration of notations interpretation *) + +let load_notation _ (_,(_,scope,pat,onlyparse,_)) = + option_iter Notation.declare_scope scope + +let open_notation i (_,(_,scope,pat,onlyparse,(ntn,df))) = + if i=1 & not (Notation.exists_notation_in_scope scope ntn pat) then begin (* Declare the interpretation *) - if not b then - Symbols.declare_notation_interpretation ntn scope pat df pp8only; - if oldpp8only & not pp8only then - Options.silently - (Symbols.declare_notation_interpretation ntn scope pat df) pp8only; - if not b & not onlyparse then - Symbols.declare_uninterpretation (NotationRule (scope,ntn)) pat + Notation.declare_notation_interpretation ntn scope pat df; + (* Declare the uninterpretation *) + if not onlyparse then + Notation.declare_uninterpretation (NotationRule (scope,ntn)) pat end let cache_notation o = load_notation 1 o; open_notation 1 o -let subst_notation (_,subst,(lc,oldse,ntn,scope,(metas,pat),b,b',df)) = - (lc,option_app - (list_smartmap (Extend.subst_syntax_entry Ast.subst_astpat subst)) oldse, - ntn,scope, - (metas,subst_aconstr subst pat), b, b', df) +let subst_notation (_,subst,(lc,scope,(metas,pat),b,ndf)) = + (lc,scope,(metas,subst_aconstr subst (List.map fst metas) pat),b,ndf) -let classify_notation (_,(local,_,_,_,_,_,_,_ as o)) = +let classify_notation (_,(local,_,_,_,_ as o)) = if local then Dispose else Substitute o -let export_notation (local,_,_,_,_,_,_,_ as o) = +let export_notation (local,_,_,_,_ as o) = if local then None else Some o let (inNotation, outNotation) = @@ -1128,37 +863,8 @@ let (inNotation, outNotation) = classify_function = classify_notation; export_function = export_notation} -(* For old ast printer *) -let rec reify_meta_ast vars = function - | Smetalam (loc,s,body) -> Smetalam (loc,s,reify_meta_ast vars body) -(* | Node(loc,"META",[Num (_,n)]) -> Nmeta (loc,create_meta n)*) - | Node(loc,"ISEVAR",[]) -> Nmeta (loc,"$_") - | Node(loc,op,args) -> Node (loc,op, List.map (reify_meta_ast vars) args) - | Slam(loc,Some id,body) when List.mem id vars -> - Smetalam (loc,string_of_id id,reify_meta_ast vars body) - | Slam(loc,na,body) -> Slam(loc,na,reify_meta_ast vars body) - | Nvar (loc,id) when List.mem id vars -> Nmeta (loc,string_of_id id) - | Nmeta _ | Id _ | Nvar _ | Str _ | Num _ | Path _ as a -> a - | Dynamic _ as a -> (* Hum... what to do here *) a - -(* For old ast syntax *) -let make_old_pp_rule n symbols typs r ntn scope vars = - let ast = Termast.ast_of_rawconstr r in - let ast = reify_meta_ast vars ast in - let scope_name = match scope with Some s -> s | None -> "core_scope" in - let rule_name = ntn^"_"^scope_name^"_notation" in - make_syntax_rule n rule_name symbols typs ast ntn scope - -(* maps positions in v8-notation into positions in v7-notation (used - for parsing). - For instance Notation "x < y < z" := .. V8only "y < z < x" - yields [1; 2; 0] (y is the second arg in v7; z is 3rd; x is fst) *) -let mk_permut vars7 vars8 = - if vars7=vars8 then None else - Some - (List.fold_right - (fun v8 subs -> list_index v8 vars7 - 1 :: subs) - vars8 []) +(**********************************************************************) +(* Recovering existing syntax *) let contract_notation ntn = if ntn = "{ _ }" then ntn else @@ -1173,304 +879,120 @@ let contract_notation ntn = else ntn in aux ntn 0 -let add_notation_in_scope local df c mods omodv8 scope = - let ((onlyparse,recs,vars,intnot,notation),prec,(n,typs,symbols,_ as ppdata),df')= - compute_syntax_data !Options.v7 (df,mods) in - (* Declare the parsing and printing rules if not already done *) - (* For both v7 and translate: parsing is as described for v7 in v7 file *) - (* For v8: parsing is as described in v8 file *) - (* For v7: printing is by the old printer - see below *) - (* For translate: printing is as described for v8 in v7 file *) - (* For v8: printing is as described in v8 file *) - (* In short: parsing does not depend on omodv8 *) - (* Printing depends on mv8 if defined, otherwise of mods (scaled by 10) *) - (* if in v7, or of mods without scaling if in v8 *) - let intnot,ntn,pprecvars,ppvars,ppprec,pp_rule = - match omodv8 with - | Some mv8 -> - let (_,recs8,vars8,intnot8,ntn8),p,d,_ = compute_syntax_data false mv8 in - intnot8,ntn8,recs8,vars8,p,make_pp_rule d - | None when not !Options.v7 -> - intnot,notation,recs,vars,prec,make_pp_rule ppdata - | None -> - (* means the rule already exists: recover it *) - (* occurs only with V8only flag alone *) - try - let ntn = contract_notation notation in - let _, oldprec8 = Symbols.level_of_notation ntn in - let rule,_ = Symbols.find_notation_printing_rule ntn in - notation,ntn,recs,vars,oldprec8,rule - with Not_found -> error "No known parsing rule for this notation in V8" - in - let permut = mk_permut vars ppvars in - let gram_rule = make_grammar_rule n typs symbols ntn permut in - Lib.add_anonymous_leaf - (inSyntaxExtension - (local,((Some prec,ppprec),ntn,Some gram_rule,pp_rule))); - - (* Declare interpretation *) - let (acvars,ac) = interp_aconstr [] ppvars c in - let a = (remove_vars pprecvars acvars,ac) (* For recursive parts *) in - let old_pp_rule = - (* Used only by v7; disable if contains a recursive pattern *) - if onlyparse or pprecvars <> [] or not (!Options.v7) then None - else - let r = interp_global_rawconstr_with_vars vars c in - Some (make_old_pp_rule n symbols typs r intnot scope vars) in - let onlyparse = onlyparse or !Options.v7_only or is_not_printable ac in - Lib.add_anonymous_leaf - (inNotation(local,old_pp_rule,intnot,scope,a,onlyparse,false,df')) - -let level_rule (n,p) = if p = E then n else max (n-1) 0 +exception NoSyntaxRule -let recover_syntax ntn = +let recover_syntax ntn = try - match Symbols.level_of_notation ntn with - | (Some prec,_ as pprec) -> - let rule,_ = Symbols.find_notation_printing_rule ntn in - let gr = Egrammar.recover_notation_grammar ntn prec in - Some (pprec,ntn,Some gr,rule) - | None,_ -> None - with Not_found -> None + let prec = Notation.level_of_notation ntn in + let pprule,_ = Notation.find_notation_printing_rule ntn in + let gr = Egrammar.recover_notation_grammar ntn prec in + (prec,ntn,gr,pprule) + with Not_found -> + raise NoSyntaxRule + +let recover_squash_syntax () = recover_syntax "{ _ }" let recover_notation_syntax rawntn = let ntn = contract_notation rawntn in - match recover_syntax ntn with - | None -> None - | Some gr -> Some (gr,if ntn=rawntn then None else recover_syntax "{ _ }") - -let set_data_for_v7_pp recs a vars = - if not !Options.v7 then None else - if recs=[] then Some (a,vars) - else (warning "No recursive notation in v7 syntax";None) - -let build_old_pp_rule notation scope symbs (r,vars) = - let prec = - try - let a,_ = Symbols.level_of_notation (contract_notation notation) in - if a = None then raise Not_found else out_some a - with Not_found -> - error "Parsing rule for this notation has to be previously declared" in - let typs = List.map2 - (fun id n -> - id,ETConstr (NumLevel (level_rule n),InternalProd)) vars (snd prec) in - make_old_pp_rule (fst prec) symbs typs r notation scope vars - -let add_notation_interpretation_core local symbs for_old df a scope onlyparse - onlypp gram_data = - let notation = make_notation_key symbs in - let old_pp_rule = - if !Options.v7 then - option_app (build_old_pp_rule notation scope symbs) for_old - else None in - option_iter - (fun (x,y) -> - Lib.add_anonymous_leaf (inSyntaxExtension (local,x)); - option_iter - (fun z -> Lib.add_anonymous_leaf (inSyntaxExtension (local,z))) y) - gram_data; - Lib.add_anonymous_leaf - (inNotation(local,old_pp_rule,notation,scope,a,onlyparse,onlypp, - (Lib.library_dp(),df))) + let sy_rule = recover_syntax ntn in + let need_squash = ntn<>rawntn in + if need_squash then [sy_rule; recover_squash_syntax ()] else [sy_rule] -let add_notation_interpretation df names c sc = +(**********************************************************************) +(* Main entry point for building parsing and printing rules *) + +let make_pa_rule (n,typs,symbols,_) ntn = + let assoc = recompute_assoc typs in + let prod = make_production typs symbols in + (n,assoc,ntn,prod) + +let make_pp_rule (n,typs,symbols,fmt) = + match fmt with + | None -> [UnpBox (PpHOVB 0, make_hunks typs symbols n)] + | Some fmt -> hunks_of_format (n,List.split typs) (symbols,parse_format fmt) + +let make_syntax_rules (ntn,prec,need_squash,sy_data) = + let pa_rule = make_pa_rule sy_data ntn in + let pp_rule = make_pp_rule sy_data in + let sy_rule = (prec,ntn,pa_rule,pp_rule) in + (* By construction, the rule for "{ _ }" is declared, but we need to + redeclare it because the file where it is declared needs not be open + when the current file opens (especially in presence of -nois) *) + if need_squash then [sy_rule; recover_squash_syntax ()] else [sy_rule] + +(**********************************************************************) +(* Main functions about notations *) + +let add_notation_in_scope local df c mods scope = + let (i_data,sy_data) = compute_syntax_data (df,mods) in + (* Declare the parsing and printing rules *) + let sy_rules = make_syntax_rules sy_data in + Lib.add_anonymous_leaf (inSyntaxExtension(local,sy_rules)); + (* Declare interpretation *) + let (onlyparse,recvars,vars,df') = i_data in + let (acvars,ac) = interp_aconstr [] vars c in + let a = (remove_vars recvars acvars,ac) (* For recursive parts *) in + let onlyparse = onlyparse or is_not_printable ac in + Lib.add_anonymous_leaf (inNotation(local,scope,a,onlyparse,df')) + +let add_notation_interpretation_core local df names c scope onlyparse = let (recs,vars,symbs) = analyse_notation_tokens (split_notation_string df) in - let gram_data = recover_notation_syntax (make_notation_key symbs) in - if gram_data = None then - error "Parsing rule for this notation has to be previously declared"; + (* Redeclare pa/pp rules *) + if not (is_numeral symbs) then begin + let sy_rules = recover_notation_syntax (make_notation_key symbs) in + Lib.add_anonymous_leaf (inSyntaxExtension (local,sy_rules)) + end; + (* Declare interpretation *) + let df' = (make_notation_key symbs,(Lib.library_dp(),df)) in let (acvars,ac) = interp_aconstr names vars c in let a = (remove_vars recs acvars,ac) (* For recursive parts *) in - let a_for_old = interp_rawconstr_with_implicits Evd.empty (Global.env()) vars names c in - let for_oldpp = set_data_for_v7_pp recs a_for_old vars in - let onlyparse = is_not_printable ac in - add_notation_interpretation_core false symbs for_oldpp df a sc onlyparse - false gram_data - -let add_notation_in_scope_v8only local df c mv8 scope = - let (_,recs,vars,intnot,notation),prec,ppdata,df' = compute_syntax_data false (df,mv8) in - let pp_rule = make_pp_rule ppdata in - Lib.add_anonymous_leaf - (inSyntaxExtension(local,((None,prec),notation,None,pp_rule))); - (* Declare the interpretation *) - let (acvars,ac) = interp_aconstr [] vars c in - let a = (remove_vars recs acvars,ac) (* For recursive parts *) in - let onlyparse = is_not_printable ac in - Lib.add_anonymous_leaf - (inNotation(local,None,intnot,scope,a,onlyparse,true,df')) + let onlyparse = onlyparse or is_not_printable ac in + Lib.add_anonymous_leaf (inNotation(local,scope,a,onlyparse,df')) -let add_notation_v8only local c (df,modifiers) sc = - let toks = split_notation_string df in - match toks with - | [String x] when (modifiers = [] or modifiers = [SetOnlyParsing]) -> - (* This is a ident to be declared as a rule *) - add_notation_in_scope_v8only local df c (SetLevel 0::modifiers) sc - | _ -> - let (assoc,lev,typs,onlyparse,fmt) = interp_modifiers modifiers in - match lev with - | None-> - if modifiers <> [] & modifiers <> [SetOnlyParsing] then - error "Parsing rule for this notation includes no level" - else - (* Declare only interpretation *) - let (recs,vars,symbs) = analyse_notation_tokens toks in - let (acvars,ac) = interp_aconstr [] vars c in - let onlyparse = modifiers = [SetOnlyParsing] - or is_not_printable ac in - let a = (remove_vars recs acvars,ac) in - add_notation_interpretation_core local symbs None df a sc - onlyparse true None - | Some n -> - (* Declare both syntax and interpretation *) - let mods = - if List.for_all (function SetAssoc _ -> false | _ -> true) - modifiers - then SetAssoc Gramext.NonA :: modifiers else modifiers in - add_notation_in_scope_v8only local df c mods sc - -let is_quoted_ident x = - let x' = unquote_notation_token x in - x <> x' & try Lexer.check_ident x'; true with _ -> false - -(* v7: dfmod=None; mv8=Some: add only v8 printing rule *) -(* dfmod=Some: add v7 parsing rule; mv8=Some: add v8 printing rule *) -(* dfmod=Some; mv8=None: same v7-parsing and v8-printing rules *) -(* v8: dfmod=Some; mv8=None: same v8 parsing and printing rules *) -let add_notation local c dfmod mv8 sc = - match dfmod with - | None -> add_notation_v8only local c (out_some mv8) sc - | Some (df,modifiers) -> - let toks = split_notation_string df in - match toks with - | [String x] when (modifiers = [] or modifiers = [SetOnlyParsing]) -> - (* This is a ident to be declared as a rule *) - add_notation_in_scope local df c (SetLevel 0::modifiers) mv8 sc - | _ -> - let (assoc,lev,typs,onlyparse,fmt) = interp_modifiers modifiers in - match lev with - | None-> - if modifiers <> [] & modifiers <> [SetOnlyParsing] then - error "Parsing rule for this notation includes no level" - else - (* Declare only interpretation *) - let (recs,vars,symbs) = analyse_notation_tokens toks in - let gram_data = - recover_notation_syntax (make_notation_key symbs) in - if gram_data <> None then - let (acvars,ac) = interp_aconstr [] vars c in - let a = (remove_vars recs acvars,ac) in - let onlyparse = modifiers = [SetOnlyParsing] - or is_not_printable ac in - let a_for_old = interp_global_rawconstr_with_vars vars c in - let for_old = set_data_for_v7_pp recs a_for_old vars in - add_notation_interpretation_core local symbs for_old df a - sc onlyparse false gram_data - else - add_notation_in_scope local df c modifiers mv8 sc - | Some n -> - (* Declare both syntax and interpretation *) - let assoc = match assoc with None -> Some Gramext.NonA | a -> a in - add_notation_in_scope local df c modifiers mv8 sc - -(* TODO add boxes information in the expression *) +(* Notations without interpretation (Reserved Notation) *) + +let add_syntax_extension local mv = + let (_,sy_data) = compute_syntax_data mv in + let sy_rules = make_syntax_rules sy_data in + Lib.add_anonymous_leaf (inSyntaxExtension(local,sy_rules)) + +(* Notations with only interpretation *) + +let add_notation_interpretation df names c sc = + try add_notation_interpretation_core false df names c sc false + with NoSyntaxRule -> + error "Parsing rule for this notation has to be previously declared" + +(* Main entry point *) + +let add_notation local c (df,modifiers) sc = + if no_syntax_modifiers modifiers then + (* No syntax data: try to rely on a previously declared rule *) + let onlyparse = modifiers=[SetOnlyParsing] in + try add_notation_interpretation_core local df [] c sc onlyparse + with NoSyntaxRule -> + (* Try to determine a default syntax rule *) + add_notation_in_scope local df c modifiers sc + else + (* Declare both syntax and interpretation *) + add_notation_in_scope local df c modifiers sc + +(* Infix notations *) let inject_var x = CRef (Ident (dummy_loc, id_of_string x)) -let rec rename x vars n = function - | [] -> - (vars,[]) - | String "_"::l -> - let (vars,l) = rename x vars (n+1) l in - let xn = x^(string_of_int n) in - ((inject_var xn)::vars,xn::l) - | String y::l -> - let (vars,l) = rename x vars n l in (vars,(quote_notation_token y)::l) - | WhiteSpace _::l -> - rename x vars n l - -let translate_distfix assoc df r = - let (vars,l) = rename "x" [] 1 (split_notation_string df) in - let df = String.concat " " l in - let a = mkAppC (mkRefC r, vars) in - let assoc = match assoc with None -> Gramext.LeftA | Some a -> a in - (assoc,df,a) - -let add_distfix local assoc n df r sc = - (* "x" cannot clash since r is globalized (included section vars) *) - let (vars,l) = rename "x" [] 1 (split_notation_string df) in - let df = String.concat " " l in - let a = mkAppC (mkRefC r, vars) in - let assoc = match assoc with None -> Gramext.LeftA | Some a -> a in - add_notation_in_scope local df a [SetAssoc assoc;SetLevel n] None sc - -let make_infix_data n assoc modl mv8 = - (* Infix defaults to LEFTA in V7 (cf doc) *) - let mv = match n with None when !Options.v7 -> SetLevel 1 :: modl | _ -> modl in - let mv = match assoc with None when !Options.v7 -> SetAssoc Gramext.LeftA :: mv | _ -> mv in - let mv8 = match mv8 with - None -> None - | Some(s8,mv8) -> - if List.for_all (function SetLevel _ -> false | _ -> true) mv8 then - error "Needs a level" - else Some (("x "^quote_notation_token s8^" y"),mv8) in - mv,mv8 - -let add_infix local (inf,modl) pr mv8 sc = - if inf="" (* Code for V8Infix only *) then - let (p8,mv8) = out_some mv8 in - let (a8,n8,onlyparse,fmt) = interp_infix_modifiers mv8 in - let metas = [inject_var "x"; inject_var "y"] in - let a = mkAppC (mkRefC pr,metas) in - let df = "x "^(quote_notation_token p8)^" y" in - let toks = split_notation_string df in - if a8=None & n8=None & fmt=None then - (* Declare only interpretation *) - let (recs,vars,symbs) = analyse_notation_tokens toks in - let (acvars,ac) = interp_aconstr [] vars a in - let a' = (remove_vars recs acvars,ac) in - let a_for_old = interp_global_rawconstr_with_vars vars a in - add_notation_interpretation_core local symbs None df a' sc - onlyparse true None - else - if n8 = None then error "Needs a level" else - let mv8 = match a8 with None -> SetAssoc Gramext.NonA :: mv8 |_ -> mv8 in - add_notation_in_scope_v8only local df a mv8 sc - else begin - let (assoc,n,onlyparse,fmt) = interp_infix_modifiers modl in +let add_infix local (inf,modifiers) pr sc = + check_infix_modifiers modifiers; (* check the precedence *) - if !Options.v7 & (n<> None & (out_some n < 1 or out_some n > 10)) then - errorlabstrm "Metasyntax.infix_grammar_entry" - (str"Precedence must be between 1 and 10."); - (* - if (assoc<>None) & (n<6 or n>9) then - errorlabstrm "Vernacentries.infix_grammar_entry" - (str"Associativity Precedence must be 6,7,8 or 9."); - *) let metas = [inject_var "x"; inject_var "y"] in - let a = mkAppC (mkRefC pr,metas) in + let c = mkAppC (mkRefC pr,metas) in let df = "x "^(quote_notation_token inf)^" y" in - let toks = split_notation_string df in - if not !Options.v7 & n=None & assoc=None then - (* En v8, une notation sans information de parsing signifie *) - (* de ne déclarer que l'interprétation *) - (* Declare only interpretation *) - let (recs,vars,symbs) = analyse_notation_tokens toks in - let gram_data = recover_notation_syntax (make_notation_key symbs) in - if gram_data <> None then - let (acvars,ac) = interp_aconstr [] vars a in - let a' = (remove_vars recs acvars,ac) in - let a_for_old = interp_global_rawconstr_with_vars vars a in - let for_old = set_data_for_v7_pp recs a_for_old vars in - add_notation_interpretation_core local symbs for_old df a' sc - onlyparse false gram_data - else - let mv,mv8 = make_infix_data n assoc modl mv8 in - add_notation_in_scope local df a mv mv8 sc - else - let mv,mv8 = make_infix_data n assoc modl mv8 in - add_notation_in_scope local df a mv mv8 sc - end + add_notation local c (df,modifiers) sc + +(**********************************************************************) +(* Miscellaneous *) -let standardise_locatable_notation ntn = +let standardize_locatable_notation ntn = let unquote = function | String s -> [unquote_notation_token s] | _ -> [] in @@ -1480,17 +1002,19 @@ let standardise_locatable_notation ntn = else unquote_notation_token ntn -(* Delimiters and classes bound to scopes *) +(**********************************************************************) +(* Delimiters and classes bound to scopes *) + type scope_command = ScopeDelim of string | ScopeClasses of Classops.cl_typ let load_scope_command _ (_,(scope,dlm)) = - Symbols.declare_scope scope + Notation.declare_scope scope let open_scope_command i (_,(scope,o)) = if i=1 then match o with - | ScopeDelim dlm -> Symbols.declare_delimiters scope dlm - | ScopeClasses cl -> Symbols.declare_class_scope scope cl + | ScopeDelim dlm -> Notation.declare_delimiters scope dlm + | ScopeClasses cl -> Notation.declare_class_scope scope cl let cache_scope_command o = load_scope_command 1 o; |