aboutsummaryrefslogtreecommitdiff
path: root/doc/tools/docgram/doc_grammar.ml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/tools/docgram/doc_grammar.ml')
-rw-r--r--doc/tools/docgram/doc_grammar.ml387
1 files changed, 312 insertions, 75 deletions
diff --git a/doc/tools/docgram/doc_grammar.ml b/doc/tools/docgram/doc_grammar.ml
index eb86bab37e..70976e705e 100644
--- a/doc/tools/docgram/doc_grammar.ml
+++ b/doc/tools/docgram/doc_grammar.ml
@@ -48,6 +48,9 @@ let default_args = {
verify = false;
}
+let start_symbols = ["vernac_toplevel"]
+let tokens = [ "bullet"; "ident"; "int"; "num"; "numeral"; "string" ]
+
(* translated symbols *)
type doc_symbol =
@@ -128,8 +131,8 @@ module DocGram = struct
g_update_prods g nt' (oprods @ nprods)
(* add a new nonterminal after "ins_after" None means insert at the beginning *)
- let g_add_after g ins_after nt prods =
- if NTMap.mem nt !g.map then raise Duplicate; (* don't update the nt if it's already present *)
+ let g_add_after g ?(update=true) ins_after nt prods =
+ if (not update) && NTMap.mem nt !g.map then raise Duplicate; (* don't update the nt if it's already present *)
let rec insert_nt order res =
match ins_after, order with
| None, _ -> nt :: order
@@ -143,6 +146,11 @@ module DocGram = struct
g := { order = insert_nt !g.order [];
map = NTMap.add nt prods !g.map }
+ let g_add_prod_after g ins_after nt prod =
+ let prods = try NTMap.find nt !g.map with Not_found -> [] in
+ (* todo: add check for duplicates *)
+ g_add_after g ~update:true ins_after nt (prods @ [prod])
+
(* replace the map and order *)
let g_reorder g map order =
let order_nts = StringSet.of_list order in
@@ -188,13 +196,13 @@ let rec output_prod plist need_semi = function
| Slist0sep (sym, sep) -> sprintf "LIST0 %s SEP %s" (prod_to_str ~plist [sym]) (prod_to_str ~plist [sep])
| Sopt sym -> sprintf "OPT %s" (prod_to_str ~plist [sym])
| Sparen sym_list -> sprintf "( %s )" (prod_to_str sym_list)
- | Sprod sym_list ->
+ | Sprod sym_list_list ->
sprintf "[ %s ]" (String.concat " " (List.mapi (fun i r ->
let prod = (prod_to_str r) in
let sep = if i = 0 then "" else
if prod <> "" then "| " else "|" in
sprintf "%s%s" sep prod)
- sym_list))
+ sym_list_list))
| Sedit s -> sprintf "%s" s
(* todo: make PLUGIN info output conditional on the set of prods? *)
| Sedit2 ("PLUGIN", plugin) ->
@@ -213,6 +221,8 @@ let rec output_prod plist need_semi = function
and prod_to_str_r plist prod =
match prod with
+ | Sterm s :: Snterm "ident" :: tl when List.mem s ["?"; "."] && plist ->
+ (sprintf "%s`ident`" s) :: (prod_to_str_r plist tl)
| p :: tl ->
let need_semi =
match prod with
@@ -258,6 +268,15 @@ and output_sep sep =
and prod_to_prodn prod = String.concat " " (List.map output_prodn prod)
+let pr_prods nt prods = (* duplicative *)
+ Printf.printf "%s: [\n" nt;
+ List.iter (fun prod ->
+ let str = prod_to_str ~plist:false prod in
+ let pfx = if str = "" then "|" else "| " in
+ Printf.printf "%s%s\n" pfx str)
+ prods;
+ Printf.printf "]\n\n"
+
type fmt = [`MLG | `PRODLIST | `PRODN ]
(* print a subset of the grammar with nts in the specified order *)
@@ -313,6 +332,8 @@ let cvt_ext prod =
in
List.map from_ext prod
+let keywords = ref StringSet.empty
+
let rec cvt_gram_sym = function
| GSymbString s -> Sterm s
| GSymbQualid (s, level) ->
@@ -352,6 +373,10 @@ and cvt_gram_sym_list l =
(Sedit2 ("NOTE", s2)) :: cvt_gram_sym_list tl
| GSymbQualid ("USE_NT", _) :: GSymbQualid (s2, l) :: tl ->
(Sedit2 ("USE_NT", s2)) :: cvt_gram_sym_list tl
+ | GSymbString s :: tl ->
+ (* todo: not seeing "(bfs)" here for some reason *)
+ keywords := StringSet.add s !keywords;
+ cvt_gram_sym (GSymbString s) :: cvt_gram_sym_list tl
| hd :: tl ->
cvt_gram_sym hd :: cvt_gram_sym_list tl
| [] -> []
@@ -453,6 +478,7 @@ let plugin_regex = Str.regexp "^plugins/\\([a-zA-Z0-9_]+\\)/"
let read_mlg is_edit ast file level_renames symdef_map =
let res = ref [] in
+ let locals = ref StringSet.empty in
let add_prods nt prods =
if not is_edit then
add_symdef nt file symdef_map;
@@ -478,6 +504,8 @@ let read_mlg is_edit ast file level_renames symdef_map =
let len = List.length ent.gentry_rules in
List.iteri (fun i rule ->
let nt = ent.gentry_name in
+ if not (List.mem nt grammar_ext.gramext_globals) then
+ locals := StringSet.add nt !locals;
let level = (get_label rule.grule_label) in
let level = if level <> "" then level else
match ent.gentry_pos with
@@ -528,7 +556,7 @@ let read_mlg is_edit ast file level_renames symdef_map =
in
List.iter prod_loop ast;
- List.rev !res
+ List.rev !res, !locals
let dir s = "doc/tools/docgram/" ^ s
@@ -536,7 +564,8 @@ let read_mlg_edit file =
let fdir = dir file in
let level_renames = ref StringMap.empty in (* ignored *)
let symdef_map = ref StringMap.empty in (* ignored *)
- read_mlg true (parse_file fdir) fdir level_renames symdef_map
+ let prods, _ = read_mlg true (parse_file fdir) fdir level_renames symdef_map in
+ prods
let add_rule g nt prods file =
let ent = try NTMap.find nt !g.map with Not_found -> [] in
@@ -555,9 +584,12 @@ let read_mlg_files g args symdef_map =
let last_autoloaded = List.hd (List.rev autoloaded_mlgs) in
List.iter (fun file ->
(* does nt renaming, deletion and splicing *)
- let rules = read_mlg false (parse_file file) file level_renames symdef_map in
+ let rules, locals = read_mlg false (parse_file file) file level_renames symdef_map in
let numprods = List.fold_left (fun num rule ->
let nt, prods = rule in
+ if NTMap.mem nt !g.map && (StringSet.mem nt locals) &&
+ StringSet.cardinal (StringSet.of_list (StringMap.find nt !symdef_map)) > 1 then
+ warn "%s: local nonterminal '%s' already defined\n" file nt;
add_rule g nt prods file;
num + List.length prods)
0 rules
@@ -572,18 +604,74 @@ let read_mlg_files g args symdef_map =
!level_renames
+ (* get the nt's in the production, preserving order, don't worry about dups *)
+ let nts_in_prod prod =
+ let rec traverse = function
+ | Sterm s -> []
+ | Snterm s -> if List.mem s tokens then [] else [s]
+ | Slist1 sym
+ | Slist0 sym
+ | Sopt sym
+ -> traverse sym
+ | Slist1sep (sym, sep)
+ | Slist0sep (sym, sep)
+ -> traverse sym @ (traverse sep)
+ | Sparen sym_list -> List.concat (List.map traverse sym_list)
+ | Sprod sym_list_list -> List.concat (List.map (fun l -> List.concat (List.map traverse l)) sym_list_list)
+ | Sedit _
+ | Sedit2 _ -> []
+ in
+ List.rev (List.concat (List.map traverse prod))
+
+let get_refdef_nts g =
+ let rec get_nts_r refd defd bindings =
+ match bindings with
+ | [] -> refd, defd
+ | (nt, prods) :: tl ->
+ get_nts_r (List.fold_left (fun res prod ->
+ StringSet.union res (StringSet.of_list (nts_in_prod prod)))
+ refd prods)
+ (StringSet.add nt defd) tl
+ in
+ let toks = StringSet.of_list tokens in
+ get_nts_r toks toks (NTMap.bindings !g.map)
+
+
(*** global editing ops ***)
-let create_edit_map edits =
+let create_edit_map g op edits =
let rec aux edits map =
match edits with
| [] -> map
| edit :: tl ->
let (key, binding) = edit in
+ let all_nts_ref, all_nts_def = get_refdef_nts g in
+ (match op with
+ (* todo: messages should tell you which edit file causes the error *)
+ | "SPLICE" ->
+ if not (StringSet.mem key all_nts_def) then
+ error "Undefined nt `%s` in SPLICE\n" key
+ | "DELETE" ->
+ if not (StringSet.mem key all_nts_ref || (StringSet.mem key all_nts_def)) then
+ error "Unused/undefined nt `%s` in DELETE\n" key;
+ | "RENAME" ->
+ if not (StringSet.mem key all_nts_ref || (StringSet.mem key all_nts_def)) then
+ error "Unused/undefined nt `%s` in RENAME\n" key;
+(* todo: could not get the following codeto type check
+ (match binding with
+ | _ :: Snterm new_nt :: _ ->
+ if not (StringSet.mem new_nt all_nts_ref) then
+ error "nt `%s` already exists in %s\n" new_nt op
+ | _ -> ())
+*)
+ | _ -> ());
aux tl (StringMap.add key binding map)
in
aux edits StringMap.empty
+let remove_Sedit2 p =
+ List.filter (fun sym -> match sym with | Sedit2 _ -> false | _ -> true) p
+
(* edit a production: rename nonterminals, drop nonterminals, substitute nonterminals *)
let rec edit_prod g top edit_map prod =
let edit_nt edit_map sym0 nt =
@@ -596,8 +684,8 @@ let rec edit_prod g top edit_map prod =
try let splice_prods = NTMap.find nt !g.map in
match splice_prods with
| [] -> assert false
- | [p] -> List.rev p
- | _ -> [Sprod splice_prods]
+ | [p] -> List.rev (remove_Sedit2 p)
+ | _ -> [Sprod (List.map remove_Sedit2 splice_prods)]
with Not_found -> error "Missing nt '%s' for splice\n" nt; [Snterm nt]
end
| _ -> [Snterm binding]
@@ -654,16 +742,22 @@ and edit_rule g edit_map nt rule =
(*** splice: replace a reference to a nonterminal with its definition ***)
-(* todo: create a better splice routine, handle recursive case *)
+(* todo: create a better splice routine *)
let apply_splice g splice_map =
- StringMap.iter (fun nt b ->
- if not (NTMap.mem nt !g.map) then
- error "Unknown nt '%s' for apply_splice\n" nt)
- splice_map;
List.iter (fun b ->
- let (nt, prods) = b in
- let (nt', prods) = edit_rule g splice_map nt prods in
- g_update_prods g nt' prods)
+ let (nt0, prods0) = b in
+ let rec splice_loop nt prods cnt =
+ let max_cnt = 10 in
+ let (nt', prods') = edit_rule g splice_map nt prods in
+ if cnt > max_cnt then
+ error "Splice for '%s' not done after %d iterations\n" nt0 max_cnt;
+ if nt' = nt && prods' = prods then
+ (nt', prods')
+ else
+ splice_loop nt' prods' (cnt+1)
+ in
+ let (nt', prods') = splice_loop nt0 prods0 0 in
+ g_update_prods g nt' prods')
(NTMap.bindings !g.map);
List.iter (fun b ->
let (nt, op) = b in
@@ -678,7 +772,7 @@ let find_first edit prods nt =
let rec find_first_r edit prods nt i =
match prods with
| [] ->
- error "Can't find '%s' in REPLACE for '%s'\n" (prod_to_str edit) nt;
+ error "Can't find '%s' in edit for '%s'\n" (prod_to_str edit) nt;
raise Not_found
| prod :: tl ->
if ematch prod edit then i
@@ -906,7 +1000,7 @@ let edit_all_prods g op eprods =
op (prod_to_str eprod) num;
aux tl res
in
- let map = create_edit_map (aux eprods []) in
+ let map = create_edit_map g op (aux eprods []) in
if op = "SPLICE" then
apply_splice g map
else (* RENAME/DELETE *)
@@ -960,6 +1054,13 @@ let edit_single_prod g edit0 prods nt =
in
edit_single_prod_r edit0 prods nt []
+let report_undef_nts g prod rec_nt =
+ let nts = nts_in_prod prod in
+ List.iter (fun nt ->
+ if not (NTMap.mem nt !g.map) && not (List.mem nt tokens) && nt <> rec_nt then
+ error "Undefined nonterminal `%s` in edit: %s\n" nt (prod_to_str prod))
+ nts
+
let apply_edit_file g edits =
List.iter (fun b ->
let (nt, eprod) = b in
@@ -970,11 +1071,26 @@ let apply_edit_file g edits =
| (Snterm "DELETE" :: oprod) :: tl ->
aux tl (remove_prod oprod prods nt) add_nt
| (Snterm "DELETENT" :: _) :: tl -> (* note this doesn't remove references *)
+ if not (NTMap.mem nt !g.map) then
+ error "DELETENT for undefined nonterminal `%s`\n" nt;
g_remove g nt;
aux tl prods false
+ | (Snterm "MOVETO" :: Snterm nt2 :: oprod) :: tl ->
+ g_add_prod_after g (Some nt) nt2 oprod;
+ let prods' = (try
+ let posn = find_first oprod prods nt in
+ let prods = insert_after posn [[Snterm nt2]] prods in (* insert new prod *)
+ remove_prod oprod prods nt (* remove orig prod *)
+ with Not_found -> prods)
+ in
+ aux tl prods' add_nt
+ | (Snterm "PRINT" :: _) :: tl ->
+ pr_prods nt (NTMap.find nt !g.map);
+ aux tl prods add_nt
| (Snterm "EDIT" :: oprod) :: tl ->
aux tl (edit_single_prod g oprod prods nt) add_nt
| (Snterm "REPLACE" :: oprod) :: (Snterm "WITH" :: rprod) :: tl ->
+ report_undef_nts g rprod "";
let prods' = (try
let posn = find_first oprod prods nt in
let prods = insert_after posn [rprod] prods in (* insert new prod *)
@@ -985,10 +1101,12 @@ let apply_edit_file g edits =
| (Snterm "REPLACE" :: _ as eprod) :: tl ->
error "Missing WITH after '%s' in '%s'\n" (prod_to_str eprod) nt;
aux tl prods add_nt
+ (* todo: check for unmatched editing keywords here *)
| prod :: tl ->
(* add a production *)
if has_match prod prods then
error "Duplicate production '%s' for %s\n" (prod_to_str prod) nt;
+ report_undef_nts g prod nt;
aux tl (prods @ [prod]) add_nt
in
let prods, add_nt =
@@ -1001,25 +1119,6 @@ let apply_edit_file g edits =
(*** main routines ***)
- (* get the nt's in the production, preserving order, don't worry about dups *)
- let nts_in_prod prod =
- let rec traverse = function
- | Sterm s -> []
- | Snterm s -> [s]
- | Slist1 sym
- | Slist0 sym
- | Sopt sym
- -> traverse sym
- | Slist1sep (sym, sep)
- | Slist0sep (sym, sep)
- -> traverse sym @ (traverse sep)
- | Sparen sym_list -> List.concat (List.map traverse sym_list)
- | Sprod sym_list_list -> List.concat (List.map (fun l -> List.concat (List.map traverse l)) sym_list_list)
- | Sedit _
- | Sedit2 _ -> []
- in
- List.rev (List.concat (List.map traverse prod))
-
(* get the special tokens in the grammar *)
let print_special_tokens g =
let rec traverse set = function
@@ -1129,24 +1228,156 @@ let print_chunks g out fmt () =
(*seen := StringSet.diff !seen (StringSet.of_list ssr_tops);*)
(*print_chunk out g seen fmt "vernac_toplevel" ["vernac_toplevel"] [];*)
+let index_of str list =
+ let rec index_of_r str list index =
+ match list with
+ | [] -> None
+ | hd :: list ->
+ if hd = str then Some index
+ else index_of_r str list (index+1)
+ in
+ index_of_r str list 0
-let start_symbols = ["vernac_toplevel"]
-(* don't report tokens as undefined *)
-let tokens = [ "bullet"; "field"; "ident"; "int"; "num"; "numeral"; "string" ]
+exception IsNone
-let report_bad_nts g file =
- let rec get_nts refd defd bindings =
- match bindings with
- | [] -> refd, defd
- | (nt, prods) :: tl ->
- get_nts (List.fold_left (fun res prod ->
- StringSet.union res (StringSet.of_list (nts_in_prod prod)))
- refd prods)
- (StringSet.add nt defd) tl
+(* todo: raise exception for bad n? *)
+let rec nthcdr n list = if n <= 0 then list else nthcdr (n-1) (List.tl list)
+
+let pfx n list =
+ let rec pfx_r n res = function
+ | item :: tl -> if n < 0 then res else pfx_r (n-1) (item :: res) tl
+ | [] -> res
+ in
+ List.rev (pfx_r n [] list)
+
+(* todo: adjust Makefile to include Option.ml/mli *)
+let get_opt = function
+ | Some y -> y
+ | _ -> raise IsNone
+
+let get_range g start end_ =
+ let starti, endi = get_opt (index_of start !g.order), get_opt (index_of end_ !g.order) in
+ pfx (endi - starti) (nthcdr starti !g.order)
+
+let get_rangeset g start end_ = StringSet.of_list (get_range g start end_)
+
+let print_dominated g =
+ let info nt rangeset exclude =
+ let reachable = StringSet.of_list (nt_closure g nt exclude) in
+ let unreachable = StringSet.of_list (nt_closure g (List.hd start_symbols) (nt::exclude)) in
+ let dominated = StringSet.diff reachable unreachable in
+ Printf.printf "For %s, 'attribute' is: reachable = %b, unreachable = %b, dominated = %b\n" nt
+ (StringSet.mem "attribute" reachable)
+ (StringSet.mem "attribute" unreachable)
+ (StringSet.mem "attribute" dominated);
+ Printf.printf " rangeset = %b excluded = %b\n"
+ (StringSet.mem "attribute" rangeset)
+ (List.mem "attribute" exclude);
+ reachable, dominated
+ in
+ let pr3 nt rangeset reachable dominated =
+ let missing = StringSet.diff dominated rangeset in
+ if not (StringSet.is_empty missing) then begin
+ Printf.printf "\nMissing in range for '%s':\n" nt;
+ StringSet.iter (fun nt -> Printf.printf " %s\n" nt) missing
+ end;
+
+ let unneeded = StringSet.diff rangeset reachable in
+ if not (StringSet.is_empty unneeded) then begin
+ Printf.printf "\nUnneeded in range for '%s':\n" nt;
+ StringSet.iter (fun nt -> Printf.printf " %s\n" nt) unneeded
+ end;
in
- let all_nts_ref, all_nts_def =
- get_nts (StringSet.of_list tokens) (StringSet.of_list tokens) (NTMap.bindings !g.map) in
+ let pr2 nt rangeset exclude =
+ let reachable, dominated = info nt rangeset exclude in
+ pr3 nt rangeset reachable dominated
+ in
+ let pr nt end_ = pr2 nt (get_rangeset g nt end_) [] in
+
+ let ssr_ltac = ["ssr_first_else"; "ssrmmod"; "ssrdotac"; "ssrortacarg";
+ "ssrparentacarg"] in
+ let ssr_tac = ["ssrintrosarg"; "ssrhintarg"; "ssrtclarg"; "ssrseqarg"; "ssrmovearg";
+ "ssrrpat"; "ssrclauses"; "ssrcasearg"; "ssrarg"; "ssrapplyarg"; "ssrexactarg";
+ "ssrcongrarg"; "ssrterm"; "ssrrwargs"; "ssrunlockargs"; "ssrfixfwd"; "ssrcofixfwd";
+ "ssrfwdid"; "ssrposefwd"; "ssrsetfwd"; "ssrdgens"; "ssrhavefwdwbinders"; "ssrhpats_nobs";
+ "ssrhavefwd"; "ssrsufffwd"; "ssrwlogfwd"; "ssrhint"; "ssrclear"; "ssr_idcomma";
+ "ssrrwarg"; "ssrintros_ne"; "ssrhint3arg" ] @ ssr_ltac in
+ let ssr_cmd = ["ssr_modlocs"; "ssr_search_arg"; "ssrhintref"; "ssrhintref_list";
+ "ssrviewpos"; "ssrviewposspc"] in
+ let ltac = ["ltac_expr"; "ltac_expr0"; "ltac_expr1"; "ltac_expr2"; "ltac_expr3"] in
+ let term = ["term"; "term0"; "term1"; "term10"; "term100"; "term9";
+ "pattern"; "pattern0"; "pattern1"; "pattern10"] in
+
+ pr "term" "constr";
+
+ let ltac_rangeset = List.fold_left StringSet.union StringSet.empty
+ [(get_rangeset g "ltac_expr" "tactic_atom");
+ (get_rangeset g "toplevel_selector" "range_selector");
+ (get_rangeset g "ltac_match_term" "match_pattern");
+ (get_rangeset g "ltac_match_goal" "match_pattern_opt")] in
+ pr2 "ltac_expr" ltac_rangeset ("simple_tactic" :: ssr_tac);
+
+ let dec_vern_rangeset = get_rangeset g "decorated_vernac" "opt_coercion" in
+ let dev_vern_excl =
+ ["gallina_ext"; "command"; "tactic_mode"; "syntax"; "command_entry"] @ term @ ltac @ ssr_tac in
+ pr2 "decorated_vernac" dec_vern_rangeset dev_vern_excl;
+
+ let simp_tac_range = get_rangeset g "simple_tactic" "hypident_occ_list_comma" in
+ let simp_tac_excl = ltac @ ssr_tac in
+ pr2 "simple_tactic" simp_tac_range simp_tac_excl;
+
+ let cmd_range = get_rangeset g "command" "int_or_id_list_opt" in
+ let cmd_excl = ssr_tac @ ssr_cmd in
+ pr2 "command" cmd_range cmd_excl;
+
+ let syn_range = get_rangeset g "syntax" "constr_as_binder_kind" in
+ let syn_excl = ssr_tac @ ssr_cmd in
+ pr2 "syntax" syn_range syn_excl;
+
+ let gext_range = get_rangeset g "gallina_ext" "Structure_opt" in
+ let gext_excl = ssr_tac @ ssr_cmd in
+ pr2 "gallina_ext" gext_range gext_excl;
+
+ let qry_range = get_rangeset g "query_command" "searchabout_query_list" in
+ let qry_excl = ssr_tac @ ssr_cmd in
+ pr2 "query_command" qry_range qry_excl
+
+ (* todo: tactic_mode *)
+
+let check_range_consistency g start end_ =
+ let defined_list = get_range g start end_ in
+ let defined = StringSet.of_list defined_list in
+ let referenced = List.fold_left (fun set nt ->
+ let prods = NTMap.find nt !g.map in
+ let refs = List.concat (List.map nts_in_prod prods) in
+ StringSet.union set (StringSet.of_list refs))
+ StringSet.empty defined_list
+ in
+ let undef = StringSet.diff referenced defined in
+ let unused = StringSet.diff defined referenced in
+ if StringSet.cardinal unused > 0 || (StringSet.cardinal undef > 0) then begin
+ Printf.printf "\nFor range '%s' to '%s':\n External reference:" start end_;
+ StringSet.iter (fun nt -> Printf.printf " %s" nt) undef;
+ Printf.printf "\n";
+ if StringSet.cardinal unused > 0 then begin
+ Printf.printf " Unreferenced:";
+ StringSet.iter (fun nt -> Printf.printf " %s" nt) unused;
+ Printf.printf "\n"
+ end
+ end
+
+(* print info on symbols with a single production of a single nonterminal *)
+let check_singletons g =
+ NTMap.iter (fun nt prods ->
+ if List.length prods = 1 then
+ if List.length (remove_Sedit2 (List.hd prods)) = 1 then
+ warn "Singleton non-terminal, maybe SPLICE?: %s\n" nt
+ else
+ (*warn "Single production, maybe SPLICE?: %s\n" nt*) ())
+ !g.map
+let report_bad_nts g file =
+ let all_nts_ref, all_nts_def = get_refdef_nts g in
let undef = StringSet.diff all_nts_ref all_nts_def in
List.iter (fun nt -> warn "%s: Undefined symbol '%s'\n" file nt) (StringSet.elements undef);
@@ -1287,12 +1518,13 @@ let finish_with_file old_file verify =
in
let temp_file = (old_file ^ "_temp") in
- if verify then
- if (files_eq old_file temp_file || !exit_code <> 0) then
- Sys.remove temp_file
- else
- error "%s is not current\n" old_file
- else
+ if !exit_code <> 0 then
+ Sys.remove temp_file
+ else if verify then begin
+ if not (files_eq old_file temp_file) then
+ error "%s is not current\n" old_file;
+ Sys.remove temp_file
+ end else
Sys.rename temp_file old_file
let open_temp_bin file =
@@ -1342,21 +1574,13 @@ let process_rst g file args seen tac_prods cmd_prods =
let ig_args_regex = Str.regexp "^[ \t]*\\([a-zA-Z0-9_\\.]*\\)[ \t]*\\([a-zA-Z0-9_\\.]*\\)" in
let blank_regex = Str.regexp "^[ \t]*$" in
let end_prodlist_regex = Str.regexp "^[ \t]*$" in
- let rec index_of_r str list index =
- match list with
- | [] -> None
- | hd :: list ->
- if hd = str then Some index
- else index_of_r str list (index+1)
- in
- let index_of str list = index_of_r str list 0 in
let getline () =
let line = input_line old_rst in
incr linenum;
line
in
+ (* todo: maybe pass end_index? *)
let output_insertgram start_index end_ indent is_coq_group =
- let rec nthcdr n list = if n = 0 then list else nthcdr (n-1) (List.tl list) in
let rec copy_prods list =
match list with
| [] -> ()
@@ -1390,10 +1614,12 @@ let process_rst g file args seen tac_prods cmd_prods =
error "%s line %d: '%s' is undefined\n" file !linenum start;
if end_index = None then
error "%s line %d: '%s' is undefined\n" file !linenum end_;
+ if start_index <> None && end_index <> None then
+ check_range_consistency g start end_;
match start_index, end_index with
| Some start_index, Some end_index ->
if start_index > end_index then
- error "%s line %d: '%s' must appear before '%s' in .../orderedGrammar\n" file !linenum start end_
+ error "%s line %d: '%s' must appear before '%s' in orderedGrammar\n" file !linenum start end_
else begin
try
let line2 = getline() in
@@ -1470,21 +1696,28 @@ let report_omitted_prods entries seen label split =
end
in
- let first, last, n = List.fold_left (fun missing nt ->
- let first, last, n = missing in
+ let first, last, n, total = List.fold_left (fun missing nt ->
+ let first, last, n, total = missing in
if NTMap.mem nt seen then begin
maybe_warn first last n;
- "", "", 0
+ "", "", 0, total
end else
- (if first = "" then nt else first), nt, n + 1)
- ("", "", 0) entries in
- maybe_warn first last n
+ (if first = "" then nt else first), nt, n + 1, total + 1)
+ ("", "", 0, 0) entries in
+ maybe_warn first last n;
+ if total <> 0 then
+ Printf.eprintf "TOTAL %ss not included = %d\n" label total
let process_grammar args =
let symdef_map = ref StringMap.empty in
let g = ref { map = NTMap.empty; order = [] } in
let level_renames = read_mlg_files g args symdef_map in
+ if args.verbose then begin
+ Printf.printf "Keywords:\n";
+ StringSet.iter (fun kw -> Printf.printf "%s " kw) !keywords;
+ Printf.printf "\n\n";
+ end;
(* rename nts with levels *)
List.iter (fun b -> let (nt, prod) = b in
@@ -1546,6 +1779,8 @@ let process_grammar args =
print_in_order out g `MLG !g.order StringSet.empty;
close_out out;
finish_with_file (dir "orderedGrammar") args.verify;
+ check_singletons g
+(* print_dominated g*)
end;
if !exit_code = 0 then begin
@@ -1558,6 +1793,8 @@ let process_grammar args =
let seen = ref { nts=NTMap.empty; tacs=NTMap.empty; cmds=NTMap.empty } in
List.iter (fun file -> process_rst g file args seen tac_prods cmd_prods) args.rst_files;
report_omitted_prods !g.order !seen.nts "Nonterminal" "";
+ let out = open_out (dir "updated_rsts") in
+ close_out out;
if args.check_tacs then
report_omitted_prods tac_list !seen.tacs "Tactic" "\n ";
if args.check_cmds then