File: pack.ml

package info (click to toggle)
dose3 7.0.0-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,276 kB
  • sloc: ml: 25,053; python: 605; perl: 391; sh: 347; makefile: 187
file content (304 lines) | stat: -rw-r--r-- 9,288 bytes parent folder | download | duplicates (6)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
(***********************************************************************)
(*                                                                     *)
(*                TypeRex : OCaml Development Tools                    *)
(*                                                                     *)
(*                       OCamlPro S.A.S.                               *)
(*                                                                     *)
(*  Copyright 2011 OCamlPro SAS                                        *)
(*  All rights reserved.  This file is distributed under the terms of  *)
(*  the GNU General Public License version 3.0.                        *)
(*                                                                     *)
(***********************************************************************)

let number = "1.0.1-dose3"

let functors_arg = ref []
let pack_functor_arg = ref None
let target_arg = ref None
let pp_arg = ref ""
let sources_arg = ref []
let rec_arg = ref false
let mli_arg = ref false
let ml_arg = ref true
let with_ns = ref false
let verbosity = ref 0
let file_number = ref 0

let oc_ml = ref None
let oc_mli = ref None

module StringSet = Set.Make(String)
module StringMap = Map.Make(String)

type namespace = {
  ns_name : string;
  mutable ns_closed : StringSet.t;
  mutable ns_open : namespace option;
}

let ns = {
  ns_name = "";
  ns_closed = StringSet.empty;
  ns_open = None;
}

let _ml s =
  match !oc_ml with
      None -> ()
    | Some oc -> output_string oc s

let _mli s =
  match !oc_mli with
      None -> ()
    | Some oc -> output_string oc s

let rec close_ns_open ns =
  match ns.ns_open with
      None -> ()
    | Some ns_in ->
      _ml "end\n";
      _mli "end\n";
      ns.ns_open <- None;
      ns.ns_closed <- StringSet.add ns_in.ns_name ns.ns_closed;
      close_ns_open ns_in

let with_process_in cmd args f =
  (*
  let path = ["/bin";"/usr/bin"] in
  let cmd =
    try
      List.find Sys.file_exists (List.map (fun d -> Filename.concat d cmd) path)
    with Not_found -> failwith (cmd^" Not found")
  in
  *)
  let ic = Unix.open_process_in (cmd^" "^args) in
  try
    let r = f ic in
    ignore (Unix.close_process_in ic) ; r
  with exn ->
      ignore (Unix.close_process_in ic) ; raise exn

let dump_file _p filename =
  if !verbosity > 0 then
    Printf.eprintf "dump_file %s\n" filename;
  _p (Printf.sprintf "#1 \"%s\"\n" filename);
  let f ic =
    try
      while true do
        let line = input_line ic in
        _p (Printf.sprintf "%s\n" line)
      done;
    with End_of_file ->
      close_in ic
  in
  match !pp_arg with
  |"" -> f (open_in filename)
  |pp -> with_process_in pp filename f

let split s c =
  let len = String.length s in
  let rec iter pos =
    try
      if pos = len then [""] else
	let pos2 = String.index_from s pos c in
	if pos2 = pos then "" :: iter (pos+1) else
          (String.sub s pos (pos2-pos)) :: (iter (pos2+1))
    with _ -> [String.sub s pos (len-pos)]
  in
  iter 0

let split_filename filename = split filename '/'

let name = Sys.argv.(0)

let arg_usage = Printf.sprintf "\
Usage:

   %s -o target.ml [options] files.ml*

Options:
" name

let version () = Printf.printf "\
ocp-pack version %s

Copyright (C) 2011 OCamlPro S.A.S.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

"
  number;
  exit 0


let arg_list = Arg.align [
  "-o", Arg.String (fun s -> target_arg := Some s),
  " <filename.ml> : generate filename filename.ml";
  "-pp", Arg.Set_string pp_arg, " <pp> : pre-process ml files";
  "-rec", Arg.Set rec_arg, " : use recursive modules (all .ml files must have a corresponding .mli file)";
    "-pack-functor", Arg.String (fun s -> pack_functor_arg := Some s),
  "<modname> : create functor with name <modname>";
  "-functor", Arg.String (fun s -> functors_arg := s :: !functors_arg),
  " <filename.mli> : use filename as an argument for functor";
  "-mli", Arg.Set mli_arg, " : output the .mli file too (.ml files without .mli file will not export any value)";
  "-no-ml", Arg.Clear ml_arg, " : do not output the .ml file";
  "-with-ns", Arg.Set with_ns, " : use directory structure to create a hierarchy of modules";
  "-v", Arg.Unit (fun _ -> incr verbosity), " : increment verbosity";
  "-version", Arg.Unit version,
  "               display version information";
]

let error msg =
  Printf.eprintf "ERROR: %s\n\n%!" msg;
  Arg.usage arg_list arg_usage;
  exit 2

let _ =
  Arg.parse arg_list (fun s -> sources_arg := s :: !sources_arg) arg_usage



