Use the line splitting solution from the original source for splits outside of the...
[hiphop-php.git] / hphp / hack / src / hackfmt / chunk_group.ml
blobeb307cd3b1574f889477768b53d6f8578af1ac2e
1 (**
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
9 *)
11 open Core
13 type t = {
14 chunks: Chunk.t list;
15 rule_map: Rule.t IMap.t;
16 rule_dependency_map: (int list) IMap.t;
17 block_indentation: int;
20 let get_rule_count t =
21 IMap.cardinal t.rule_map
23 let get_rules t =
24 (* TODO verify or log if there are unused rules *)
25 List.map (IMap.bindings t.rule_map) ~f:fst
27 let get_rule_kind t id =
28 let r = IMap.find_unsafe id t.rule_map in
29 r.Rule.kind
31 let get_char_range t =
32 t.chunks |> List.fold ~init:(max_int,0)
33 ~f:(fun (start_char, end_char) chunk ->
34 let chunk_start, chunk_end = Chunk.get_range chunk in
35 min start_char chunk_start,
36 max end_char chunk_end
39 let constrain_rules t rbm rule_list =
40 let aux rule_id = Rule.cares_about_children (get_rule_kind t rule_id) in
41 let rules_that_care = List.filter rule_list ~f:aux in
42 List.fold rules_that_care ~init:rbm ~f:(fun acc k -> IMap.add k true acc)
44 let get_always_rule_bindings t =
45 let is_always_rule _k v = v.Rule.kind = Rule.Always in
46 let always_rules = IMap.filter is_always_rule t.rule_map in
47 IMap.map (fun _ -> true) always_rules
49 let get_initial_rule_bindings t =
50 let is_always_rule _k v = v.Rule.kind = Rule.Always in
51 let always_rules = IMap.filter is_always_rule t.rule_map in
52 let get_dependencies rule_id =
53 try IMap.find_unsafe rule_id t.rule_dependency_map with Not_found -> [] in
54 let constrain k _v acc = constrain_rules t acc (get_dependencies k) in
55 let init_map = IMap.map (fun _ -> true) always_rules in
56 IMap.fold constrain always_rules init_map
58 (* When a child rule is broken on, all its parent rules must break too. *)
59 let is_dependency_satisfied parent_kind parent_val child_val =
60 (* If the parent rule doesn't care about whether its child rules break, then
61 * the dependency doesn't matter. *)
62 if not (Rule.cares_about_children parent_kind) then true
63 else
64 (* Otherwise, the dependency is only unsatisfied when the parent rule is
65 * bound not to break and the child rule is bound to break. *)
66 match parent_val, child_val with
67 | Some false, true -> false
68 | _ -> true
70 let are_rule_bindings_valid t rbm =
71 let valid_map = IMap.mapi (fun rule_id v ->
72 let parent_list = try IMap.find_unsafe rule_id t.rule_dependency_map
73 with Not_found -> []
75 List.for_all parent_list ~f:(fun parent_id ->
76 let parent_rule = IMap.find_unsafe parent_id t.rule_map in
77 let parent_value = IMap.get parent_id rbm in
78 is_dependency_satisfied parent_rule.Rule.kind parent_value v
80 ) rbm in
81 List.for_all ~f:(fun x -> x) @@ List.map ~f:snd @@ IMap.bindings valid_map
83 let dependency_map_to_string t =
84 let get_map_values map = List.map ~f:snd @@ IMap.bindings @@ map in
85 let str_list = get_map_values @@ IMap.mapi (fun k v_list ->
86 let values = List.map v_list ~f:string_of_int in
87 string_of_int k ^ ": [" ^ String.concat ", " values ^ "]"
88 ) t.rule_dependency_map in
89 "{" ^ String.concat ", " str_list ^ "}"