4 exception NoRuleFailure
10 | Many of filetype list
12 type ('a,'b) cmd = 'a -> 'b -> filename -> string list
17 cmd : 'a -> filename list -> filename -> string list
21 let one_to_one src dest cmd = {
24 cmd = (fun a -> function [x] -> cmd a x | _ -> invalid_arg "")
29 Many (List.unique @@ List.sort ~cmp:compare xs)
31 let many_to_one src dest cmd = {
37 let is_loop {src=src; dest=dest} =
40 | Many xs -> xs = [dest]
42 let is_reach dest {dest=dest'} =
49 let reachable dest rs =
50 List.filter (is_reach dest) rs
54 if f a b then a else b in
57 invalid_arg "empty list"
59 List.fold_left min y ys
61 let remove_rule xs x =
62 List.remove_if (fun {src=src; dest=dest}-> x.src=src && x.dest=dest) xs
64 let rec shortest rs src dest =
66 One x,One y when x = y ->
68 | One x,Many ys when [x] = ys ->
70 | Many xs,Many ys when xs = ys ->
72 | One _,One _ | Many _,Many _| One _,Many _ | Many _,One _ ->
75 +> HList.concat_map begin fun r ->
76 match shortest (remove_rule rs r) src r.src with
80 if shortests = [] then
83 Some (minimum_by (fun a b -> List.length a < List.length b) shortests)
87 Str.regexp ".*\\.\\(.*\\)$" in
88 if Str.string_match regexp x 0 then
91 invalid_arg "no suffix"
95 (Filename.chop_suffix name (suffix name))
98 let route rs inputs output =
104 many (List.map suffix xs) in
106 One (suffix output) in
109 let commands ctx rs inputs output =
110 match route rs inputs output with
114 r +> List.rev +> map_accum_left
115 (fun inputs' {dest=dest; cmd=cmd} ->
116 [tmp output dest],cmd ctx inputs' @@ tmp output dest)
121 let temp_files _ rs inputs output =
122 match route rs inputs output with
123 | None | Some [] | Some [_] ->