Release coccinelle-0.2.3rc1
[bpt/coccinelle.git] / commons / common.ml
CommitLineData
b1b2de81
C
1(* Yoann Padioleau
2 *
ae4735db 3 * Copyright (C) 2010 INRIA, University of Copenhagen DIKU
b1b2de81 4 * Copyright (C) 1998-2009 Yoann Padioleau
34e49164
C
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * version 2.1 as published by the Free Software Foundation, with the
9 * special exception on linking described in file license.txt.
ae4735db 10 *
34e49164
C
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
14 * license.txt for more details.
15 *)
16
17(*****************************************************************************)
18(* Notes *)
19(*****************************************************************************)
20
21
22
23(* ---------------------------------------------------------------------- *)
24(* Maybe could split common.ml and use include tricks as in ofullcommon.ml or
25 * Jane Street core lib. But then harder to bundle simple scripts like my
26 * make_full_linux_kernel.ml because would then need to pass all the files
27 * either to ocamlc or either to some #load. Also as the code of many
28 * functions depends on other functions from this common, it would
29 * be tedious to add those dependencies. Here simpler (have just the
30 * pb of the Prelude, but it's a small problem).
ae4735db 31 *
34e49164
C
32 * pixel means code from Pascal Rigaux
33 * julia means code from Julia Lawall
34 *)
35(* ---------------------------------------------------------------------- *)
36
37(*****************************************************************************)
38(* We use *)
39(*****************************************************************************)
ae4735db 40(*
34e49164
C
41 * modules:
42 * - Pervasives, of course
43 * - List
44 * - Str
45 * - Hashtbl
ae4735db 46 * - Format
34e49164
C
47 * - Buffer
48 * - Unix and Sys
49 * - Arg
ae4735db
C
50 *
51 * functions:
52 * - =, <=, max min, abs, ...
34e49164 53 * - List.rev, List.mem, List.partition,
ae4735db 54 * - List.fold*, List.concat, ...
34e49164 55 * - Str.global_replace
91eba41f 56 * - Filename.is_relative
0708f913 57 * - String.uppercase, String.lowercase
ae4735db
C
58 *
59 *
34e49164
C
60 * The Format library allows to hide passing an indent_level variable.
61 * You use as usual the print_string function except that there is
62 * this automatic indent_level variable handled for you (and maybe
63 * more services). src: julia in coccinelle unparse_cocci.
ae4735db
C
64 *
65 * Extra packages
34e49164 66 * - ocamlbdb
91eba41f 67 * - ocamlgtk, and gtksourceview
34e49164
C
68 * - ocamlgl
69 * - ocamlpython
70 * - ocamlagrep
71 * - ocamlfuse
72 * - ocamlmpi
73 * - ocamlcalendar
ae4735db 74 *
91eba41f
C
75 * - pcre
76 * - sdl
ae4735db 77 *
91eba41f 78 * Many functions in this file were inspired by Haskell or Lisp librairies.
34e49164
C
79 *)
80
81(*****************************************************************************)
82(* Prelude *)
83(*****************************************************************************)
84
85(* The following functions should be in their respective sections but
86 * because some functions in some sections use functions in other
87 * sections, and because I don't want to take care of the order of
88 * those sections, of those dependencies, I put the functions causing
89 * dependency problem here. C is better than caml on this with the
90 * ability to declare prototype, enabling some form of forward
91 * reference. *)
92
93let (+>) o f = f o
94let (++) = (@)
95
96exception Timeout
ae4735db 97exception UnixExit of int
34e49164
C
98
99let rec (do_n: int -> (unit -> unit) -> unit) = fun i f ->
100 if i = 0 then () else (f(); do_n (i-1) f)
101let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i ->
102 if i = 0 then acc else foldn f (f acc i) (i-1)
103
104let sum_int = List.fold_left (+) 0
105
106(* could really call it 'for' :) *)
107let fold_left_with_index f acc =
108 let rec fold_lwi_aux acc n = function
109 | [] -> acc
ae4735db 110 | x::xs -> fold_lwi_aux (f acc x n) (n+1) xs
34e49164
C
111 in fold_lwi_aux acc 0
112
113
ae4735db 114let rec drop n xs =
34e49164
C
115 match (n,xs) with
116 | (0,_) -> xs
117 | (_,[]) -> failwith "drop: not enough"
118 | (n,x::xs) -> drop (n-1) xs
119
120let rec enum_orig x n = if x = n then [n] else x::enum_orig (x+1) n
121
ae4735db 122let enum x n =
34e49164
C
123 if not(x <= n)
124 then failwith (Printf.sprintf "bad values in enum, expect %d <= %d" x n);
ae4735db
C
125 let rec enum_aux acc x n =
126 if x = n then n::acc else enum_aux (x::acc) (x+1) n
34e49164
C
127 in
128 List.rev (enum_aux [] x n)
129
ae4735db 130let rec take n xs =
34e49164
C
131 match (n,xs) with
132 | (0,_) -> []
133 | (_,[]) -> failwith "take: not enough"
134 | (n,x::xs) -> x::take (n-1) xs
135
136
137let last_n n l = List.rev (take n (List.rev l))
138let last l = List.hd (last_n 1 l)
139
140
141let (list_of_string: string -> char list) = function
142 "" -> []
143 | s -> (enum 0 ((String.length s) - 1) +> List.map (String.get s))
144
ae4735db 145let (lines: string -> string list) = fun s ->
34e49164
C
146 let rec lines_aux = function
147 | [] -> []
ae4735db
C
148 | [x] -> if x = "" then [] else [x]
149 | x::xs ->
150 x::lines_aux xs
34e49164
C
151 in
152 Str.split_delim (Str.regexp "\n") s +> lines_aux
153
154
155let push2 v l =
156 l := v :: !l
157
b1b2de81 158let null xs = match xs with [] -> true | _ -> false
34e49164
C
159
160
161
162
ae4735db 163let debugger = ref false
34e49164
C
164
165let unwind_protect f cleanup =
ae4735db 166 if !debugger then f() else
34e49164
C
167 try f ()
168 with e -> begin cleanup e; raise e end
169
ae4735db
C
170let finalize f cleanup =
171 if !debugger then f() else
172 try
34e49164
C
173 let res = f () in
174 cleanup ();
175 res
ae4735db 176 with e ->
34e49164
C
177 cleanup ();
178 raise e
179
180let command2 s = ignore(Sys.command s)
181
182
ae4735db 183let (matched: int -> string -> string) = fun i s ->
34e49164
C
184 Str.matched_group i s
185
186let matched1 = fun s -> matched 1 s
187let matched2 = fun s -> (matched 1 s, matched 2 s)
188let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s)
189let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s)
190let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s)
191let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s)
192let matched7 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s, matched 7 s)
193
194let (with_open_stringbuf: (((string -> unit) * Buffer.t) -> unit) -> string) =
195 fun f ->
196 let buf = Buffer.create 1000 in
197 let pr s = Buffer.add_string buf (s ^ "\n") in
198 f (pr, buf);
199 Buffer.contents buf
200
201
485bce71
C
202let foldl1 p = function x::xs -> List.fold_left p x xs | _ -> failwith "foldl1"
203
34e49164
C
204(*****************************************************************************)
205(* Debugging/logging *)
206(*****************************************************************************)
207
ae4735db 208(* I used this in coccinelle where the huge logging of stuff ask for
34e49164 209 * a more organized solution that use more visual indentation hints.
ae4735db
C
210 *
211 * todo? could maybe use log4j instead ? or use Format module more
34e49164
C
212 * consistently ?
213 *)
214
215let _tab_level_print = ref 0
216let _tab_indent = 5
217
218
219let _prefix_pr = ref ""
220
ae4735db 221let indent_do f =
34e49164 222 _tab_level_print := !_tab_level_print + _tab_indent;
ae4735db 223 finalize f
34e49164
C
224 (fun () -> _tab_level_print := !_tab_level_print - _tab_indent;)
225
226
ae4735db 227let pr s =
34e49164
C
228 print_string !_prefix_pr;
229 do_n !_tab_level_print (fun () -> print_string " ");
230 print_string s;
ae4735db 231 print_string "\n";
34e49164
C
232 flush stdout
233
ae4735db 234let pr_no_nl s =
34e49164
C
235 print_string !_prefix_pr;
236 do_n !_tab_level_print (fun () -> print_string " ");
237 print_string s;
238 flush stdout
239
240
708f4980
C
241
242
243
244
245let _chan_pr2 = ref (None: out_channel option)
246
ae4735db 247let out_chan_pr2 ?(newline=true) s =
708f4980
C
248 match !_chan_pr2 with
249 | None -> ()
ae4735db
C
250 | Some chan ->
251 output_string chan (s ^ (if newline then "\n" else ""));
708f4980
C
252 flush chan
253
ae4735db 254let print_to_stderr = ref true
708f4980 255
ae4735db
C
256let pr2 s =
257 if !print_to_stderr
258 then
259 begin
260 prerr_string !_prefix_pr;
261 do_n !_tab_level_print (fun () -> prerr_string " ");
262 prerr_string s;
263 prerr_string "\n";
264 flush stderr;
265 out_chan_pr2 s;
266 ()
267 end
34e49164 268
ae4735db
C
269let pr2_no_nl s =
270 if !print_to_stderr
271 then
272 begin
273 prerr_string !_prefix_pr;
274 do_n !_tab_level_print (fun () -> prerr_string " ");
275 prerr_string s;
276 flush stderr;
277 out_chan_pr2 ~newline:false s;
278 ()
279 end
708f4980 280
34e49164 281
ae4735db 282let pr_xxxxxxxxxxxxxxxxx () =
34e49164
C
283 pr "-----------------------------------------------------------------------"
284
ae4735db 285let pr2_xxxxxxxxxxxxxxxxx () =
34e49164
C
286 pr2 "-----------------------------------------------------------------------"
287
288
289let reset_pr_indent () =
290 _tab_level_print := 0
291
ae4735db 292(* old:
34e49164 293 * let pr s = (print_string s; print_string "\n"; flush stdout)
ae4735db 294 * let pr2 s = (prerr_string s; prerr_string "\n"; flush stderr)
34e49164
C
295 *)
296
297(* ---------------------------------------------------------------------- *)
298
ae4735db 299(* I can not use the _xxx ref tech that I use for common_extra.ml here because
34e49164 300 * ocaml don't like the polymorphism of Dumper mixed with refs.
ae4735db
C
301 *
302 * let (_dump_func : ('a -> string) ref) = ref
34e49164
C
303 * (fun x -> failwith "no dump yet, have you included common_extra.cmo?")
304 * let (dump : 'a -> string) = fun x ->
305 * !_dump_func x
ae4735db 306 *
34e49164
C
307 * So I have included directly dumper.ml in common.ml. It's more practical
308 * when want to give script that use my common.ml, I just have to give
309 * this file.
310 *)
311
312(* start of dumper.ml *)
313
314(* Dump an OCaml value into a printable string.
315 * By Richard W.M. Jones (rich@annexia.org).
ae4735db 316 * dumper.ml 1.2 2005/02/06 12:38:21 rich Exp
34e49164
C
317 *)
318open Printf
319open Obj
320
321let rec dump r =
322 if is_int r then
323 string_of_int (magic r : int)
324 else ( (* Block. *)
325 let rec get_fields acc = function
326 | 0 -> acc
327 | n -> let n = n-1 in get_fields (field r n :: acc) n
328 in
329 let rec is_list r =
330 if is_int r then (
331 if (magic r : int) = 0 then true (* [] *)
332 else false
333 ) else (
334 let s = size r and t = tag r in
335 if t = 0 && s = 2 then is_list (field r 1) (* h :: t *)
336 else false
337 )
338 in
339 let rec get_list r =
340 if is_int r then []
341 else let h = field r 0 and t = get_list (field r 1) in h :: t
342 in
343 let opaque name =
344 (* XXX In future, print the address of value 'r'. Not possible in
345 * pure OCaml at the moment.
346 *)
347 "<" ^ name ^ ">"
348 in
349
350 let s = size r and t = tag r in
351
352 (* From the tag, determine the type of block. *)
353 if is_list r then ( (* List. *)
354 let fields = get_list r in
355 "[" ^ String.concat "; " (List.map dump fields) ^ "]"
356 )
357 else if t = 0 then ( (* Tuple, array, record. *)
358 let fields = get_fields [] s in
359 "(" ^ String.concat ", " (List.map dump fields) ^ ")"
360 )
361
362 (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
363 * clear if very large constructed values could have the same
364 * tag. XXX *)
365 else if t = lazy_tag then opaque "lazy"
366 else if t = closure_tag then opaque "closure"
367 else if t = object_tag then ( (* Object. *)
368 let fields = get_fields [] s in
369 let clasz, id, slots =
370 match fields with h::h'::t -> h, h', t | _ -> assert false in
371 (* No information on decoding the class (first field). So just print
372 * out the ID and the slots.
373 *)
374 "Object #" ^ dump id ^
375 " (" ^ String.concat ", " (List.map dump slots) ^ ")"
376 )
377 else if t = infix_tag then opaque "infix"
378 else if t = forward_tag then opaque "forward"
379
380 else if t < no_scan_tag then ( (* Constructed value. *)
381 let fields = get_fields [] s in
382 "Tag" ^ string_of_int t ^
383 " (" ^ String.concat ", " (List.map dump fields) ^ ")"
384 )
385 else if t = string_tag then (
386 "\"" ^ String.escaped (magic r : string) ^ "\""
387 )
388 else if t = double_tag then (
389 string_of_float (magic r : float)
390 )
391 else if t = abstract_tag then opaque "abstract"
392 else if t = custom_tag then opaque "custom"
393 else if t = final_tag then opaque "final"
394 else failwith ("dump: impossible tag (" ^ string_of_int t ^ ")")
395 )
396
397let dump v = dump (repr v)
398
399(* end of dumper.ml *)
400
401(*
402let (dump : 'a -> string) = fun x ->
403 Dumper.dump x
404*)
405
406
407(* ---------------------------------------------------------------------- *)
408let pr2_gen x = pr2 (dump x)
409
410
411
412(* ---------------------------------------------------------------------- *)
413
414
415let _already_printed = Hashtbl.create 101
ae4735db 416let disable_pr2_once = ref false
708f4980 417
ae4735db 418let xxx_once f s =
34e49164 419 if !disable_pr2_once then pr2 s
ae4735db 420 else
34e49164
C
421 if not (Hashtbl.mem _already_printed s)
422 then begin
423 Hashtbl.add _already_printed s true;
708f4980 424 f ("(ONCE) " ^ s);
34e49164
C
425 end
426
708f4980
C
427let pr2_once s = xxx_once pr2 s
428
429(* ---------------------------------------------------------------------- *)
978fd7e5
C
430let mk_pr2_wrappers aref =
431 let fpr2 s =
708f4980
C
432 if !aref
433 then pr2 s
978fd7e5 434 else
708f4980
C
435 (* just to the log file *)
436 out_chan_pr2 s
437 in
978fd7e5 438 let fpr2_once s =
708f4980
C
439 if !aref
440 then pr2_once s
978fd7e5 441 else
708f4980
C
442 xxx_once out_chan_pr2 s
443 in
978fd7e5 444 fpr2, fpr2_once
34e49164
C
445
446(* ---------------------------------------------------------------------- *)
447(* could also be in File section *)
448
978fd7e5
C
449let redirect_stdout file f =
450 begin
451 let chan = open_out file in
452 let descr = Unix.descr_of_out_channel chan in
453
454 let saveout = Unix.dup Unix.stdout in
455 Unix.dup2 descr Unix.stdout;
456 flush stdout;
457 let res = f() in
458 flush stdout;
459 Unix.dup2 saveout Unix.stdout;
460 close_out chan;
461 res
462 end
463
464let redirect_stdout_opt optfile f =
465 match optfile with
466 | None -> f()
467 | Some outfile -> redirect_stdout outfile f
468
469let redirect_stdout_stderr file f =
34e49164
C
470 begin
471 let chan = open_out file in
472 let descr = Unix.descr_of_out_channel chan in
473
474 let saveout = Unix.dup Unix.stdout in
475 let saveerr = Unix.dup Unix.stderr in
476 Unix.dup2 descr Unix.stdout;
477 Unix.dup2 descr Unix.stderr;
478 flush stdout; flush stderr;
479 f();
480 flush stdout; flush stderr;
481 Unix.dup2 saveout Unix.stdout;
482 Unix.dup2 saveerr Unix.stderr;
483 close_out chan;
484 end
485
978fd7e5 486let redirect_stdin file f =
34e49164
C
487 begin
488 let chan = open_in file in
489 let descr = Unix.descr_of_in_channel chan in
490
491 let savein = Unix.dup Unix.stdin in
492 Unix.dup2 descr Unix.stdin;
493 f();
494 Unix.dup2 savein Unix.stdin;
495 close_in chan;
496 end
497
978fd7e5 498let redirect_stdin_opt optfile f =
34e49164
C
499 match optfile with
500 | None -> f()
501 | Some infile -> redirect_stdin infile f
502
503
ae4735db
C
504(* cf end
505let with_pr2_to_string f =
708f4980 506*)
ae4735db 507
34e49164
C
508
509(* ---------------------------------------------------------------------- *)
510
511include Printf
512
513(* cf common.mli, fprintf, printf, eprintf, sprintf.
514 * also what is this ?
515 * val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a
516 * val kprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b
517 *)
518
ae4735db 519(* ex of printf:
34e49164
C
520 * printf "%02d" i
521 * for padding
522 *)
523
524let spf = sprintf
525
526(* ---------------------------------------------------------------------- *)
527
528let _chan = ref stderr
ae4735db 529let start_log_file () =
34e49164
C
530 let filename = (spf "/tmp/debugml%d:%d" (Unix.getuid()) (Unix.getpid())) in
531 pr2 (spf "now using %s for logging" filename);
532 _chan := open_out filename
ae4735db 533
34e49164
C
534
535let dolog s = output_string !_chan (s ^ "\n"); flush !_chan
536
537let verbose_level = ref 1
538let log s = if !verbose_level >= 1 then dolog s
539let log2 s = if !verbose_level >= 2 then dolog s
540let log3 s = if !verbose_level >= 3 then dolog s
541let log4 s = if !verbose_level >= 4 then dolog s
542
543let if_log f = if !verbose_level >= 1 then f()
544let if_log2 f = if !verbose_level >= 2 then f()
545let if_log3 f = if !verbose_level >= 3 then f()
546let if_log4 f = if !verbose_level >= 4 then f()
547
548(* ---------------------------------------------------------------------- *)
549
550let pause () = (pr2 "pause: type return"; ignore(read_line ()))
551
552(* src: from getopt from frish *)
553let bip () = Printf.printf "\007"; flush stdout
ae4735db 554let wait () = Unix.sleep 1
34e49164
C
555
556(* was used by fix_caml *)
557let _trace_var = ref 0
558let add_var() = incr _trace_var
559let dec_var() = decr _trace_var
560let get_var() = !_trace_var
561
ae4735db 562let (print_n: int -> string -> unit) = fun i s ->
34e49164 563 do_n i (fun () -> print_string s)
ae4735db 564let (printerr_n: int -> string -> unit) = fun i s ->
34e49164
C
565 do_n i (fun () -> prerr_string s)
566
567let _debug = ref true
568let debugon () = _debug := true
569let debugoff () = _debug := false
570let debug f = if !_debug then f () else ()
571
572
573
574(* now in prelude:
ae4735db 575 * let debugger = ref false
34e49164
C
576 *)
577
578
579(*****************************************************************************)
580(* Profiling *)
581(*****************************************************************************)
582
583let get_mem() =
584 command2("grep VmData /proc/" ^ string_of_int (Unix.getpid()) ^ "/status")
585
586let memory_stat () =
587 let stat = Gc.stat() in
588 let conv_mo x = x * 4 / 1000000 in
589 Printf.sprintf "maximal = %d Mo\n" (conv_mo stat.Gc.top_heap_words) ^
590 Printf.sprintf "current = %d Mo\n" (conv_mo stat.Gc.heap_words) ^
591 Printf.sprintf "lives = %d Mo\n" (conv_mo stat.Gc.live_words)
592 (* Printf.printf "fragments = %d Mo\n" (conv_mo stat.Gc.fragments); *)
593
ae4735db 594let timenow () =
34e49164 595 "sys:" ^ (string_of_float (Sys.time ())) ^ " seconds" ^
ae4735db 596 ":real:" ^
34e49164 597 (let tm = Unix.time () +> Unix.gmtime in
ae4735db 598 tm.Unix.tm_min +> string_of_int ^ " min:" ^
34e49164
C
599 tm.Unix.tm_sec +> string_of_int ^ ".00 seconds")
600
ae4735db
C
601let _count1 = ref 0
602let _count2 = ref 0
603let _count3 = ref 0
604let _count4 = ref 0
605let _count5 = ref 0
34e49164
C
606
607let count1 () = incr _count1
608let count2 () = incr _count2
609let count3 () = incr _count3
610let count4 () = incr _count4
611let count5 () = incr _count5
612
ae4735db
C
613let profile_diagnostic_basic () =
614 Printf.sprintf
615 "count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\ncount5 = %d\n"
34e49164
C
616 !_count1 !_count2 !_count3 !_count4 !_count5
617
618
619
ae4735db 620let time_func f =
34e49164
C
621 (* let _ = Timing () in *)
622 let x = f () in
623 (* let _ = Timing () in *)
624 x
625
626(* ---------------------------------------------------------------------- *)
627
628type prof = PALL | PNONE | PSOME of string list
629let profile = ref PNONE
485bce71 630let show_trace_profile = ref false
34e49164
C
631
632let check_profile category =
633 match !profile with
634 PALL -> true
635 | PNONE -> false
636 | PSOME l -> List.mem category l
637
638let _profile_table = ref (Hashtbl.create 100)
485bce71
C
639
640let adjust_profile_entry category difftime =
ae4735db 641 let (xtime, xcount) =
485bce71 642 (try Hashtbl.find !_profile_table category
ae4735db 643 with Not_found ->
485bce71
C
644 let xtime = ref 0.0 in
645 let xcount = ref 0 in
646 Hashtbl.add !_profile_table category (xtime, xcount);
647 (xtime, xcount)
648 ) in
649 xtime := !xtime +. difftime;
650 xcount := !xcount + 1;
651 ()
652
34e49164
C
653let profile_start category = failwith "todo"
654let profile_end category = failwith "todo"
655
485bce71 656
34e49164
C
657(* subtil: don't forget to give all argumens to f, otherwise partial app
658 * and will profile nothing.
ae4735db 659 *
0708f913 660 * todo: try also detect when complexity augment each time, so can
ae4735db
C
661 * detect the situation for a function gets worse and worse ?
662 *)
663let profile_code category f =
34e49164 664 if not (check_profile category)
fc1ad971 665 then f()
34e49164 666 else begin
485bce71 667 if !show_trace_profile then pr2 (spf "p: %s" category);
34e49164 668 let t = Unix.gettimeofday () in
ae4735db 669 let res, prefix =
34e49164
C
670 try Some (f ()), ""
671 with Timeout -> None, "*"
672 in
673 let category = prefix ^ category in (* add a '*' to indicate timeout func *)
674 let t' = Unix.gettimeofday () in
485bce71
C
675
676 adjust_profile_entry category (t' -. t);
34e49164
C
677 (match res with
678 | Some res -> res
679 | None -> raise Timeout
680 );
681 end
682
485bce71 683
ae4735db 684let _is_in_exclusif = ref (None: string option)
485bce71 685
ae4735db 686let profile_code_exclusif category f =
485bce71 687 if not (check_profile category)
ae4735db 688 then f()
485bce71
C
689 else begin
690
691 match !_is_in_exclusif with
ae4735db 692 | Some s ->
485bce71 693 failwith (spf "profile_code_exclusif: %s but already in %s " category s);
ae4735db 694 | None ->
485bce71 695 _is_in_exclusif := (Some category);
ae4735db
C
696 finalize
697 (fun () ->
485bce71 698 profile_code category f
ae4735db
C
699 )
700 (fun () ->
485bce71
C
701 _is_in_exclusif := None
702 )
703
704 end
705
ae4735db 706let profile_code_inside_exclusif_ok category f =
485bce71
C
707 failwith "Todo"
708
709
34e49164 710(* todo: also put % ? also add % to see if coherent numbers *)
ae4735db 711let profile_diagnostic () =
34e49164 712 if !profile = PNONE then "" else
ae4735db
C
713 let xs =
714 Hashtbl.fold (fun k v acc -> (k,v)::acc) !_profile_table []
34e49164
C
715 +> List.sort (fun (k1, (t1,n1)) (k2, (t2,n2)) -> compare t2 t1)
716 in
ae4735db 717 with_open_stringbuf (fun (pr,_) ->
34e49164
C
718 pr "---------------------";
719 pr "profiling result";
720 pr "---------------------";
ae4735db 721 xs +> List.iter (fun (k, (t,n)) ->
34e49164
C
722 pr (sprintf "%-40s : %10.3f sec %10d count" k !t !n)
723 )
724 )
725
726
727
ae4735db 728let report_if_take_time timethreshold s f =
34e49164
C
729 let t = Unix.gettimeofday () in
730 let res = f () in
731 let t' = Unix.gettimeofday () in
ae4735db 732 if (t' -. t > float_of_int timethreshold)
978fd7e5 733 then pr2 (sprintf "Note: processing took %7.1fs: %s" (t' -. t) s);
34e49164
C
734 res
735
ae4735db
C
736let profile_code2 category f =
737 profile_code category (fun () ->
34e49164
C
738 if !profile = PALL
739 then pr2 ("starting: " ^ category);
740 let t = Unix.gettimeofday () in
741 let res = f () in
742 let t' = Unix.gettimeofday () in
743 if !profile = PALL
744 then pr2 (spf "ending: %s, %fs" category (t' -. t));
745 res
746 )
ae4735db 747
34e49164
C
748
749(*****************************************************************************)
750(* Test *)
751(*****************************************************************************)
752let example b = assert b
753
754let _ex1 = example (enum 1 4 = [1;2;3;4])
755
ae4735db
C
756let assert_equal a b =
757 if not (a = b)
758 then failwith ("assert_equal: those 2 values are not equal:\n\t" ^
34e49164
C
759 (dump a) ^ "\n\t" ^ (dump b) ^ "\n")
760
ae4735db 761let (example2: string -> bool -> unit) = fun s b ->
34e49164
C
762 try assert b with x -> failwith s
763
764(*-------------------------------------------------------------------*)
765let _list_bool = ref []
766
ae4735db 767let (example3: string -> bool -> unit) = fun s b ->
34e49164
C
768 _list_bool := (s,b)::(!_list_bool)
769
770(* could introduce a fun () otherwise the calculus is made at compile time
771 * and this can be long. This would require to redefine test_all.
ae4735db 772 * let (example3: string -> (unit -> bool) -> unit) = fun s func ->
34e49164 773 * _list_bool := (s,func):: (!_list_bool)
ae4735db 774 *
34e49164
C
775 * I would like to do as a func that take 2 terms, and make an = over it
776 * avoid to add this ugly fun (), but pb of type, cant do that :(
777 *)
778
779
ae4735db
C
780let (test_all: unit -> unit) = fun () ->
781 List.iter (fun (s, b) ->
34e49164
C
782 Printf.printf "%s: %s\n" s (if b then "passed" else "failed")
783 ) !_list_bool
784
ae4735db
C
785let (test: string -> unit) = fun s ->
786 Printf.printf "%s: %s\n" s
34e49164
C
787 (if (List.assoc s (!_list_bool)) then "passed" else "failed")
788
789let _ex = example3 "++" ([1;2]++[3;4;5] = [1;2;3;4;5])
790
791(*-------------------------------------------------------------------*)
792(* Regression testing *)
793(*-------------------------------------------------------------------*)
794
ae4735db 795(* cf end of file. It uses too many other common functions so I
34e49164
C
796 * have put the code at the end of this file.
797 *)
798
799
800
801(* todo? take code from julien signoles in calendar-2.0.2/tests *)
802(*
803
804(* Generic functions used in the tests. *)
805
806val reset : unit -> unit
807val nb_ok : unit -> int
808val nb_bug : unit -> int
809val test : bool -> string -> unit
810val test_exn : 'a Lazy.t -> string -> unit
811
812
813let ok_ref = ref 0
814let ok () = incr ok_ref
815let nb_ok () = !ok_ref
816
817let bug_ref = ref 0
818let bug () = incr bug_ref
819let nb_bug () = !bug_ref
820
821let reset () =
822 ok_ref := 0;
823 bug_ref := 0
824
ae4735db 825let test x s =
34e49164
C
826 if x then ok () else begin Printf.printf "%s\n" s; bug () end;;
827
828let test_exn x s =
829 try
830 ignore (Lazy.force x);
831 Printf.printf "%s\n" s;
832 bug ()
833 with _ ->
834 ok ();;
835*)
836
837
838(*****************************************************************************)
839(* Quickcheck like (sfl) *)
840(*****************************************************************************)
841
842(* Better than quickcheck, cos cant do a test_all_prop in haskell cos
843 * prop were functions, whereas here we have not prop_Unix x = ... but
ae4735db 844 * laws "unit" ...
34e49164
C
845 *
846 * How to do without overloading ? objet ? can pass a generator as a
847 * parameter, mais lourd, prefer automatic inferring of the
848 * generator? But at the same time quickcheck does not do better cos
ae4735db
C
849 * we must explictly type the property. So between a
850 * prop_unit:: [Int] -> [Int] -> bool ...
851 * prop_unit x = reverse [x] == [x]
852 * and
853 * let _ = laws "unit" (fun x -> reverse [x] = [x]) (listg intg)
854 * there is no real differences.
34e49164
C
855 *
856 * Yes I define typeg generator but quickcheck too, he must define
857 * class instance. I emulate the context Gen a => Gen [a] by making
858 * listg take as a param a type generator. Moreover I have not the pb of
ae4735db 859 * monad. I can do random independently, so my code is more simple
34e49164 860 * I think than the haskell code of quickcheck.
ae4735db 861 *
34e49164
C
862 * update: apparently Jane Street have copied some of my code for their
863 * Ounit_util.ml and quichcheck.ml in their Core library :)
864 *)
865
866(*---------------------------------------------------------------------------*)
867(* generators *)
868(*---------------------------------------------------------------------------*)
869type 'a gen = unit -> 'a
870
871let (ig: int gen) = fun () ->
872 Random.int 10
ae4735db 873let (lg: ('a gen) -> ('a list) gen) = fun gen () ->
34e49164 874 foldn (fun acc i -> (gen ())::acc) [] (Random.int 10)
ae4735db 875let (pg: ('a gen) -> ('b gen) -> ('a * 'b) gen) = fun gen1 gen2 () ->
34e49164
C
876 (gen1 (), gen2 ())
877let polyg = ig
ae4735db 878let (ng: (string gen)) = fun () ->
34e49164
C
879 "a" ^ (string_of_int (ig ()))
880
ae4735db
C
881let (oneofl: ('a list) -> 'a gen) = fun xs () ->
882 List.nth xs (Random.int (List.length xs))
34e49164
C
883(* let oneofl l = oneof (List.map always l) *)
884
ae4735db
C
885let (oneof: (('a gen) list) -> 'a gen) = fun xs ->
886 List.nth xs (Random.int (List.length xs))
34e49164
C
887
888let (always: 'a -> 'a gen) = fun e () -> e
889
ae4735db 890let (frequency: ((int * ('a gen)) list) -> 'a gen) = fun xs ->
34e49164
C
891 let sums = sum_int (List.map fst xs) in
892 let i = Random.int sums in
ae4735db
C
893 let rec freq_aux acc = function
894 | (x,g)::xs -> if i < acc+x then g else freq_aux (acc+x) xs
895 | _ -> failwith "frequency"
34e49164
C
896 in
897 freq_aux 0 xs
898let frequencyl l = frequency (List.map (fun (i,e) -> (i,always e)) l)
899
ae4735db 900(*
34e49164
C
901let b = oneof [always true; always false] ()
902let b = frequency [3, always true; 2, always false] ()
903*)
904
905(* cant do this:
906 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneofl [[]; lg gen ()]
907 * nor
908 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneof [always []; lg gen]
ae4735db 909 *
34e49164
C
910 * because caml is not as lazy as haskell :( fix the pb by introducing a size
911 * limit. take the bounds/size as parameter. morover this is needed for
912 * more complex type.
ae4735db 913 *
34e49164 914 * how make a bintreeg ?? we need recursion
ae4735db
C
915 *
916 * let rec (bintreeg: ('a gen) -> ('a bintree) gen) = fun gen () ->
917 * let rec aux n =
34e49164
C
918 * if n = 0 then (Leaf (gen ()))
919 * else frequencyl [1, Leaf (gen ()); 4, Branch ((aux (n / 2)), aux (n / 2))]
920 * ()
921 * in aux 20
ae4735db 922 *
34e49164
C
923 *)
924
925
926(*---------------------------------------------------------------------------*)
927(* property *)
928(*---------------------------------------------------------------------------*)
929
930(* todo: a test_all_laws, better syntax (done already a little with ig in
ae4735db
C
931 * place of intg. En cas d'erreur, print the arg that not respect
932 *
34e49164
C
933 * todo: with monitoring, as in haskell, laws = laws2, no need for 2 func,
934 * but hard i found
ae4735db
C
935 *
936 * todo classify, collect, forall
34e49164
C
937 *)
938
939
940(* return None when good, and Just the_problematic_case when bad *)
941let (laws: string -> ('a -> bool) -> ('a gen) -> 'a option) = fun s func gen ->
942 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
943 let res = List.filter (fun (x,b) -> not b) res in
944 if res = [] then None else Some (fst (List.hd res))
945
946let rec (statistic_number: ('a list) -> (int * 'a) list) = function
947 | [] -> []
948 | x::xs -> let (splitg, splitd) = List.partition (fun y -> y = x) xs in
949 (1+(List.length splitg), x)::(statistic_number splitd)
950
951(* in pourcentage *)
952let (statistic: ('a list) -> (int * 'a) list) = fun xs ->
953 let stat_num = statistic_number xs in
954 let totals = sum_int (List.map fst stat_num) in
ae4735db
C
955 List.map (fun (i, v) -> ((i * 100) / totals), v) stat_num
956
957let (laws2:
958 string -> ('a -> (bool * 'b)) -> ('a gen) ->
959 ('a option * ((int * 'b) list ))) =
34e49164
C
960 fun s func gen ->
961 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
962 let stat = statistic (List.map (fun (x,(b,v)) -> v) res) in
963 let res = List.filter (fun (x,(b,v)) -> not b) res in
964 if res = [] then (None, stat) else (Some (fst (List.hd res)), stat)
965
966
967(*
968let b = laws "unit" (fun x -> reverse [x] = [x] )ig
969let b = laws "app " (fun (xs,ys) -> reverse (xs++ys) = reverse ys++reverse xs)(pg (lg ig)(lg ig))
970let b = laws "rev " (fun xs -> reverse (reverse xs) = xs )(lg ig)
971let b = laws "appb" (fun (xs,ys) -> reverse (xs++ys) = reverse xs++reverse ys)(pg (lg ig)(lg ig))
972let b = laws "max" (fun (x,y) -> x <= y ==> (max x y = y) )(pg ig ig)
973
ae4735db 974let b = laws2 "max" (fun (x,y) -> ((x <= y ==> (max x y = y)), x <= y))(pg ig ig)
34e49164
C
975*)
976
977
978(* todo, do with coarbitrary ?? idea is that given a 'a, generate a 'b
979 * depending of 'a and gen 'b, that is modify gen 'b, what is important is
980 * that each time given the same 'a, we must get the same 'b !!!
981 *)
982
983(*
984let (fg: ('a gen) -> ('b gen) -> ('a -> 'b) gen) = fun gen1 gen2 () ->
985let b = laws "funs" (fun (f,g,h) -> x <= y ==> (max x y = y) )(pg ig ig)
986 *)
987
988(*
ae4735db 989let one_of xs = List.nth xs (Random.int (List.length xs))
34e49164
C
990let take_one xs =
991 if empty xs then failwith "Take_one: empty list"
ae4735db 992 else
34e49164
C
993 let i = Random.int (List.length xs) in
994 List.nth xs i, filter_index (fun j _ -> i <> j) xs
ae4735db 995*)
34e49164
C
996
997(*****************************************************************************)
998(* Persistence *)
999(*****************************************************************************)
1000
ae4735db 1001let get_value filename =
34e49164
C
1002 let chan = open_in filename in
1003 let x = input_value chan in (* <=> Marshal.from_channel *)
1004 (close_in chan; x)
1005
ae4735db 1006let write_value valu filename =
34e49164
C
1007 let chan = open_out filename in
1008 (output_value chan valu; (* <=> Marshal.to_channel *)
1009 (* Marshal.to_channel chan valu [Marshal.Closures]; *)
ae4735db 1010 close_out chan)
34e49164 1011
ae4735db 1012let write_back func filename =
34e49164
C
1013 write_value (func (get_value filename)) filename
1014
1015
485bce71
C
1016let read_value f = get_value f
1017
34e49164 1018
ae4735db 1019let marshal__to_string2 v flags =
0708f913 1020 Marshal.to_string v flags
ae4735db 1021let marshal__to_string a b =
0708f913
C
1022 profile_code "Marshalling" (fun () -> marshal__to_string2 a b)
1023
ae4735db 1024let marshal__from_string2 v flags =
0708f913 1025 Marshal.from_string v flags
ae4735db 1026let marshal__from_string a b =
0708f913
C
1027 profile_code "Marshalling" (fun () -> marshal__from_string2 a b)
1028
1029
1030
34e49164
C
1031(*****************************************************************************)
1032(* Counter *)
1033(*****************************************************************************)
1034let _counter = ref 0
1035let counter () = (_counter := !_counter +1; !_counter)
1036
1037let _counter2 = ref 0
1038let counter2 () = (_counter2 := !_counter2 +1; !_counter2)
1039
1040let _counter3 = ref 0
1041let counter3 () = (_counter3 := !_counter3 +1; !_counter3)
1042
1043type timestamp = int
1044
1045(*****************************************************************************)
1046(* String_of *)
1047(*****************************************************************************)
1048(* To work with the macro system autogenerated string_of and print_ function
1049 (kind of deriving a la haskell) *)
1050
ae4735db 1051(* int, bool, char, float, ref ?, string *)
34e49164
C
1052
1053let string_of_string s = "\"" ^ s "\""
1054
ae4735db 1055let string_of_list f xs =
34e49164
C
1056 "[" ^ (xs +> List.map f +> String.concat ";" ) ^ "]"
1057
1058let string_of_unit () = "()"
1059
1060let string_of_array f xs =
1061 "[|" ^ (xs +> Array.to_list +> List.map f +> String.concat ";") ^ "|]"
1062
1063let string_of_option f = function
1064 | None -> "None "
1065 | Some x -> "Some " ^ (f x)
1066
1067
1068
1069
1070let print_bool x = print_string (if x then "True" else "False")
1071
1072let print_option pr = function
1073 | None -> print_string "None"
1074 | Some x -> print_string "Some ("; pr x; print_string ")"
1075
ae4735db 1076let print_list pr xs =
34e49164 1077 begin
ae4735db
C
1078 print_string "[";
1079 List.iter (fun x -> pr x; print_string ",") xs;
34e49164
C
1080 print_string "]";
1081 end
1082
ae4735db
C
1083(* specialised
1084let (string_of_list: char list -> string) =
34e49164
C
1085 List.fold_left (fun acc x -> acc^(Char.escaped x)) ""
1086*)
1087
1088
1089let rec print_between between fn = function
1090 | [] -> ()
1091 | [x] -> fn x
1092 | x::xs -> fn x; between(); print_between between fn xs
1093
1094
1095
1096
ae4735db
C
1097let adjust_pp_with_indent f =
1098 Format.open_box !_tab_level_print;
34e49164 1099 (*Format.force_newline();*)
ae4735db 1100 f();
34e49164
C
1101 Format.close_box ();
1102 Format.print_newline()
1103
ae4735db
C
1104let adjust_pp_with_indent_and_header s f =
1105 Format.open_box (!_tab_level_print + String.length s);
34e49164
C
1106 do_n !_tab_level_print (fun () -> Format.print_string " ");
1107 Format.print_string s;
1108 f();
1109 Format.close_box ();
1110 Format.print_newline()
1111
1112
1113
1114let pp_do_in_box f = Format.open_box 1; f(); Format.close_box ()
1115let pp_do_in_zero_box f = Format.open_box 0; f(); Format.close_box ()
1116
ae4735db
C
1117let pp_f_in_box f =
1118 Format.open_box 1;
1119 let res = f() in
34e49164
C
1120 Format.close_box ();
1121 res
1122
1123let pp s = Format.print_string s
1124
ae4735db 1125let mk_str_func_of_assoc_conv xs =
0708f913
C
1126 let swap (x,y) = (y,x) in
1127
ae4735db 1128 (fun s ->
0708f913
C
1129 let xs' = List.map swap xs in
1130 List.assoc s xs'
1131 ),
ae4735db 1132 (fun a ->
0708f913
C
1133 List.assoc a xs
1134 )
1135
708f4980
C
1136
1137
1138(* julia: convert something printed using format to print into a string *)
1139(* now at bottom of file
1140let format_to_string f =
1141 ...
1142*)
1143
1144
1145
34e49164
C
1146(*****************************************************************************)
1147(* Macro *)
1148(*****************************************************************************)
1149
1150(* put your macro in macro.ml4, and you can test it interactivly as in lisp *)
ae4735db 1151let macro_expand s =
34e49164
C
1152 let c = open_out "/tmp/ttttt.ml" in
1153 begin
1154 output_string c s; close_out c;
1155 command2 ("ocamlc -c -pp 'camlp4o pa_extend.cmo q_MLast.cmo -impl' " ^
1156 "-I +camlp4 -impl macro.ml4");
1157 command2 "camlp4o ./macro.cmo pr_o.cmo /tmp/ttttt.ml";
1158 command2 "rm -f /tmp/ttttt.ml";
1159 end
1160
1161(*
1162let t = macro_expand "{ x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x>2 and y<3}"
1163let x = { x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x > 2 and y < 3}
1164let t = macro_expand "{1 .. 10}"
1165let x = {1 .. 10} +> List.map (fun i -> i)
1166let t = macro_expand "[1;2] to append to [2;4]"
1167let t = macro_expand "{x = 2; x = 3}"
1168
1169let t = macro_expand "type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)"
1170*)
1171
ae4735db 1172
34e49164
C
1173
1174(*****************************************************************************)
1175(* Composition/Control *)
1176(*****************************************************************************)
1177
1178(* I like the obj.func object notation. In OCaml cant use '.' so I use +>
ae4735db 1179 *
34e49164
C
1180 * update: it seems that F# agrees with me :) but they use |>
1181 *)
1182
1183(* now in prelude:
1184 * let (+>) o f = f o
1185 *)
ae4735db
C
1186let (+!>) refo f = refo := f !refo
1187(* alternatives:
34e49164 1188 * let ((@): 'a -> ('a -> 'b) -> 'b) = fun a b -> b a
ae4735db 1189 * let o f g x = f (g x)
34e49164
C
1190 *)
1191
1192let ($) f g x = g (f x)
1193let compose f g x = f (g x)
1194