diff options
Diffstat (limited to 'tools/addlabels.ml')
| -rw-r--r-- | tools/addlabels.ml | 451 |
1 files changed, 0 insertions, 451 deletions
diff --git a/tools/addlabels.ml b/tools/addlabels.ml deleted file mode 100644 index 5a98e161e1..0000000000 --- a/tools/addlabels.ml +++ /dev/null @@ -1,451 +0,0 @@ -(* $Id$ *) - -open StdLabels -open Asttypes -open Parsetree - -let norec = ref false - -let input_file file = - let ic = try open_in file with _ -> failwith ("input_file : " ^ file) in - let b = Buffer.create 1024 in - let buf = String.create 1024 and len = ref 0 in - while len := input ic buf 0 1024; !len > 0 do - Buffer.add_substring b buf 0 !len - done; - close_in ic; - Buffer.contents b - -module SMap = struct - include Map.Make(struct type t = string let compare = compare end) - let rec removes l m = - match l with [] -> m - | k::l -> - let m = try remove k m with Not_found -> m in - removes l m -end - -let rec labels_of_sty sty = - match sty.ptyp_desc with - Ptyp_arrow (lab, _, rem) -> lab :: labels_of_sty rem - | Ptyp_alias (rem, _) -> labels_of_sty rem - | _ -> [] - -let rec labels_of_cty cty = - match cty.pcty_desc with - Pcty_fun (lab, _, rem) -> - let (labs, meths) = labels_of_cty rem in - (lab :: labs, meths) - | Pcty_signature (_, fields) -> - ([], - List.fold_left fields ~init:[] ~f: - begin fun meths -> function - Pctf_meth (s, _, sty, _) -> (s, labels_of_sty sty)::meths - | _ -> meths - end) - | _ -> - ([],[]) - -let rec pattern_vars pat = - match pat.ppat_desc with - Ppat_var s -> [s] - | Ppat_alias (pat, s) -> - s :: pattern_vars pat - | Ppat_tuple l - | Ppat_array l -> - List.concat (List.map pattern_vars l) - | Ppat_construct (_, Some pat, _) - | Ppat_variant (_, Some pat) - | Ppat_constraint (pat, _) -> - pattern_vars pat - | Ppat_record l -> - List.concat (List.map l ~f:(fun (_,p) -> pattern_vars p)) - | Ppat_or (pat1, pat2) -> - pattern_vars pat1 @ pattern_vars pat2 - | Ppat_any | Ppat_constant _ | Ppat_construct _ | Ppat_variant _ - | Ppat_type _ -> - [] - -let pattern_name pat = - match pat.ppat_desc with - Ppat_var s -> Some s - | Ppat_constraint ({ppat_desc = Ppat_var s}, _) -> Some s - | _ -> None - -let insertions = ref [] -let add_insertion pos s = insertions := (pos,s) :: !insertions -let sort_insertions () = - List.sort !insertions ~cmp:(fun (pos1,_) (pos2,_) -> pos1 - pos2) - -let is_space = function ' '|'\t'|'\n'|'\r' -> true | _ -> false -let is_alphanum = function 'A'..'Z'|'a'..'z'|'_'|'\192'..'\214'|'\216'..'\246' - | '\248'..'\255'|'\''|'0'..'9' -> true - | _ -> false - -(* Remove "(" or "begin" before a pattern *) -let rec insertion_point pos ~text = - let pos' = ref (pos-1) in - while is_space text.[!pos'] do decr pos' done; - if text.[!pos'] = '(' then insertion_point !pos' ~text else - if !pos' >= 5 && String.sub text ~pos:(!pos'-4) ~len:5 = "begin" - && not (is_alphanum text.[!pos'-5]) then insertion_point (!pos'-4) ~text - else pos - -(* Search "=" or "->" before "function" *) -let rec insertion_point2 pos ~text = - let pos' = ref (pos-1) in - while is_space text.[!pos'] do decr pos' done; - if text.[!pos'] = '(' then insertion_point2 !pos' ~text else - if !pos' >= 5 && String.sub text ~pos:(!pos'-4) ~len:5 = "begin" - && not (is_alphanum text.[!pos'-5]) then insertion_point2 (!pos'-4) ~text - else if text.[!pos'] = '=' then Some !pos' else - if !pos' >= 1 && text.[!pos'-1] = '-' && text.[!pos'] = '>' - then Some (!pos' - 1) - else None - -let rec insert_labels ~labels ~text expr = - match labels, expr.pexp_desc with - l::labels, Pexp_function(l', _, [pat, rem]) -> - if l <> "" && l.[0] <> '?' && l' = "" then begin - let start_c = pat.ppat_loc.Location.loc_start.Lexing.pos_cnum in - let pos = insertion_point start_c ~text in - match pattern_name pat with - | Some name when l = name -> add_insertion pos "~" - | _ -> add_insertion pos ("~" ^ l ^ ":") - end; - insert_labels ~labels ~text rem - | l::labels, Pexp_function(l', _, lst) -> - let pos = expr.pexp_loc.Location.loc_start.Lexing.pos_cnum in - if l <> "" && l.[0] <> '?' && l' = "" - && String.sub text ~pos ~len:8 = "function" then begin - String.blit ~src:"match th" ~src_pos:0 ~dst:text - ~dst_pos:pos ~len:8; - add_insertion (pos+6) (l ^ " wi"); - match insertion_point2 pos ~text with - Some pos' -> - add_insertion pos' ("~" ^ l ^ " ") - | None -> - add_insertion pos ("fun ~" ^ l ^ " -> ") - end; - List.iter lst ~f:(fun (p,e) -> insert_labels ~labels ~text e) - | _, Pexp_match( _, lst) -> - List.iter lst ~f:(fun (p,e) -> insert_labels ~labels ~text e) - | _, Pexp_try(expr, lst) -> - insert_labels ~labels ~text expr; - List.iter lst ~f:(fun (p,e) -> insert_labels ~labels ~text e) - | _, ( Pexp_let(_,_,e) | Pexp_sequence(_,e) | Pexp_when(_,e) - | Pexp_constraint(e,_,_) | Pexp_letmodule(_,_,e) - | Pexp_ifthenelse(_,e,None) ) -> - insert_labels ~labels ~text e - | _, Pexp_ifthenelse (_, e1, Some e2) -> - insert_labels ~labels ~text e1; - insert_labels ~labels ~text e2 - | _ -> - () - -let rec insert_labels_class ~labels ~text expr = - match labels, expr.pcl_desc with - l::labels, Pcl_fun(l', _, pat, rem) -> - if l <> "" && l.[0] <> '?' && l' = "" then begin - let start_c = pat.ppat_loc.Location.loc_start.Lexing.pos_cnum in - let pos = insertion_point start_c ~text in - match pattern_name pat with - | Some name when l = name -> add_insertion pos "~" - | _ -> add_insertion pos ("~" ^ l ^ ":") - end; - insert_labels_class ~labels ~text rem - | labels, (Pcl_constraint (expr, _) | Pcl_let (_, _, expr)) -> - insert_labels_class ~labels ~text expr - | _ -> - () - -let rec insert_labels_type ~labels ~text ty = - match labels, ty.ptyp_desc with - l::labels, Ptyp_arrow(l', _, rem) -> - if l <> "" && l.[0] <> '?' && l' = "" then begin - let start_c = ty.ptyp_loc.Location.loc_start.Lexing.pos_cnum in - let pos = insertion_point start_c ~text in - add_insertion pos (l ^ ":") - end; - insert_labels_type ~labels ~text rem - | _ -> - () - -let rec insert_labels_app ~labels ~text args = - match labels, args with - l::labels, (l',arg)::args -> - if l <> "" && l.[0] <> '?' && l' = "" then begin - let pos0 = arg.pexp_loc.Location.loc_start.Lexing.pos_cnum in - let pos = insertion_point pos0 ~text in - match arg.pexp_desc with - | Pexp_ident(Longident.Lident name) when l = name && pos = pos0 -> - add_insertion pos "~" - | _ -> add_insertion pos ("~" ^ l ^ ":") - end; - insert_labels_app ~labels ~text args - | _ -> - () - -let insert_labels_app ~labels ~text args = - let labels, opt_labels = - List.partition labels ~f:(fun l -> l = "" || l.[0] <> '?') in - let nopt_labels = - List.map opt_labels - ~f:(fun l -> String.sub l ~pos:1 ~len:(String.length l - 1)) in - (* avoid ambiguous labels *) - if List.exists labels ~f:(List.mem ~set:nopt_labels) then () else - let aopt_labels = opt_labels @ nopt_labels in - let args, lab_args = List.partition args ~f:(fun (l,_) -> l = "") in - (* only optional arguments are labeled *) - if List.for_all lab_args ~f:(fun (l,_) -> List.mem l ~set:aopt_labels) - then insert_labels_app ~labels ~text args - -let rec add_labels_expr ~text ~values ~classes expr = - let add_labels_rec ?(values=values) expr = - add_labels_expr ~text ~values ~classes expr in - match expr.pexp_desc with - Pexp_apply ({pexp_desc=Pexp_ident(Longident.Lident s)}, args) -> - begin try - let labels = SMap.find s values in - insert_labels_app ~labels ~text args - with Not_found -> () - end; - List.iter args ~f:(fun (_,e) -> add_labels_rec e) - | Pexp_apply ({pexp_desc=Pexp_send - ({pexp_desc=Pexp_ident(Longident.Lident s)},meth)}, args) -> - begin try - if SMap.find s values = ["<object>"] then - let labels = SMap.find (s ^ "#" ^ meth) values in - insert_labels_app ~labels ~text args - with Not_found -> () - end - | Pexp_apply ({pexp_desc=Pexp_new (Longident.Lident s)}, args) -> - begin try - let labels = SMap.find s classes in - insert_labels_app ~labels ~text args - with Not_found -> () - end - | Pexp_let (recp, lst, expr) -> - let vars = List.concat (List.map lst ~f:(fun (p,_) -> pattern_vars p)) in - let vals = SMap.removes vars values in - List.iter lst ~f: - begin fun (_,e) -> - add_labels_rec e ~values:(if recp = Recursive then vals else values) - end; - add_labels_rec expr ~values:vals - | Pexp_function (_, None, lst) -> - List.iter lst ~f: - (fun (p,e) -> - add_labels_rec e ~values:(SMap.removes (pattern_vars p) values)) - | Pexp_function (_, Some e, lst) - | Pexp_match (e, lst) - | Pexp_try (e, lst) -> - add_labels_rec e; - List.iter lst ~f: - (fun (p,e) -> - add_labels_rec e ~values:(SMap.removes (pattern_vars p) values)) - | Pexp_apply (e, args) -> - List.iter add_labels_rec (e :: List.map snd args) - | Pexp_tuple l | Pexp_array l -> - List.iter add_labels_rec l - | Pexp_construct (_, Some e, _) - | Pexp_variant (_, Some e) - | Pexp_field (e, _) - | Pexp_constraint (e, _, _) - | Pexp_send (e, _) - | Pexp_setinstvar (_, e) - | Pexp_letmodule (_, _, e) - | Pexp_assert e - | Pexp_lazy e - | Pexp_poly (e, _) -> - add_labels_rec e - | Pexp_record (lst, opt) -> - List.iter lst ~f:(fun (_,e) -> add_labels_rec e); - begin match opt with Some e -> add_labels_rec e | None -> () end - | Pexp_setfield (e1, _, e2) - | Pexp_ifthenelse (e1, e2, None) - | Pexp_sequence (e1, e2) - | Pexp_while (e1, e2) - | Pexp_when (e1, e2) -> - add_labels_rec e1; add_labels_rec e2 - | Pexp_ifthenelse (e1, e2, Some e3) -> - add_labels_rec e1; add_labels_rec e2; add_labels_rec e3 - | Pexp_for (s, e1, e2, _, e3) -> - add_labels_rec e1; add_labels_rec e2; - add_labels_rec e3 ~values:(SMap.removes [s] values) - | Pexp_override lst -> - List.iter lst ~f:(fun (_,e) -> add_labels_rec e) - | Pexp_ident _ | Pexp_constant _ | Pexp_construct _ | Pexp_variant _ - | Pexp_new _ | Pexp_assertfalse | Pexp_object _ -> - () - -let rec add_labels_class ~text ~classes ~values ~methods cl = - match cl.pcl_desc with - Pcl_constr _ -> () - | Pcl_structure (p, l) -> - let values = SMap.removes (pattern_vars p) values in - let values = - match pattern_name p with None -> values - | Some s -> - List.fold_left methods - ~init:(SMap.add s ["<object>"] values) - ~f:(fun m (k,l) -> SMap.add (s^"#"^k) l m) - in - List.fold_left l ~init:values ~f: - begin fun values -> function - | Pcf_val (s, _, e, _) -> - add_labels_expr ~text ~classes ~values e; - SMap.removes [s] values - | Pcf_meth (s, _, e, _) -> - begin try - let labels = List.assoc s methods in - insert_labels ~labels ~text e - with Not_found -> () - end; - add_labels_expr ~text ~classes ~values e; - values - | Pcf_init e -> - add_labels_expr ~text ~classes ~values e; - values - | Pcf_inher _ | Pcf_virt _ | Pcf_cstr _ -> values - | Pcf_let _ -> values (* not in the grammar *) - end; - () - | Pcl_fun (_, opt, pat, cl) -> - begin match opt with None -> () - | Some e -> add_labels_expr ~text ~classes ~values e - end; - let values = SMap.removes (pattern_vars pat) values in - add_labels_class ~text ~classes ~values ~methods cl - | Pcl_apply (cl, args) -> - List.map args ~f:(fun (_,e) -> add_labels_expr ~text ~classes ~values e); - add_labels_class ~text ~classes ~values ~methods cl - | Pcl_let (recp, lst, cl) -> - let vars = List.concat (List.map lst ~f:(fun (p,_) -> pattern_vars p)) in - let vals = SMap.removes vars values in - List.iter lst ~f: - begin fun (_,e) -> - add_labels_expr e ~text ~classes - ~values:(if recp = Recursive then vals else values) - end; - add_labels_class cl ~text ~classes ~values:vals ~methods - | Pcl_constraint (cl, _) -> - add_labels_class ~text ~classes ~values ~methods cl - -let add_labels ~intf ~impl ~file = - insertions := []; - let values, classes = - List.fold_left intf ~init:(SMap.empty, SMap.empty) ~f: - begin fun (values, classes as acc) item -> - match item.psig_desc with - Psig_value (name, {pval_type = sty}) -> - (SMap.add name (labels_of_sty sty) values, classes) - | Psig_class l -> - (values, - List.fold_left l ~init:classes ~f: - begin fun classes {pci_name=name; pci_expr=cty} -> - SMap.add name (labels_of_cty cty) classes - end) - | _ -> - acc - end - in - let text = input_file file in - List.fold_right impl ~init:(values, classes) ~f: - begin fun item (values, classes as acc) -> - match item.pstr_desc with - Pstr_value (recp, l) -> - let names = - List.concat (List.map l ~f:(fun (p,_) -> pattern_vars p)) in - List.iter l ~f: - begin fun (pat, expr) -> - begin match pattern_name pat with - | Some s -> - begin try - let labels = SMap.find s values in - insert_labels ~labels ~text expr; - if !norec then () else - let values = - SMap.fold - (fun s l m -> - if List.mem s names then SMap.add s l m else m) - values SMap.empty in - add_labels_expr expr ~text ~values ~classes:SMap.empty - with Not_found -> () - end - | None -> () - end; - end; - (SMap.removes names values, classes) - | Pstr_primitive (s, {pval_type=sty}) -> - begin try - let labels = SMap.find s values in - insert_labels_type ~labels ~text sty; - (SMap.removes [s] values, classes) - with Not_found -> acc - end - | Pstr_class l -> - let names = List.map l ~f:(fun pci -> pci.pci_name) in - List.iter l ~f: - begin fun {pci_name=name; pci_expr=expr} -> - try - let (labels, methods) = SMap.find name classes in - insert_labels_class ~labels ~text expr; - if !norec then () else - let classes = - SMap.fold - (fun s (l,_) m -> - if List.mem s names then SMap.add s l m else m) - classes SMap.empty in - add_labels_class expr ~text ~classes ~methods - ~values:SMap.empty - with Not_found -> () - end; - (values, SMap.removes names classes) - | _ -> - acc - end; - if !insertions <> [] then begin - let backup = file ^ ".bak" in - if Sys.file_exists backup then Sys.remove file - else Sys.rename file backup; - let oc = open_out file in - let last_pos = - List.fold_left (sort_insertions ()) ~init:0 ~f: - begin fun pos (pos', s) -> - output oc text pos (pos'-pos); - output_string oc s; - pos' - end in - if last_pos < String.length text then - output oc text last_pos (String.length text - last_pos); - close_out oc - end - else prerr_endline ("No labels to insert in " ^ file) - -let process_file file = - prerr_endline ("Processing " ^ file); - if Filename.check_suffix file ".ml" then - let intf = Filename.chop_suffix file ".ml" ^ ".mli" in - let ic = open_in intf in - let lexbuf = Lexing.from_channel ic in - Location.init lexbuf intf; - let intf = Parse.interface lexbuf in - close_in ic; - let ic = open_in file in - let lexbuf = Lexing.from_channel ic in - Location.init lexbuf file; - let impl = Parse.implementation lexbuf in - close_in ic; - add_labels ~intf ~impl ~file - else prerr_endline (file ^ " is not an implementation") - -let main () = - let files = ref [] in - Arg.parse ["-norec", Arg.Set norec, "do not labelize recursive calls"] - (fun f -> files := f :: !files) - "addlabels [-norec] <files>"; - let files = List.rev !files in - List.iter files ~f:process_file - -let () = main () |
