File: gen_rules_lib.ml

package info (click to toggle)
ocaml-odoc 2.1.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,744 kB
  • sloc: ml: 37,049; makefile: 124; sh: 79
file content (191 lines) | stat: -rw-r--r-- 5,378 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
type sexp = Sexplib0.Sexp.t = Atom of string | List of sexp list

type enabledif = Min of string | Max of string | MinMax of string * string

type test_case = {
  input : Fpath.t;
  cmt : Fpath.t option;  (** [None] for mld files. *)
  odoc : Fpath.t;
  odocl : Fpath.t;
  enabledif : enabledif option;
}

module Dune = struct
  let arg_fpath f = Fpath.to_string f

  let arg_dep f = "%{dep:" ^ Fpath.to_string f ^ "}"

  let arg_list args = List.map (fun x -> Atom x) args

  let render_enabledif = function
    | Some (Min v) ->
        [
          List
            [
              Atom "enabled_if";
              List [ Atom ">="; Atom "%{ocaml_version}"; Atom v ];
            ];
        ]
    | Some (Max v) ->
        [
          List
            [
              Atom "enabled_if";
              List [ Atom "<="; Atom "%{ocaml_version}"; Atom v ];
            ];
        ]
    | Some (MinMax (min, max)) ->
        [
          List
            [
              Atom "enabled_if";
              List
                [
                  Atom "and";
                  List [ Atom ">="; Atom "%{ocaml_version}"; Atom min ];
                  List [ Atom "<="; Atom "%{ocaml_version}"; Atom max ];
                ];
            ];
        ]
    | None -> []

  let run cmd = List (Atom "run" :: arg_list cmd)

  let action x = List [ Atom "action"; x ]

  let rule ?enabledif fields =
    List ((Atom "rule" :: fields) @ render_enabledif enabledif)

  let simple_rule ?enabledif target cmd =
    rule ?enabledif
      [ List [ Atom "target"; Atom (arg_fpath target) ]; action (run cmd) ]

  let rule_with_output_to ?enabledif target cmd =
    rule ?enabledif
      [
        action
          (List [ Atom "with-outputs-to"; Atom (arg_fpath target); run cmd ]);
      ]

  let runtest_diff ?enabledif file_a file_b =
    rule ?enabledif
      [
        List [ Atom "alias"; Atom "runtest" ];
        action
          (List
             [ Atom "diff"; Atom (arg_fpath file_a); Atom (arg_fpath file_b) ]);
      ]

  let subdir dir rules = List (Atom "subdir" :: Atom (arg_fpath dir) :: rules)
end

let cu_target_rule enabledif dep target =
  Dune.simple_rule ?enabledif target
    [ "ocamlc"; "-c"; "-bin-annot"; "-o"; "%{target}"; Dune.arg_dep dep ]

let odoc_target_rule enabledif dep target =
  Dune.simple_rule ?enabledif target
    [ "odoc"; "compile"; "-o"; "%{target}"; Dune.arg_dep dep ]

let odocl_target_rule enabledif dep target =
  Dune.simple_rule ?enabledif target
    [ "odoc"; "link"; "-o"; "%{target}"; Dune.arg_dep dep ]

let gen_rule_for_source_file { input; cmt; odoc; odocl; enabledif } =
  let cmt_rule, input =
    match cmt with
    | Some cmt -> ([ cu_target_rule enabledif input cmt ], cmt)
    | None -> ([], input)
  in
  cmt_rule
  @ [
      odoc_target_rule enabledif input odoc;
      odocl_target_rule enabledif odoc odocl;
    ]

let read_lines ic =
  let lines = ref [] in
  try
    while true do
      lines := input_line ic :: !lines
    done;
    assert false
  with End_of_file -> List.rev !lines

let lines_of_file path =
  let ic = open_in (Fpath.to_string path) in
  let lines = read_lines ic in
  close_in ic;
  lines

let targets_file_path f = Fpath.(base f |> set_ext ".targets")

let expected_targets backend test_case =
  let targets_file = Fpath.( // ) backend (targets_file_path test_case) in
  try lines_of_file targets_file |> List.map Fpath.v with _ -> []

let gen_targets_file enabledif ?flat_flag backend target_path relinput =
  let flat_flag = match flat_flag with None -> [] | Some x -> [ x ] in
  let gen_path = Fpath.add_ext ".gen" target_path in
  [
    Dune.subdir backend
      [
        Dune.rule_with_output_to ?enabledif gen_path
          ([
             "odoc";
             Fpath.to_string backend ^ "-targets";
             "-o";
             ".";
             Dune.arg_dep relinput;
           ]
          @ flat_flag);
        Dune.runtest_diff ?enabledif target_path gen_path;
      ];
  ]

let gen_backend_diff_rule enabledif ~targets (b_t_r, b, _) p =
  match targets with
  | [] -> []
  | _ ->
      let targets_gen = List.map (Fpath.add_ext ".gen") targets in
      Dune.
        [
          subdir b
            (rule ?enabledif
               [
                 List
                   (Atom "targets"
                   :: List.map (fun t -> Atom (Dune.arg_fpath t)) targets_gen);
                 action (run (b_t_r p));
               ]
            :: List.map2 (Dune.runtest_diff ?enabledif) targets targets_gen);
        ]

let gen_backend_rule enabledif backend_target_rules path =
  List.map
    (fun b_t_r ->
      let _, b, flat_flag = b_t_r in
      let targets = expected_targets b path in
      let relpath =
        let path = Fpath.relativize ~root:b path in
        match path with Some p -> p | None -> assert false
      in
      let targets_file = targets_file_path relpath in
      [
        gen_backend_diff_rule enabledif ~targets b_t_r relpath;
        gen_targets_file enabledif ?flat_flag b targets_file relpath;
      ]
      |> List.concat)
    backend_target_rules
  |> List.flatten

let gen_rule backend_target_rules test_cases =
  List.concat
    [
      List.(concat (map gen_rule_for_source_file test_cases));
      List.map
        (fun case ->
          gen_backend_rule case.enabledif backend_target_rules case.odocl)
        test_cases
      |> List.flatten;
    ]