let rec output_file ns prefix filename =
  let full_filename = String.concat "/" (prefix @ filename) in
  let dirname = Filename.dirname full_filename in

  match filename with
      [] -> assert false
    | ("." | "") :: filename ->
      output_file ns prefix filename
    | [ basename ] ->
      let basename = Filename.chop_extension basename in
      let ml_filename = Filename.concat dirname (basename ^ ".ml") in
      let mli_filename = Filename.concat dirname (basename ^ ".mli") in

      let modname = String.capitalize basename in
      close_ns_open ns;
      if StringSet.mem modname ns.ns_closed then
	error (Printf.sprintf "module %s already opened when reading %s" modname ml_filename);


      let has_ml_file = Sys.file_exists ml_filename in
      let has_mli_file = Sys.file_exists mli_filename in

      let keyword =
	if !rec_arg then
	  if !file_number = 0 then "module rec" else "and"
	else "module"
      in

      if has_ml_file then begin
	if has_mli_file then
	  begin
	    _mli (Printf.sprintf "%s %s : sig\n" keyword modname);
	    dump_file _mli mli_filename;
	    _mli (Printf.sprintf "end\n");
	  end
	else
	  if !rec_arg then
	    failwith (Printf.sprintf "File %s needs an interface with -rec option" ml_filename);

	_ml (Printf.sprintf "%s %s" keyword modname);
	if has_mli_file then begin
	  _ml (Printf.sprintf ": sig\n");
	  dump_file _ml mli_filename;
	  _ml (Printf.sprintf "end = struct\n");
	  if !rec_arg then begin
	    _ml (Printf.sprintf "module type INTERFACE = sig\n");
	    dump_file _ml mli_filename;
	    _ml (Printf.sprintf "end\n");
	    _ml (Printf.sprintf "module IMPLEMENTATION = struct\n");
	    dump_file _ml ml_filename;
	    _ml (Printf.sprintf "end\n");
	    _ml (Printf.sprintf "include (IMPLEMENTATION : INTERFACE)\n");
	  end else begin
	    dump_file _ml ml_filename;
	  end;
	  _ml (Printf.sprintf "end\n");
	end else begin
	  _ml (Printf.sprintf " = struct\n");
	  dump_file _ml ml_filename;
	  _ml (Printf.sprintf "end\n");
	end
      end else begin
	_ml (Printf.sprintf  "%s %s : sig\n" keyword modname);
	dump_file _ml mli_filename;
	_ml (Printf.sprintf  "end = struct\n");
	dump_file _ml mli_filename;
	_ml (Printf.sprintf  "end\n");

	_mli (Printf.sprintf "%s %s : sig\n" keyword modname);
	dump_file _mli mli_filename;
	_mli (Printf.sprintf "end\n");
      end;

      ns.ns_closed <- StringSet.add modname ns.ns_closed

    | dirname :: tail ->
      if !with_ns then
	let modname = String.capitalize dirname in
	if StringSet.mem modname ns.ns_closed then
	  failwith (Printf.sprintf "module %s already closed when reading %s" modname full_filename);
	let ns_in =
	  match ns.ns_open with
	      Some ns_in when ns_in.ns_name = modname -> ns_in
	    | _ ->
	      close_ns_open ns;
	      let ns_in = {
		ns_name = modname;
		ns_closed = StringSet.empty;
		ns_open = None;
	      } in
	      _mli (Printf.sprintf  "module %s : sig\n" modname);
	      _ml (Printf.sprintf  "module %s = struct \n" modname);
	      ns.ns_open <- Some ns_in;
	      ns_in
	in
	output_file ns_in (prefix @[ dirname ]) tail
      else
	output_file ns (prefix @[ dirname ]) tail

let _ =
  sources_arg := List.rev !sources_arg;
  match !target_arg with
      None -> error "You must specify a target with -o target.ml"
    | Some target ->
      if !ml_arg then oc_ml := Some (open_out target);
      if !mli_arg then oc_mli  := Some ( open_out (target ^ "i") );
      (match !pack_functor_arg with
	  None -> ()
	| Some modname ->
	  _ml (Printf.sprintf "module %s" modname);
	  List.iter (fun mli_filename ->
	    let modname = String.capitalize (Filename.chop_suffix (Filename.basename mli_filename) ".mli")in
	    _ml (Printf.sprintf "(%s : sig\n" modname);
	    dump_file _ml mli_filename;
	    _ml ("\nend)\n");
	  ) (List.rev !functors_arg);
	  _ml (Printf.sprintf " = struct\n");
      );
      List.iter (fun filename ->
	if Filename.check_suffix filename ".ml" ||
	  Filename.check_suffix filename ".mli"
	then begin
	  if !verbosity > 0 then
	    Printf.eprintf "Inserting %s\n" filename;
	  let filename = split_filename filename in
	  output_file ns [] filename;
	  incr file_number;
	end else
(*	if Filename.check_suffix filename ".mli" then
	  Printf.fprintf stderr "Discarding interface file %s\n%!" filename
	else *)
	  error (Printf.sprintf "Don't know what to do with anonymous argument [%s]" filename)
      ) !sources_arg;
      close_ns_open ns;
      (match !pack_functor_arg with
	  None -> ()
	| Some modname ->
	  _ml (Printf.sprintf "\nend\n");
      );
      (match !oc_ml with None -> () | Some oc ->
	close_out oc; oc_ml := None);
      (match !oc_mli with None -> () | Some oc ->
	close_out oc; oc_mli := None)