Coccinelle release-1.0.0-rc11
[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
3a314143
C
429let clear_pr2_once _ = Hashtbl.clear _already_printed
430
708f4980 431(* ---------------------------------------------------------------------- *)
978fd7e5
C
432let mk_pr2_wrappers aref =
433 let fpr2 s =
708f4980
C
434 if !aref
435 then pr2 s
978fd7e5 436 else
708f4980
C
437 (* just to the log file *)
438 out_chan_pr2 s
439 in
978fd7e5 440 let fpr2_once s =
708f4980
C
441 if !aref
442 then pr2_once s
978fd7e5 443 else
708f4980
C
444 xxx_once out_chan_pr2 s
445 in
978fd7e5 446 fpr2, fpr2_once
34e49164
C
447
448(* ---------------------------------------------------------------------- *)
449(* could also be in File section *)
450
978fd7e5
C
451let redirect_stdout file f =
452 begin
453 let chan = open_out file in
454 let descr = Unix.descr_of_out_channel chan in
455
456 let saveout = Unix.dup Unix.stdout in
457 Unix.dup2 descr Unix.stdout;
458 flush stdout;
459 let res = f() in
460 flush stdout;
461 Unix.dup2 saveout Unix.stdout;
462 close_out chan;
463 res
464 end
465
466let redirect_stdout_opt optfile f =
467 match optfile with
468 | None -> f()
469 | Some outfile -> redirect_stdout outfile f
470
471let redirect_stdout_stderr file f =
34e49164
C
472 begin
473 let chan = open_out file in
474 let descr = Unix.descr_of_out_channel chan in
475
476 let saveout = Unix.dup Unix.stdout in
477 let saveerr = Unix.dup Unix.stderr in
478 Unix.dup2 descr Unix.stdout;
479 Unix.dup2 descr Unix.stderr;
480 flush stdout; flush stderr;
481 f();
482 flush stdout; flush stderr;
483 Unix.dup2 saveout Unix.stdout;
484 Unix.dup2 saveerr Unix.stderr;
485 close_out chan;
486 end
487
978fd7e5 488let redirect_stdin file f =
34e49164
C
489 begin
490 let chan = open_in file in
491 let descr = Unix.descr_of_in_channel chan in
492
493 let savein = Unix.dup Unix.stdin in
494 Unix.dup2 descr Unix.stdin;
3a314143 495 let res = f() in
34e49164
C
496 Unix.dup2 savein Unix.stdin;
497 close_in chan;
3a314143 498 res
34e49164
C
499 end
500
978fd7e5 501let redirect_stdin_opt optfile f =
34e49164
C
502 match optfile with
503 | None -> f()
504 | Some infile -> redirect_stdin infile f
505
506
ae4735db
C
507(* cf end
508let with_pr2_to_string f =
708f4980 509*)
ae4735db 510
34e49164
C
511
512(* ---------------------------------------------------------------------- *)
513
514include Printf
515
516(* cf common.mli, fprintf, printf, eprintf, sprintf.
517 * also what is this ?
518 * val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a
519 * val kprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b
520 *)
521
ae4735db 522(* ex of printf:
34e49164
C
523 * printf "%02d" i
524 * for padding
525 *)
526
527let spf = sprintf
528
529(* ---------------------------------------------------------------------- *)
530
531let _chan = ref stderr
ae4735db 532let start_log_file () =
34e49164
C
533 let filename = (spf "/tmp/debugml%d:%d" (Unix.getuid()) (Unix.getpid())) in
534 pr2 (spf "now using %s for logging" filename);
535 _chan := open_out filename
ae4735db 536
34e49164
C
537
538let dolog s = output_string !_chan (s ^ "\n"); flush !_chan
539
540let verbose_level = ref 1
541let log s = if !verbose_level >= 1 then dolog s
542let log2 s = if !verbose_level >= 2 then dolog s
543let log3 s = if !verbose_level >= 3 then dolog s
544let log4 s = if !verbose_level >= 4 then dolog s
545
546let if_log f = if !verbose_level >= 1 then f()
547let if_log2 f = if !verbose_level >= 2 then f()
548let if_log3 f = if !verbose_level >= 3 then f()
549let if_log4 f = if !verbose_level >= 4 then f()
550
551(* ---------------------------------------------------------------------- *)
552
553let pause () = (pr2 "pause: type return"; ignore(read_line ()))
554
555(* src: from getopt from frish *)
556let bip () = Printf.printf "\007"; flush stdout
ae4735db 557let wait () = Unix.sleep 1
34e49164
C
558
559(* was used by fix_caml *)
560let _trace_var = ref 0
561let add_var() = incr _trace_var
562let dec_var() = decr _trace_var
563let get_var() = !_trace_var
564
ae4735db 565let (print_n: int -> string -> unit) = fun i s ->
34e49164 566 do_n i (fun () -> print_string s)
ae4735db 567let (printerr_n: int -> string -> unit) = fun i s ->
34e49164
C
568 do_n i (fun () -> prerr_string s)
569
570let _debug = ref true
571let debugon () = _debug := true
572let debugoff () = _debug := false
573let debug f = if !_debug then f () else ()
574
575
576
577(* now in prelude:
ae4735db 578 * let debugger = ref false
34e49164
C
579 *)
580
581
582(*****************************************************************************)
583(* Profiling *)
584(*****************************************************************************)
585
586let get_mem() =
587 command2("grep VmData /proc/" ^ string_of_int (Unix.getpid()) ^ "/status")
588
589let memory_stat () =
590 let stat = Gc.stat() in
591 let conv_mo x = x * 4 / 1000000 in
592 Printf.sprintf "maximal = %d Mo\n" (conv_mo stat.Gc.top_heap_words) ^
593 Printf.sprintf "current = %d Mo\n" (conv_mo stat.Gc.heap_words) ^
594 Printf.sprintf "lives = %d Mo\n" (conv_mo stat.Gc.live_words)
595 (* Printf.printf "fragments = %d Mo\n" (conv_mo stat.Gc.fragments); *)
596
ae4735db 597let timenow () =
34e49164 598 "sys:" ^ (string_of_float (Sys.time ())) ^ " seconds" ^
ae4735db 599 ":real:" ^
34e49164 600 (let tm = Unix.time () +> Unix.gmtime in
ae4735db 601 tm.Unix.tm_min +> string_of_int ^ " min:" ^
34e49164
C
602 tm.Unix.tm_sec +> string_of_int ^ ".00 seconds")
603
ae4735db
C
604let _count1 = ref 0
605let _count2 = ref 0
606let _count3 = ref 0
607let _count4 = ref 0
608let _count5 = ref 0
34e49164
C
609
610let count1 () = incr _count1
611let count2 () = incr _count2
612let count3 () = incr _count3
613let count4 () = incr _count4
614let count5 () = incr _count5
615
ae4735db
C
616let profile_diagnostic_basic () =
617 Printf.sprintf
618 "count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\ncount5 = %d\n"
34e49164
C
619 !_count1 !_count2 !_count3 !_count4 !_count5
620
621
622
ae4735db 623let time_func f =
34e49164
C
624 (* let _ = Timing () in *)
625 let x = f () in
626 (* let _ = Timing () in *)
627 x
628
629(* ---------------------------------------------------------------------- *)
630
631type prof = PALL | PNONE | PSOME of string list
632let profile = ref PNONE
485bce71 633let show_trace_profile = ref false
34e49164
C
634
635let check_profile category =
636 match !profile with
637 PALL -> true
638 | PNONE -> false
639 | PSOME l -> List.mem category l
640
641let _profile_table = ref (Hashtbl.create 100)
485bce71
C
642
643let adjust_profile_entry category difftime =
ae4735db 644 let (xtime, xcount) =
485bce71 645 (try Hashtbl.find !_profile_table category
ae4735db 646 with Not_found ->
485bce71
C
647 let xtime = ref 0.0 in
648 let xcount = ref 0 in
649 Hashtbl.add !_profile_table category (xtime, xcount);
650 (xtime, xcount)
651 ) in
652 xtime := !xtime +. difftime;
653 xcount := !xcount + 1;
654 ()
655
34e49164
C
656let profile_start category = failwith "todo"
657let profile_end category = failwith "todo"
658
485bce71 659
34e49164
C
660(* subtil: don't forget to give all argumens to f, otherwise partial app
661 * and will profile nothing.
ae4735db 662 *
0708f913 663 * todo: try also detect when complexity augment each time, so can
ae4735db
C
664 * detect the situation for a function gets worse and worse ?
665 *)
666let profile_code category f =
34e49164 667 if not (check_profile category)
fc1ad971 668 then f()
34e49164 669 else begin
485bce71 670 if !show_trace_profile then pr2 (spf "p: %s" category);
34e49164 671 let t = Unix.gettimeofday () in
ae4735db 672 let res, prefix =
34e49164
C
673 try Some (f ()), ""
674 with Timeout -> None, "*"
675 in
676 let category = prefix ^ category in (* add a '*' to indicate timeout func *)
677 let t' = Unix.gettimeofday () in
485bce71
C
678
679 adjust_profile_entry category (t' -. t);
34e49164
C
680 (match res with
681 | Some res -> res
682 | None -> raise Timeout
683 );
684 end
685
485bce71 686
ae4735db 687let _is_in_exclusif = ref (None: string option)
485bce71 688
ae4735db 689let profile_code_exclusif category f =
485bce71 690 if not (check_profile category)
ae4735db 691 then f()
485bce71
C
692 else begin
693
694 match !_is_in_exclusif with
ae4735db 695 | Some s ->
485bce71 696 failwith (spf "profile_code_exclusif: %s but already in %s " category s);
ae4735db 697 | None ->
485bce71 698 _is_in_exclusif := (Some category);
ae4735db
C
699 finalize
700 (fun () ->
485bce71 701 profile_code category f
ae4735db
C
702 )
703 (fun () ->
485bce71
C
704 _is_in_exclusif := None
705 )
706
707 end
708
ae4735db 709let profile_code_inside_exclusif_ok category f =
485bce71
C
710 failwith "Todo"
711
712
34e49164 713(* todo: also put % ? also add % to see if coherent numbers *)
ae4735db 714let profile_diagnostic () =
34e49164 715 if !profile = PNONE then "" else
ae4735db
C
716 let xs =
717 Hashtbl.fold (fun k v acc -> (k,v)::acc) !_profile_table []
34e49164
C
718 +> List.sort (fun (k1, (t1,n1)) (k2, (t2,n2)) -> compare t2 t1)
719 in
ae4735db 720 with_open_stringbuf (fun (pr,_) ->
34e49164
C
721 pr "---------------------";
722 pr "profiling result";
723 pr "---------------------";
ae4735db 724 xs +> List.iter (fun (k, (t,n)) ->
34e49164
C
725 pr (sprintf "%-40s : %10.3f sec %10d count" k !t !n)
726 )
727 )
728
729
730
ae4735db 731let report_if_take_time timethreshold s f =
34e49164
C
732 let t = Unix.gettimeofday () in
733 let res = f () in
734 let t' = Unix.gettimeofday () in
ae4735db 735 if (t' -. t > float_of_int timethreshold)
978fd7e5 736 then pr2 (sprintf "Note: processing took %7.1fs: %s" (t' -. t) s);
34e49164
C
737 res
738
ae4735db
C
739let profile_code2 category f =
740 profile_code category (fun () ->
34e49164
C
741 if !profile = PALL
742 then pr2 ("starting: " ^ category);
743 let t = Unix.gettimeofday () in
744 let res = f () in
745 let t' = Unix.gettimeofday () in
746 if !profile = PALL
747 then pr2 (spf "ending: %s, %fs" category (t' -. t));
748 res
749 )
ae4735db 750
34e49164
C
751
752(*****************************************************************************)
753(* Test *)
754(*****************************************************************************)
755let example b = assert b
756
757let _ex1 = example (enum 1 4 = [1;2;3;4])
758
ae4735db
C
759let assert_equal a b =
760 if not (a = b)
761 then failwith ("assert_equal: those 2 values are not equal:\n\t" ^
34e49164
C
762 (dump a) ^ "\n\t" ^ (dump b) ^ "\n")
763
ae4735db 764let (example2: string -> bool -> unit) = fun s b ->
34e49164
C
765 try assert b with x -> failwith s
766
767(*-------------------------------------------------------------------*)
768let _list_bool = ref []
769
ae4735db 770let (example3: string -> bool -> unit) = fun s b ->
34e49164
C
771 _list_bool := (s,b)::(!_list_bool)
772
773(* could introduce a fun () otherwise the calculus is made at compile time
774 * and this can be long. This would require to redefine test_all.
ae4735db 775 * let (example3: string -> (unit -> bool) -> unit) = fun s func ->
34e49164 776 * _list_bool := (s,func):: (!_list_bool)
ae4735db 777 *
34e49164
C
778 * I would like to do as a func that take 2 terms, and make an = over it
779 * avoid to add this ugly fun (), but pb of type, cant do that :(
780 *)
781
782
ae4735db
C
783let (test_all: unit -> unit) = fun () ->
784 List.iter (fun (s, b) ->
34e49164
C
785 Printf.printf "%s: %s\n" s (if b then "passed" else "failed")
786 ) !_list_bool
787
ae4735db
C
788let (test: string -> unit) = fun s ->
789 Printf.printf "%s: %s\n" s
34e49164
C
790 (if (List.assoc s (!_list_bool)) then "passed" else "failed")
791
792let _ex = example3 "++" ([1;2]++[3;4;5] = [1;2;3;4;5])
793
794(*-------------------------------------------------------------------*)
795(* Regression testing *)
796(*-------------------------------------------------------------------*)
797
ae4735db 798(* cf end of file. It uses too many other common functions so I
34e49164
C
799 * have put the code at the end of this file.
800 *)
801
802
803
804(* todo? take code from julien signoles in calendar-2.0.2/tests *)
805(*
806
807(* Generic functions used in the tests. *)
808
809val reset : unit -> unit
810val nb_ok : unit -> int
811val nb_bug : unit -> int
812val test : bool -> string -> unit
813val test_exn : 'a Lazy.t -> string -> unit
814
815
816let ok_ref = ref 0
817let ok () = incr ok_ref
818let nb_ok () = !ok_ref
819
820let bug_ref = ref 0
821let bug () = incr bug_ref
822let nb_bug () = !bug_ref
823
824let reset () =
825 ok_ref := 0;
826 bug_ref := 0
827
ae4735db 828let test x s =
34e49164
C
829 if x then ok () else begin Printf.printf "%s\n" s; bug () end;;
830
831let test_exn x s =
832 try
833 ignore (Lazy.force x);
834 Printf.printf "%s\n" s;
835 bug ()
836 with _ ->
837 ok ();;
838*)
839
840
841(*****************************************************************************)
842(* Quickcheck like (sfl) *)
843(*****************************************************************************)
844
845(* Better than quickcheck, cos cant do a test_all_prop in haskell cos
846 * prop were functions, whereas here we have not prop_Unix x = ... but
ae4735db 847 * laws "unit" ...
34e49164
C
848 *
849 * How to do without overloading ? objet ? can pass a generator as a
850 * parameter, mais lourd, prefer automatic inferring of the
851 * generator? But at the same time quickcheck does not do better cos
ae4735db
C
852 * we must explictly type the property. So between a
853 * prop_unit:: [Int] -> [Int] -> bool ...
854 * prop_unit x = reverse [x] == [x]
855 * and
856 * let _ = laws "unit" (fun x -> reverse [x] = [x]) (listg intg)
857 * there is no real differences.
34e49164
C
858 *
859 * Yes I define typeg generator but quickcheck too, he must define
860 * class instance. I emulate the context Gen a => Gen [a] by making
861 * listg take as a param a type generator. Moreover I have not the pb of
ae4735db 862 * monad. I can do random independently, so my code is more simple
34e49164 863 * I think than the haskell code of quickcheck.
ae4735db 864 *
34e49164
C
865 * update: apparently Jane Street have copied some of my code for their
866 * Ounit_util.ml and quichcheck.ml in their Core library :)
867 *)
868
869(*---------------------------------------------------------------------------*)
870(* generators *)
871(*---------------------------------------------------------------------------*)
872type 'a gen = unit -> 'a
873
874let (ig: int gen) = fun () ->
875 Random.int 10
ae4735db 876let (lg: ('a gen) -> ('a list) gen) = fun gen () ->
34e49164 877 foldn (fun acc i -> (gen ())::acc) [] (Random.int 10)
ae4735db 878let (pg: ('a gen) -> ('b gen) -> ('a * 'b) gen) = fun gen1 gen2 () ->
34e49164
C
879 (gen1 (), gen2 ())
880let polyg = ig
ae4735db 881let (ng: (string gen)) = fun () ->
34e49164
C
882 "a" ^ (string_of_int (ig ()))
883
ae4735db
C
884let (oneofl: ('a list) -> 'a gen) = fun xs () ->
885 List.nth xs (Random.int (List.length xs))
34e49164
C
886(* let oneofl l = oneof (List.map always l) *)
887
ae4735db
C
888let (oneof: (('a gen) list) -> 'a gen) = fun xs ->
889 List.nth xs (Random.int (List.length xs))
34e49164
C
890
891let (always: 'a -> 'a gen) = fun e () -> e
892
ae4735db 893let (frequency: ((int * ('a gen)) list) -> 'a gen) = fun xs ->
34e49164
C
894 let sums = sum_int (List.map fst xs) in
895 let i = Random.int sums in
ae4735db
C
896 let rec freq_aux acc = function
897 | (x,g)::xs -> if i < acc+x then g else freq_aux (acc+x) xs
898 | _ -> failwith "frequency"
34e49164
C
899 in
900 freq_aux 0 xs
901let frequencyl l = frequency (List.map (fun (i,e) -> (i,always e)) l)
902
ae4735db 903(*
34e49164
C
904let b = oneof [always true; always false] ()
905let b = frequency [3, always true; 2, always false] ()
906*)
907
908(* cant do this:
909 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneofl [[]; lg gen ()]
910 * nor
911 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneof [always []; lg gen]
ae4735db 912 *
34e49164
C
913 * because caml is not as lazy as haskell :( fix the pb by introducing a size
914 * limit. take the bounds/size as parameter. morover this is needed for
915 * more complex type.
ae4735db 916 *
34e49164 917 * how make a bintreeg ?? we need recursion
ae4735db
C
918 *
919 * let rec (bintreeg: ('a gen) -> ('a bintree) gen) = fun gen () ->
920 * let rec aux n =
34e49164
C
921 * if n = 0 then (Leaf (gen ()))
922 * else frequencyl [1, Leaf (gen ()); 4, Branch ((aux (n / 2)), aux (n / 2))]
923 * ()
924 * in aux 20
ae4735db 925 *
34e49164
C
926 *)
927
928
929(*---------------------------------------------------------------------------*)
930(* property *)
931(*---------------------------------------------------------------------------*)
932
933(* todo: a test_all_laws, better syntax (done already a little with ig in
ae4735db
C
934 * place of intg. En cas d'erreur, print the arg that not respect
935 *
34e49164
C
936 * todo: with monitoring, as in haskell, laws = laws2, no need for 2 func,
937 * but hard i found
ae4735db
C
938 *
939 * todo classify, collect, forall
34e49164
C
940 *)
941
942
943(* return None when good, and Just the_problematic_case when bad *)
944let (laws: string -> ('a -> bool) -> ('a gen) -> 'a option) = fun s func gen ->
945 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
946 let res = List.filter (fun (x,b) -> not b) res in
947 if res = [] then None else Some (fst (List.hd res))
948
949let rec (statistic_number: ('a list) -> (int * 'a) list) = function
950 | [] -> []
951 | x::xs -> let (splitg, splitd) = List.partition (fun y -> y = x) xs in
952 (1+(List.length splitg), x)::(statistic_number splitd)
953
954(* in pourcentage *)
955let (statistic: ('a list) -> (int * 'a) list) = fun xs ->
956 let stat_num = statistic_number xs in
957 let totals = sum_int (List.map fst stat_num) in
ae4735db
C
958 List.map (fun (i, v) -> ((i * 100) / totals), v) stat_num
959
960let (laws2:
961 string -> ('a -> (bool * 'b)) -> ('a gen) ->
962 ('a option * ((int * 'b) list ))) =
34e49164
C
963 fun s func gen ->
964 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
965 let stat = statistic (List.map (fun (x,(b,v)) -> v) res) in
966 let res = List.filter (fun (x,(b,v)) -> not b) res in
967 if res = [] then (None, stat) else (Some (fst (List.hd res)), stat)
968
969
970(*
971let b = laws "unit" (fun x -> reverse [x] = [x] )ig
972let b = laws "app " (fun (xs,ys) -> reverse (xs++ys) = reverse ys++reverse xs)(pg (lg ig)(lg ig))
973let b = laws "rev " (fun xs -> reverse (reverse xs) = xs )(lg ig)
974let b = laws "appb" (fun (xs,ys) -> reverse (xs++ys) = reverse xs++reverse ys)(pg (lg ig)(lg ig))
975let b = laws "max" (fun (x,y) -> x <= y ==> (max x y = y) )(pg ig ig)
976
ae4735db 977let b = laws2 "max" (fun (x,y) -> ((x <= y ==> (max x y = y)), x <= y))(pg ig ig)
34e49164
C
978*)
979
980
981(* todo, do with coarbitrary ?? idea is that given a 'a, generate a 'b
982 * depending of 'a and gen 'b, that is modify gen 'b, what is important is
983 * that each time given the same 'a, we must get the same 'b !!!
984 *)
985
986(*
987let (fg: ('a gen) -> ('b gen) -> ('a -> 'b) gen) = fun gen1 gen2 () ->
988let b = laws "funs" (fun (f,g,h) -> x <= y ==> (max x y = y) )(pg ig ig)
989 *)
990
991(*
ae4735db 992let one_of xs = List.nth xs (Random.int (List.length xs))
34e49164
C
993let take_one xs =
994 if empty xs then failwith "Take_one: empty list"
ae4735db 995 else
34e49164
C
996 let i = Random.int (List.length xs) in
997 List.nth xs i, filter_index (fun j _ -> i <> j) xs
ae4735db 998*)
34e49164
C
999
1000(*****************************************************************************)
1001(* Persistence *)
1002(*****************************************************************************)
1003
ae4735db 1004let get_value filename =
34e49164
C
1005 let chan = open_in filename in
1006 let x = input_value chan in (* <=> Marshal.from_channel *)
1007 (close_in chan; x)
1008
ae4735db 1009let write_value valu filename =
34e49164
C
1010 let chan = open_out filename in
1011 (output_value chan valu; (* <=> Marshal.to_channel *)
1012 (* Marshal.to_channel chan valu [Marshal.Closures]; *)
ae4735db 1013 close_out chan)
34e49164 1014
ae4735db 1015let write_back func filename =
34e49164
C
1016 write_value (func (get_value filename)) filename
1017
1018
485bce71
C
1019let read_value f = get_value f
1020
34e49164 1021
ae4735db 1022let marshal__to_string2 v flags =
0708f913 1023 Marshal.to_string v flags
ae4735db 1024let marshal__to_string a b =
0708f913
C
1025 profile_code "Marshalling" (fun () -> marshal__to_string2 a b)
1026
ae4735db 1027let marshal__from_string2 v flags =
0708f913 1028 Marshal.from_string v flags
ae4735db 1029let marshal__from_string a b =
0708f913
C
1030 profile_code "Marshalling" (fun () -> marshal__from_string2 a b)
1031
1032
1033
34e49164
C
1034(*****************************************************************************)
1035(* Counter *)
1036(*****************************************************************************)
1037let _counter = ref 0
1038let counter () = (_counter := !_counter +1; !_counter)
1039
1040let _counter2 = ref 0
1041let counter2 () = (_counter2 := !_counter2 +1; !_counter2)
1042
1043let _counter3 = ref 0
1044let counter3 () = (_counter3 := !_counter3 +1; !_counter3)
1045
1046type timestamp = int
1047
1048(*****************************************************************************)
1049(* String_of *)
1050(*****************************************************************************)
1051(* To work with the macro system autogenerated string_of and print_ function
1052 (kind of deriving a la haskell) *)
1053
ae4735db 1054(* int, bool, char, float, ref ?, string *)
34e49164
C
1055
1056let string_of_string s = "\"" ^ s "\""
1057
ae4735db 1058let string_of_list f xs =
34e49164
C
1059 "[" ^ (xs +> List.map f +> String.concat ";" ) ^ "]"
1060
1061let string_of_unit () = "()"
1062
1063let string_of_array f xs =
1064 "[|" ^ (xs +> Array.to_list +> List.map f +> String.concat ";") ^ "|]"
1065
1066let string_of_option f = function
1067 | None -> "None "
1068 | Some x -> "Some " ^ (f x)
1069
1070
1071
1072
1073let print_bool x = print_string (if x then "True" else "False")
1074
1075let print_option pr = function
1076 | None -> print_string "None"
1077 | Some x -> print_string "Some ("; pr x; print_string ")"
1078
ae4735db 1079let print_list pr xs =
34e49164 1080 begin
ae4735db
C
1081 print_string "[";
1082 List.iter (fun x -> pr x; print_string ",") xs;
34e49164
C
1083 print_string "]";
1084 end
1085
ae4735db
C
1086(* specialised
1087let (string_of_list: char list -> string) =
34e49164
C
1088 List.fold_left (fun acc x -> acc^(Char.escaped x)) ""
1089*)
1090
1091
1092let rec print_between between fn = function
1093 | [] -> ()
1094 | [x] -> fn x
1095 | x::xs -> fn x; between(); print_between between fn xs
1096
1097
1098
1099
ae4735db
C
1100let adjust_pp_with_indent f =
1101 Format.open_box !_tab_level_print;
34e49164 1102 (*Format.force_newline();*)
ae4735db 1103 f();
34e49164
C
1104 Format.close_box ();
1105 Format.print_newline()
1106
ae4735db
C
1107let adjust_pp_with_indent_and_header s f =
1108 Format.open_box (!_tab_level_print + String.length s);
34e49164
C
1109 do_n !_tab_level_print (fun () -> Format.print_string " ");
1110 Format.print_string s;
1111 f();
1112 Format.close_box ();
1113 Format.print_newline()
1114
1115
1116
1117let pp_do_in_box f = Format.open_box 1; f(); Format.close_box ()
1118let pp_do_in_zero_box f = Format.open_box 0; f(); Format.close_box ()
1119
ae4735db
C
1120let pp_f_in_box f =
1121 Format.open_box 1;
1122 let res = f() in
34e49164
C
1123 Format.close_box ();
1124 res
1125
1126let pp s = Format.print_string s
1127
ae4735db 1128let mk_str_func_of_assoc_conv xs =
0708f913
C
1129 let swap (x,y) = (y,x) in
1130
ae4735db 1131 (fun s ->
0708f913
C
1132 let xs' = List.map swap xs in
1133 List.assoc s xs'
1134 ),
ae4735db 1135 (fun a ->
0708f913
C
1136 List.assoc a xs
1137 )
1138
708f4980
C
1139
1140
1141(* julia: convert something printed using format to print into a string *)
1142(* now at bottom of file
1143let format_to_string f =
1144 ...
1145*)
1146
1147
1148
34e49164
C
1149(*****************************************************************************)
1150(* Macro *)
1151(*****************************************************************************)
1152
1153(* put your macro in macro.ml4, and you can test it interactivly as in lisp *)
ae4735db 1154let macro_expand s =
34e49164
C
1155 let c = open_out "/tmp/ttttt.ml" in
1156 begin
1157 output_string c s; close_out c;
1158 command2 ("ocamlc -c -pp 'camlp4o pa_extend.cmo q_MLast.cmo -impl' " ^
1159 "-I +camlp4 -impl macro.ml4");
1160 command2 "camlp4o ./macro.cmo pr_o.cmo /tmp/ttttt.ml";
1161 command2 "rm -f /tmp/ttttt.ml";
1162 end
1163
1164(*
1165let t = macro_expand "{ x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x>2 and y<3}"
1166let x = { x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x > 2 and y < 3}
1167let t = macro_expand "{1 .. 10}"
1168let x = {1 .. 10} +> List.map (fun i -> i)
1169let t = macro_expand "[1;2] to append to [2;4]"
1170let t = macro_expand "{x = 2; x = 3}"
1171
1172let t = macro_expand "type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)"
1173*)
1174
ae4735db 1175
34e49164
C
1176
1177(*****************************************************************************)
1178(* Composition/Control *)
1179(*****************************************************************************)
1180
1181(* I like the obj.func object notation. In OCaml cant use '.' so I use +>
ae4735db 1182 *
34e49164
C
1183 * update: it seems that F# agrees with me :) but they use |>
1184 *)
1185
1186(* now in prelude:
1187 * let (+>) o f = f o
1188 *)
ae4735db
C
1189let (+!>) refo f = refo := f !refo
1190(* alternatives:
34e49164 1191 * let ((@): 'a -> ('a -> 'b) -> 'b) = fun a b -> b a
ae4735db 1192 * let o f g x = f (g x)
34e49164
C
1193 *)
1194
1195let ($) f g x = g (f x)
1196let compose f g x = f (g x)
1197