1d128a00d802ace19bc49a5cdf8f320cd3a8afeb
[bpt/coccinelle.git] / commons / common.ml
1 (* Yoann Padioleau
2 *
3 * Copyright (C) 1998-2009 Yoann Padioleau
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * version 2.1 as published by the Free Software Foundation, with the
8 * special exception on linking described in file license.txt.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
13 * license.txt for more details.
14 *)
15
16 (*****************************************************************************)
17 (* Notes *)
18 (*****************************************************************************)
19
20
21
22 (* ---------------------------------------------------------------------- *)
23 (* Maybe could split common.ml and use include tricks as in ofullcommon.ml or
24 * Jane Street core lib. But then harder to bundle simple scripts like my
25 * make_full_linux_kernel.ml because would then need to pass all the files
26 * either to ocamlc or either to some #load. Also as the code of many
27 * functions depends on other functions from this common, it would
28 * be tedious to add those dependencies. Here simpler (have just the
29 * pb of the Prelude, but it's a small problem).
30 *
31 * pixel means code from Pascal Rigaux
32 * julia means code from Julia Lawall
33 *)
34 (* ---------------------------------------------------------------------- *)
35
36 (*****************************************************************************)
37 (* We use *)
38 (*****************************************************************************)
39 (*
40 * modules:
41 * - Pervasives, of course
42 * - List
43 * - Str
44 * - Hashtbl
45 * - Format
46 * - Buffer
47 * - Unix and Sys
48 * - Arg
49 *
50 * functions:
51 * - =, <=, max min, abs, ...
52 * - List.rev, List.mem, List.partition,
53 * - List.fold*, List.concat, ...
54 * - Str.global_replace
55 * - Filename.is_relative
56 * - String.uppercase, String.lowercase
57 *
58 *
59 * The Format library allows to hide passing an indent_level variable.
60 * You use as usual the print_string function except that there is
61 * this automatic indent_level variable handled for you (and maybe
62 * more services). src: julia in coccinelle unparse_cocci.
63 *
64 * Extra packages
65 * - ocamlbdb
66 * - ocamlgtk, and gtksourceview
67 * - ocamlgl
68 * - ocamlpython
69 * - ocamlagrep
70 * - ocamlfuse
71 * - ocamlmpi
72 * - ocamlcalendar
73 *
74 * - pcre
75 * - sdl
76 *
77 * Many functions in this file were inspired by Haskell or Lisp librairies.
78 *)
79
80 (*****************************************************************************)
81 (* Prelude *)
82 (*****************************************************************************)
83
84 (* The following functions should be in their respective sections but
85 * because some functions in some sections use functions in other
86 * sections, and because I don't want to take care of the order of
87 * those sections, of those dependencies, I put the functions causing
88 * dependency problem here. C is better than caml on this with the
89 * ability to declare prototype, enabling some form of forward
90 * reference. *)
91
92 let (+>) o f = f o
93 let (++) = (@)
94
95 exception Timeout
96 exception UnixExit of int
97
98 let rec (do_n: int -> (unit -> unit) -> unit) = fun i f ->
99 if i = 0 then () else (f(); do_n (i-1) f)
100 let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i ->
101 if i = 0 then acc else foldn f (f acc i) (i-1)
102
103 let sum_int = List.fold_left (+) 0
104
105 (* could really call it 'for' :) *)
106 let fold_left_with_index f acc =
107 let rec fold_lwi_aux acc n = function
108 | [] -> acc
109 | x::xs -> fold_lwi_aux (f acc x n) (n+1) xs
110 in fold_lwi_aux acc 0
111
112
113 let rec drop n xs =
114 match (n,xs) with
115 | (0,_) -> xs
116 | (_,[]) -> failwith "drop: not enough"
117 | (n,x::xs) -> drop (n-1) xs
118
119 let rec enum_orig x n = if x = n then [n] else x::enum_orig (x+1) n
120
121 let enum x n =
122 if not(x <= n)
123 then failwith (Printf.sprintf "bad values in enum, expect %d <= %d" x n);
124 let rec enum_aux acc x n =
125 if x = n then n::acc else enum_aux (x::acc) (x+1) n
126 in
127 List.rev (enum_aux [] x n)
128
129 let rec take n xs =
130 match (n,xs) with
131 | (0,_) -> []
132 | (_,[]) -> failwith "take: not enough"
133 | (n,x::xs) -> x::take (n-1) xs
134
135
136 let last_n n l = List.rev (take n (List.rev l))
137 let last l = List.hd (last_n 1 l)
138
139
140 let (list_of_string: string -> char list) = function
141 "" -> []
142 | s -> (enum 0 ((String.length s) - 1) +> List.map (String.get s))
143
144 let (lines: string -> string list) = fun s ->
145 let rec lines_aux = function
146 | [] -> []
147 | [x] -> if x = "" then [] else [x]
148 | x::xs ->
149 x::lines_aux xs
150 in
151 Str.split_delim (Str.regexp "\n") s +> lines_aux
152
153
154 let push2 v l =
155 l := v :: !l
156
157 let null xs = match xs with [] -> true | _ -> false
158
159
160
161
162 let debugger = ref false
163
164 let unwind_protect f cleanup =
165 if !debugger then f() else
166 try f ()
167 with e -> begin cleanup e; raise e end
168
169 let finalize f cleanup =
170 if !debugger then f() else
171 try
172 let res = f () in
173 cleanup ();
174 res
175 with e ->
176 cleanup ();
177 raise e
178
179 let command2 s = ignore(Sys.command s)
180
181
182 let (matched: int -> string -> string) = fun i s ->
183 Str.matched_group i s
184
185 let matched1 = fun s -> matched 1 s
186 let matched2 = fun s -> (matched 1 s, matched 2 s)
187 let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s)
188 let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s)
189 let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s)
190 let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s)
191 let matched7 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s, matched 7 s)
192
193 let (with_open_stringbuf: (((string -> unit) * Buffer.t) -> unit) -> string) =
194 fun f ->
195 let buf = Buffer.create 1000 in
196 let pr s = Buffer.add_string buf (s ^ "\n") in
197 f (pr, buf);
198 Buffer.contents buf
199
200
201 let foldl1 p = function x::xs -> List.fold_left p x xs | _ -> failwith "foldl1"
202
203 (*****************************************************************************)
204 (* Debugging/logging *)
205 (*****************************************************************************)
206
207 (* I used this in coccinelle where the huge logging of stuff ask for
208 * a more organized solution that use more visual indentation hints.
209 *
210 * todo? could maybe use log4j instead ? or use Format module more
211 * consistently ?
212 *)
213
214 let _tab_level_print = ref 0
215 let _tab_indent = 5
216
217
218 let _prefix_pr = ref ""
219
220 let indent_do f =
221 _tab_level_print := !_tab_level_print + _tab_indent;
222 finalize f
223 (fun () -> _tab_level_print := !_tab_level_print - _tab_indent;)
224
225
226 let pr s =
227 print_string !_prefix_pr;
228 do_n !_tab_level_print (fun () -> print_string " ");
229 print_string s;
230 print_string "\n";
231 flush stdout
232
233 let pr_no_nl s =
234 print_string !_prefix_pr;
235 do_n !_tab_level_print (fun () -> print_string " ");
236 print_string s;
237 flush stdout
238
239
240 let pr2 s =
241 prerr_string !_prefix_pr;
242 do_n !_tab_level_print (fun () -> prerr_string " ");
243 prerr_string s;
244 prerr_string "\n";
245 flush stderr
246
247 let pr2_no_nl s =
248 prerr_string !_prefix_pr;
249 do_n !_tab_level_print (fun () -> prerr_string " ");
250 prerr_string s;
251 flush stderr
252
253 let pr_xxxxxxxxxxxxxxxxx () =
254 pr "-----------------------------------------------------------------------"
255
256 let pr2_xxxxxxxxxxxxxxxxx () =
257 pr2 "-----------------------------------------------------------------------"
258
259
260 let reset_pr_indent () =
261 _tab_level_print := 0
262
263 (* old:
264 * let pr s = (print_string s; print_string "\n"; flush stdout)
265 * let pr2 s = (prerr_string s; prerr_string "\n"; flush stderr)
266 *)
267
268 (* ---------------------------------------------------------------------- *)
269
270 (* I can not use the _xxx ref tech that I use for common_extra.ml here because
271 * ocaml don't like the polymorphism of Dumper mixed with refs.
272 *
273 * let (_dump_func : ('a -> string) ref) = ref
274 * (fun x -> failwith "no dump yet, have you included common_extra.cmo?")
275 * let (dump : 'a -> string) = fun x ->
276 * !_dump_func x
277 *
278 * So I have included directly dumper.ml in common.ml. It's more practical
279 * when want to give script that use my common.ml, I just have to give
280 * this file.
281 *)
282
283 (* start of dumper.ml *)
284
285 (* Dump an OCaml value into a printable string.
286 * By Richard W.M. Jones (rich@annexia.org).
287 * dumper.ml 1.2 2005/02/06 12:38:21 rich Exp
288 *)
289 open Printf
290 open Obj
291
292 let rec dump r =
293 if is_int r then
294 string_of_int (magic r : int)
295 else ( (* Block. *)
296 let rec get_fields acc = function
297 | 0 -> acc
298 | n -> let n = n-1 in get_fields (field r n :: acc) n
299 in
300 let rec is_list r =
301 if is_int r then (
302 if (magic r : int) = 0 then true (* [] *)
303 else false
304 ) else (
305 let s = size r and t = tag r in
306 if t = 0 && s = 2 then is_list (field r 1) (* h :: t *)
307 else false
308 )
309 in
310 let rec get_list r =
311 if is_int r then []
312 else let h = field r 0 and t = get_list (field r 1) in h :: t
313 in
314 let opaque name =
315 (* XXX In future, print the address of value 'r'. Not possible in
316 * pure OCaml at the moment.
317 *)
318 "<" ^ name ^ ">"
319 in
320
321 let s = size r and t = tag r in
322
323 (* From the tag, determine the type of block. *)
324 if is_list r then ( (* List. *)
325 let fields = get_list r in
326 "[" ^ String.concat "; " (List.map dump fields) ^ "]"
327 )
328 else if t = 0 then ( (* Tuple, array, record. *)
329 let fields = get_fields [] s in
330 "(" ^ String.concat ", " (List.map dump fields) ^ ")"
331 )
332
333 (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
334 * clear if very large constructed values could have the same
335 * tag. XXX *)
336 else if t = lazy_tag then opaque "lazy"
337 else if t = closure_tag then opaque "closure"
338 else if t = object_tag then ( (* Object. *)
339 let fields = get_fields [] s in
340 let clasz, id, slots =
341 match fields with h::h'::t -> h, h', t | _ -> assert false in
342 (* No information on decoding the class (first field). So just print
343 * out the ID and the slots.
344 *)
345 "Object #" ^ dump id ^
346 " (" ^ String.concat ", " (List.map dump slots) ^ ")"
347 )
348 else if t = infix_tag then opaque "infix"
349 else if t = forward_tag then opaque "forward"
350
351 else if t < no_scan_tag then ( (* Constructed value. *)
352 let fields = get_fields [] s in
353 "Tag" ^ string_of_int t ^
354 " (" ^ String.concat ", " (List.map dump fields) ^ ")"
355 )
356 else if t = string_tag then (
357 "\"" ^ String.escaped (magic r : string) ^ "\""
358 )
359 else if t = double_tag then (
360 string_of_float (magic r : float)
361 )
362 else if t = abstract_tag then opaque "abstract"
363 else if t = custom_tag then opaque "custom"
364 else if t = final_tag then opaque "final"
365 else failwith ("dump: impossible tag (" ^ string_of_int t ^ ")")
366 )
367
368 let dump v = dump (repr v)
369
370 (* end of dumper.ml *)
371
372 (*
373 let (dump : 'a -> string) = fun x ->
374 Dumper.dump x
375 *)
376
377
378 (* ---------------------------------------------------------------------- *)
379 let pr2_gen x = pr2 (dump x)
380
381
382
383 (* ---------------------------------------------------------------------- *)
384
385
386 let _already_printed = Hashtbl.create 101
387 let disable_pr2_once = ref false
388 let pr2_once s =
389 if !disable_pr2_once then pr2 s
390 else
391 if not (Hashtbl.mem _already_printed s)
392 then begin
393 Hashtbl.add _already_printed s true;
394 pr2 ("(ONCE) " ^ s);
395 end
396
397
398 (* ---------------------------------------------------------------------- *)
399 (* could also be in File section *)
400
401 let redirect_stdout_stderr file f =
402 begin
403 let chan = open_out file in
404 let descr = Unix.descr_of_out_channel chan in
405
406 let saveout = Unix.dup Unix.stdout in
407 let saveerr = Unix.dup Unix.stderr in
408 Unix.dup2 descr Unix.stdout;
409 Unix.dup2 descr Unix.stderr;
410 flush stdout; flush stderr;
411 f();
412 flush stdout; flush stderr;
413 Unix.dup2 saveout Unix.stdout;
414 Unix.dup2 saveerr Unix.stderr;
415 close_out chan;
416 end
417
418 let redirect_stdin file f =
419 begin
420 let chan = open_in file in
421 let descr = Unix.descr_of_in_channel chan in
422
423 let savein = Unix.dup Unix.stdin in
424 Unix.dup2 descr Unix.stdin;
425 f();
426 Unix.dup2 savein Unix.stdin;
427 close_in chan;
428 end
429
430 let redirect_stdin_opt optfile f =
431 match optfile with
432 | None -> f()
433 | Some infile -> redirect_stdin infile f
434
435
436
437 (* ---------------------------------------------------------------------- *)
438
439 include Printf
440
441 (* cf common.mli, fprintf, printf, eprintf, sprintf.
442 * also what is this ?
443 * val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a
444 * val kprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b
445 *)
446
447 (* ex of printf:
448 * printf "%02d" i
449 * for padding
450 *)
451
452 let spf = sprintf
453
454 (* ---------------------------------------------------------------------- *)
455
456 let _chan = ref stderr
457 let start_log_file () =
458 let filename = (spf "/tmp/debugml%d:%d" (Unix.getuid()) (Unix.getpid())) in
459 pr2 (spf "now using %s for logging" filename);
460 _chan := open_out filename
461
462
463 let dolog s = output_string !_chan (s ^ "\n"); flush !_chan
464
465 let verbose_level = ref 1
466 let log s = if !verbose_level >= 1 then dolog s
467 let log2 s = if !verbose_level >= 2 then dolog s
468 let log3 s = if !verbose_level >= 3 then dolog s
469 let log4 s = if !verbose_level >= 4 then dolog s
470
471 let if_log f = if !verbose_level >= 1 then f()
472 let if_log2 f = if !verbose_level >= 2 then f()
473 let if_log3 f = if !verbose_level >= 3 then f()
474 let if_log4 f = if !verbose_level >= 4 then f()
475
476 (* ---------------------------------------------------------------------- *)
477
478 let pause () = (pr2 "pause: type return"; ignore(read_line ()))
479
480 (* src: from getopt from frish *)
481 let bip () = Printf.printf "\007"; flush stdout
482 let wait () = Unix.sleep 1
483
484 (* was used by fix_caml *)
485 let _trace_var = ref 0
486 let add_var() = incr _trace_var
487 let dec_var() = decr _trace_var
488 let get_var() = !_trace_var
489
490 let (print_n: int -> string -> unit) = fun i s ->
491 do_n i (fun () -> print_string s)
492 let (printerr_n: int -> string -> unit) = fun i s ->
493 do_n i (fun () -> prerr_string s)
494
495 let _debug = ref true
496 let debugon () = _debug := true
497 let debugoff () = _debug := false
498 let debug f = if !_debug then f () else ()
499
500
501
502 (* now in prelude:
503 * let debugger = ref false
504 *)
505
506
507 (*****************************************************************************)
508 (* Profiling *)
509 (*****************************************************************************)
510
511 let get_mem() =
512 command2("grep VmData /proc/" ^ string_of_int (Unix.getpid()) ^ "/status")
513
514 let memory_stat () =
515 let stat = Gc.stat() in
516 let conv_mo x = x * 4 / 1000000 in
517 Printf.sprintf "maximal = %d Mo\n" (conv_mo stat.Gc.top_heap_words) ^
518 Printf.sprintf "current = %d Mo\n" (conv_mo stat.Gc.heap_words) ^
519 Printf.sprintf "lives = %d Mo\n" (conv_mo stat.Gc.live_words)
520 (* Printf.printf "fragments = %d Mo\n" (conv_mo stat.Gc.fragments); *)
521
522 let timenow () =
523 "sys:" ^ (string_of_float (Sys.time ())) ^ " seconds" ^
524 ":real:" ^
525 (let tm = Unix.time () +> Unix.gmtime in
526 tm.Unix.tm_min +> string_of_int ^ " min:" ^
527 tm.Unix.tm_sec +> string_of_int ^ ".00 seconds")
528
529 let _count1 = ref 0
530 let _count2 = ref 0
531 let _count3 = ref 0
532 let _count4 = ref 0
533 let _count5 = ref 0
534
535 let count1 () = incr _count1
536 let count2 () = incr _count2
537 let count3 () = incr _count3
538 let count4 () = incr _count4
539 let count5 () = incr _count5
540
541 let profile_diagnostic_basic () =
542 Printf.sprintf
543 "count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\ncount5 = %d\n"
544 !_count1 !_count2 !_count3 !_count4 !_count5
545
546
547
548 let time_func f =
549 (* let _ = Timing () in *)
550 let x = f () in
551 (* let _ = Timing () in *)
552 x
553
554 (* ---------------------------------------------------------------------- *)
555
556 type prof = PALL | PNONE | PSOME of string list
557 let profile = ref PNONE
558 let show_trace_profile = ref false
559
560 let check_profile category =
561 match !profile with
562 PALL -> true
563 | PNONE -> false
564 | PSOME l -> List.mem category l
565
566 let _profile_table = ref (Hashtbl.create 100)
567
568 let adjust_profile_entry category difftime =
569 let (xtime, xcount) =
570 (try Hashtbl.find !_profile_table category
571 with Not_found ->
572 let xtime = ref 0.0 in
573 let xcount = ref 0 in
574 Hashtbl.add !_profile_table category (xtime, xcount);
575 (xtime, xcount)
576 ) in
577 xtime := !xtime +. difftime;
578 xcount := !xcount + 1;
579 ()
580
581 let profile_start category = failwith "todo"
582 let profile_end category = failwith "todo"
583
584
585 (* subtil: don't forget to give all argumens to f, otherwise partial app
586 * and will profile nothing.
587 *
588 * todo: try also detect when complexity augment each time, so can
589 * detect the situation for a function gets worse and worse ?
590 *)
591 let profile_code category f =
592 if not (check_profile category)
593 then f()
594 else begin
595 if !show_trace_profile then pr2 (spf "p: %s" category);
596 let t = Unix.gettimeofday () in
597 let res, prefix =
598 try Some (f ()), ""
599 with Timeout -> None, "*"
600 in
601 let category = prefix ^ category in (* add a '*' to indicate timeout func *)
602 let t' = Unix.gettimeofday () in
603
604 adjust_profile_entry category (t' -. t);
605 (match res with
606 | Some res -> res
607 | None -> raise Timeout
608 );
609 end
610
611
612 let _is_in_exclusif = ref (None: string option)
613
614 let profile_code_exclusif category f =
615 if not (check_profile category)
616 then f()
617 else begin
618
619 match !_is_in_exclusif with
620 | Some s ->
621 failwith (spf "profile_code_exclusif: %s but already in %s " category s);
622 | None ->
623 _is_in_exclusif := (Some category);
624 finalize
625 (fun () ->
626 profile_code category f
627 )
628 (fun () ->
629 _is_in_exclusif := None
630 )
631
632 end
633
634 let profile_code_inside_exclusif_ok category f =
635 failwith "Todo"
636
637
638 (* todo: also put % ? also add % to see if coherent numbers *)
639 let profile_diagnostic () =
640 if !profile = PNONE then "" else
641 let xs =
642 Hashtbl.fold (fun k v acc -> (k,v)::acc) !_profile_table []
643 +> List.sort (fun (k1, (t1,n1)) (k2, (t2,n2)) -> compare t2 t1)
644 in
645 with_open_stringbuf (fun (pr,_) ->
646 pr "---------------------";
647 pr "profiling result";
648 pr "---------------------";
649 xs +> List.iter (fun (k, (t,n)) ->
650 pr (sprintf "%-40s : %10.3f sec %10d count" k !t !n)
651 )
652 )
653
654
655
656 let report_if_take_time timethreshold s f =
657 let t = Unix.gettimeofday () in
658 let res = f () in
659 let t' = Unix.gettimeofday () in
660 if (t' -. t > float_of_int timethreshold)
661 then pr2 (sprintf "NOTE: this code takes more than: %ds %s" timethreshold s);
662 res
663
664 let profile_code2 category f =
665 profile_code category (fun () ->
666 if !profile = PALL
667 then pr2 ("starting: " ^ category);
668 let t = Unix.gettimeofday () in
669 let res = f () in
670 let t' = Unix.gettimeofday () in
671 if !profile = PALL
672 then pr2 (spf "ending: %s, %fs" category (t' -. t));
673 res
674 )
675
676
677 (*****************************************************************************)
678 (* Test *)
679 (*****************************************************************************)
680 let example b = assert b
681
682 let _ex1 = example (enum 1 4 = [1;2;3;4])
683
684 let assert_equal a b =
685 if not (a = b)
686 then failwith ("assert_equal: those 2 values are not equal:\n\t" ^
687 (dump a) ^ "\n\t" ^ (dump b) ^ "\n")
688
689 let (example2: string -> bool -> unit) = fun s b ->
690 try assert b with x -> failwith s
691
692 (*-------------------------------------------------------------------*)
693 let _list_bool = ref []
694
695 let (example3: string -> bool -> unit) = fun s b ->
696 _list_bool := (s,b)::(!_list_bool)
697
698 (* could introduce a fun () otherwise the calculus is made at compile time
699 * and this can be long. This would require to redefine test_all.
700 * let (example3: string -> (unit -> bool) -> unit) = fun s func ->
701 * _list_bool := (s,func):: (!_list_bool)
702 *
703 * I would like to do as a func that take 2 terms, and make an = over it
704 * avoid to add this ugly fun (), but pb of type, cant do that :(
705 *)
706
707
708 let (test_all: unit -> unit) = fun () ->
709 List.iter (fun (s, b) ->
710 Printf.printf "%s: %s\n" s (if b then "passed" else "failed")
711 ) !_list_bool
712
713 let (test: string -> unit) = fun s ->
714 Printf.printf "%s: %s\n" s
715 (if (List.assoc s (!_list_bool)) then "passed" else "failed")
716
717 let _ex = example3 "++" ([1;2]++[3;4;5] = [1;2;3;4;5])
718
719 (*-------------------------------------------------------------------*)
720 (* Regression testing *)
721 (*-------------------------------------------------------------------*)
722
723 (* cf end of file. It uses too many other common functions so I
724 * have put the code at the end of this file.
725 *)
726
727
728
729 (* todo? take code from julien signoles in calendar-2.0.2/tests *)
730 (*
731
732 (* Generic functions used in the tests. *)
733
734 val reset : unit -> unit
735 val nb_ok : unit -> int
736 val nb_bug : unit -> int
737 val test : bool -> string -> unit
738 val test_exn : 'a Lazy.t -> string -> unit
739
740
741 let ok_ref = ref 0
742 let ok () = incr ok_ref
743 let nb_ok () = !ok_ref
744
745 let bug_ref = ref 0
746 let bug () = incr bug_ref
747 let nb_bug () = !bug_ref
748
749 let reset () =
750 ok_ref := 0;
751 bug_ref := 0
752
753 let test x s =
754 if x then ok () else begin Printf.printf "%s\n" s; bug () end;;
755
756 let test_exn x s =
757 try
758 ignore (Lazy.force x);
759 Printf.printf "%s\n" s;
760 bug ()
761 with _ ->
762 ok ();;
763 *)
764
765
766 (*****************************************************************************)
767 (* Quickcheck like (sfl) *)
768 (*****************************************************************************)
769
770 (* Better than quickcheck, cos cant do a test_all_prop in haskell cos
771 * prop were functions, whereas here we have not prop_Unix x = ... but
772 * laws "unit" ...
773 *
774 * How to do without overloading ? objet ? can pass a generator as a
775 * parameter, mais lourd, prefer automatic inferring of the
776 * generator? But at the same time quickcheck does not do better cos
777 * we must explictly type the property. So between a
778 * prop_unit:: [Int] -> [Int] -> bool ...
779 * prop_unit x = reverse [x] == [x]
780 * and
781 * let _ = laws "unit" (fun x -> reverse [x] = [x]) (listg intg)
782 * there is no real differences.
783 *
784 * Yes I define typeg generator but quickcheck too, he must define
785 * class instance. I emulate the context Gen a => Gen [a] by making
786 * listg take as a param a type generator. Moreover I have not the pb of
787 * monad. I can do random independently, so my code is more simple
788 * I think than the haskell code of quickcheck.
789 *
790 * update: apparently Jane Street have copied some of my code for their
791 * Ounit_util.ml and quichcheck.ml in their Core library :)
792 *)
793
794 (*---------------------------------------------------------------------------*)
795 (* generators *)
796 (*---------------------------------------------------------------------------*)
797 type 'a gen = unit -> 'a
798
799 let (ig: int gen) = fun () ->
800 Random.int 10
801 let (lg: ('a gen) -> ('a list) gen) = fun gen () ->
802 foldn (fun acc i -> (gen ())::acc) [] (Random.int 10)
803 let (pg: ('a gen) -> ('b gen) -> ('a * 'b) gen) = fun gen1 gen2 () ->
804 (gen1 (), gen2 ())
805 let polyg = ig
806 let (ng: (string gen)) = fun () ->
807 "a" ^ (string_of_int (ig ()))
808
809 let (oneofl: ('a list) -> 'a gen) = fun xs () ->
810 List.nth xs (Random.int (List.length xs))
811 (* let oneofl l = oneof (List.map always l) *)
812
813 let (oneof: (('a gen) list) -> 'a gen) = fun xs ->
814 List.nth xs (Random.int (List.length xs))
815
816 let (always: 'a -> 'a gen) = fun e () -> e
817
818 let (frequency: ((int * ('a gen)) list) -> 'a gen) = fun xs ->
819 let sums = sum_int (List.map fst xs) in
820 let i = Random.int sums in
821 let rec freq_aux acc = function
822 | (x,g)::xs -> if i < acc+x then g else freq_aux (acc+x) xs
823 | _ -> failwith "frequency"
824 in
825 freq_aux 0 xs
826 let frequencyl l = frequency (List.map (fun (i,e) -> (i,always e)) l)
827
828 (*
829 let b = oneof [always true; always false] ()
830 let b = frequency [3, always true; 2, always false] ()
831 *)
832
833 (* cant do this:
834 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneofl [[]; lg gen ()]
835 * nor
836 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneof [always []; lg gen]
837 *
838 * because caml is not as lazy as haskell :( fix the pb by introducing a size
839 * limit. take the bounds/size as parameter. morover this is needed for
840 * more complex type.
841 *
842 * how make a bintreeg ?? we need recursion
843 *
844 * let rec (bintreeg: ('a gen) -> ('a bintree) gen) = fun gen () ->
845 * let rec aux n =
846 * if n = 0 then (Leaf (gen ()))
847 * else frequencyl [1, Leaf (gen ()); 4, Branch ((aux (n / 2)), aux (n / 2))]
848 * ()
849 * in aux 20
850 *
851 *)
852
853
854 (*---------------------------------------------------------------------------*)
855 (* property *)
856 (*---------------------------------------------------------------------------*)
857
858 (* todo: a test_all_laws, better syntax (done already a little with ig in
859 * place of intg. En cas d'erreur, print the arg that not respect
860 *
861 * todo: with monitoring, as in haskell, laws = laws2, no need for 2 func,
862 * but hard i found
863 *
864 * todo classify, collect, forall
865 *)
866
867
868 (* return None when good, and Just the_problematic_case when bad *)
869 let (laws: string -> ('a -> bool) -> ('a gen) -> 'a option) = fun s func gen ->
870 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
871 let res = List.filter (fun (x,b) -> not b) res in
872 if res = [] then None else Some (fst (List.hd res))
873
874 let rec (statistic_number: ('a list) -> (int * 'a) list) = function
875 | [] -> []
876 | x::xs -> let (splitg, splitd) = List.partition (fun y -> y = x) xs in
877 (1+(List.length splitg), x)::(statistic_number splitd)
878
879 (* in pourcentage *)
880 let (statistic: ('a list) -> (int * 'a) list) = fun xs ->
881 let stat_num = statistic_number xs in
882 let totals = sum_int (List.map fst stat_num) in
883 List.map (fun (i, v) -> ((i * 100) / totals), v) stat_num
884
885 let (laws2:
886 string -> ('a -> (bool * 'b)) -> ('a gen) ->
887 ('a option * ((int * 'b) list ))) =
888 fun s func gen ->
889 let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in
890 let stat = statistic (List.map (fun (x,(b,v)) -> v) res) in
891 let res = List.filter (fun (x,(b,v)) -> not b) res in
892 if res = [] then (None, stat) else (Some (fst (List.hd res)), stat)
893
894
895 (*
896 let b = laws "unit" (fun x -> reverse [x] = [x] )ig
897 let b = laws "app " (fun (xs,ys) -> reverse (xs++ys) = reverse ys++reverse xs)(pg (lg ig)(lg ig))
898 let b = laws "rev " (fun xs -> reverse (reverse xs) = xs )(lg ig)
899 let b = laws "appb" (fun (xs,ys) -> reverse (xs++ys) = reverse xs++reverse ys)(pg (lg ig)(lg ig))
900 let b = laws "max" (fun (x,y) -> x <= y ==> (max x y = y) )(pg ig ig)
901
902 let b = laws2 "max" (fun (x,y) -> ((x <= y ==> (max x y = y)), x <= y))(pg ig ig)
903 *)
904
905
906 (* todo, do with coarbitrary ?? idea is that given a 'a, generate a 'b
907 * depending of 'a and gen 'b, that is modify gen 'b, what is important is
908 * that each time given the same 'a, we must get the same 'b !!!
909 *)
910
911 (*
912 let (fg: ('a gen) -> ('b gen) -> ('a -> 'b) gen) = fun gen1 gen2 () ->
913 let b = laws "funs" (fun (f,g,h) -> x <= y ==> (max x y = y) )(pg ig ig)
914 *)
915
916 (*
917 let one_of xs = List.nth xs (Random.int (List.length xs))
918 let take_one xs =
919 if empty xs then failwith "Take_one: empty list"
920 else
921 let i = Random.int (List.length xs) in
922 List.nth xs i, filter_index (fun j _ -> i <> j) xs
923 *)
924
925 (*****************************************************************************)
926 (* Persistence *)
927 (*****************************************************************************)
928
929 let get_value filename =
930 let chan = open_in filename in
931 let x = input_value chan in (* <=> Marshal.from_channel *)
932 (close_in chan; x)
933
934 let write_value valu filename =
935 let chan = open_out filename in
936 (output_value chan valu; (* <=> Marshal.to_channel *)
937 (* Marshal.to_channel chan valu [Marshal.Closures]; *)
938 close_out chan)
939
940 let write_back func filename =
941 write_value (func (get_value filename)) filename
942
943
944 let read_value f = get_value f
945
946
947 let marshal__to_string2 v flags =
948 Marshal.to_string v flags
949 let marshal__to_string a b =
950 profile_code "Marshalling" (fun () -> marshal__to_string2 a b)
951
952 let marshal__from_string2 v flags =
953 Marshal.from_string v flags
954 let marshal__from_string a b =
955 profile_code "Marshalling" (fun () -> marshal__from_string2 a b)
956
957
958
959 (*****************************************************************************)
960 (* Counter *)
961 (*****************************************************************************)
962 let _counter = ref 0
963 let counter () = (_counter := !_counter +1; !_counter)
964
965 let _counter2 = ref 0
966 let counter2 () = (_counter2 := !_counter2 +1; !_counter2)
967
968 let _counter3 = ref 0
969 let counter3 () = (_counter3 := !_counter3 +1; !_counter3)
970
971 type timestamp = int
972
973 (*****************************************************************************)
974 (* String_of *)
975 (*****************************************************************************)
976 (* To work with the macro system autogenerated string_of and print_ function
977 (kind of deriving a la haskell) *)
978
979 (* int, bool, char, float, ref ?, string *)
980
981 let string_of_string s = "\"" ^ s "\""
982
983 let string_of_list f xs =
984 "[" ^ (xs +> List.map f +> String.concat ";" ) ^ "]"
985
986 let string_of_unit () = "()"
987
988 let string_of_array f xs =
989 "[|" ^ (xs +> Array.to_list +> List.map f +> String.concat ";") ^ "|]"
990
991 let string_of_option f = function
992 | None -> "None "
993 | Some x -> "Some " ^ (f x)
994
995
996
997
998 let print_bool x = print_string (if x then "True" else "False")
999
1000 let print_option pr = function
1001 | None -> print_string "None"
1002 | Some x -> print_string "Some ("; pr x; print_string ")"
1003
1004 let print_list pr xs =
1005 begin
1006 print_string "[";
1007 List.iter (fun x -> pr x; print_string ",") xs;
1008 print_string "]";
1009 end
1010
1011 (* specialised
1012 let (string_of_list: char list -> string) =
1013 List.fold_left (fun acc x -> acc^(Char.escaped x)) ""
1014 *)
1015
1016
1017 let rec print_between between fn = function
1018 | [] -> ()
1019 | [x] -> fn x
1020 | x::xs -> fn x; between(); print_between between fn xs
1021
1022
1023
1024
1025 let adjust_pp_with_indent f =
1026 Format.open_box !_tab_level_print;
1027 (*Format.force_newline();*)
1028 f();
1029 Format.close_box ();
1030 Format.print_newline()
1031
1032 let adjust_pp_with_indent_and_header s f =
1033 Format.open_box (!_tab_level_print + String.length s);
1034 do_n !_tab_level_print (fun () -> Format.print_string " ");
1035 Format.print_string s;
1036 f();
1037 Format.close_box ();
1038 Format.print_newline()
1039
1040
1041
1042 let pp_do_in_box f = Format.open_box 1; f(); Format.close_box ()
1043 let pp_do_in_zero_box f = Format.open_box 0; f(); Format.close_box ()
1044
1045 let pp_f_in_box f =
1046 Format.open_box 1;
1047 let res = f() in
1048 Format.close_box ();
1049 res
1050
1051 let pp s = Format.print_string s
1052
1053
1054
1055 (* julia: convert something printed using format to print into a string *)
1056 let format_to_string f =
1057 let o = open_out "/tmp/out" in
1058 Format.set_formatter_out_channel o;
1059 let _ = f() in
1060 Format.print_flush();
1061 Format.set_formatter_out_channel stdout;
1062 close_out o;
1063 let i = open_in "/tmp/out" in
1064 let lines = ref [] in
1065 let rec loop _ =
1066 let cur = input_line i in
1067 lines := cur :: !lines;
1068 loop() in
1069 (try loop() with End_of_file -> ());
1070 close_in i;
1071 String.concat "\n" (List.rev !lines)
1072
1073
1074
1075 let mk_str_func_of_assoc_conv xs =
1076 let swap (x,y) = (y,x) in
1077
1078 (fun s ->
1079 let xs' = List.map swap xs in
1080 List.assoc s xs'
1081 ),
1082 (fun a ->
1083 List.assoc a xs
1084 )
1085
1086 (*****************************************************************************)
1087 (* Macro *)
1088 (*****************************************************************************)
1089
1090 (* put your macro in macro.ml4, and you can test it interactivly as in lisp *)
1091 let macro_expand s =
1092 let c = open_out "/tmp/ttttt.ml" in
1093 begin
1094 output_string c s; close_out c;
1095 command2 ("ocamlc -c -pp 'camlp4o pa_extend.cmo q_MLast.cmo -impl' " ^
1096 "-I +camlp4 -impl macro.ml4");
1097 command2 "camlp4o ./macro.cmo pr_o.cmo /tmp/ttttt.ml";
1098 command2 "rm -f /tmp/ttttt.ml";
1099 end
1100
1101 (*
1102 let t = macro_expand "{ x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x>2 and y<3}"
1103 let x = { x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x > 2 and y < 3}
1104 let t = macro_expand "{1 .. 10}"
1105 let x = {1 .. 10} +> List.map (fun i -> i)
1106 let t = macro_expand "[1;2] to append to [2;4]"
1107 let t = macro_expand "{x = 2; x = 3}"
1108
1109 let t = macro_expand "type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)"
1110 *)
1111
1112
1113
1114 (*****************************************************************************)
1115 (* Composition/Control *)
1116 (*****************************************************************************)
1117
1118 (* I like the obj.func object notation. In OCaml cant use '.' so I use +>
1119 *
1120 * update: it seems that F# agrees with me :) but they use |>
1121 *)
1122
1123 (* now in prelude:
1124 * let (+>) o f = f o
1125 *)
1126 let (+!>) refo f = refo := f !refo
1127 (* alternatives:
1128 * let ((@): 'a -> ('a -> 'b) -> 'b) = fun a b -> b a
1129 * let o f g x = f (g x)
1130 *)
1131
1132 let ($) f g x = g (f x)
1133 let compose f g x = f (g x)
1134 (* dont work :( let ( ° ) f g x = f(g(x)) *)
1135
1136 (* trick to have something similar to the 1 `max` 4 haskell infix notation.
1137 by Keisuke Nakano on the caml mailing list.
1138 > let ( /* ) x y = y x
1139 > and ( */ ) x y = x y
1140 or
1141 let ( <| ) x y = y x
1142 and ( |> ) x y = x y
1143
1144 > Then we can make an infix operator <| f |> for a binary function f.
1145 *)
1146
1147 let flip f = fun a b -> f b a
1148
1149 let curry f x y = f (x,y)
1150 let uncurry f (a,b) = f a b
1151
1152 let id = fun x -> x
1153
1154 let do_nothing () = ()
1155
1156 let rec applyn n f o = if n = 0 then o else applyn (n-1) f (f o)
1157
1158 let forever f =
1159 while true do
1160 f();
1161 done
1162
1163
1164 class ['a] shared_variable_hook (x:'a) =
1165 object(self)
1166 val mutable data = x
1167 val mutable registered = []
1168 method set x =
1169 begin
1170 data <- x;
1171 pr "refresh registered";
1172 registered +> List.iter (fun f -> f());
1173 end
1174 method get = data
1175 method modify f = self#set (f self#get)
1176 method register f =
1177 registered <- f :: registered
1178 end
1179
1180 (* src: from aop project. was called ptFix *)
1181 let rec fixpoint trans elem =
1182 let image = trans elem in
1183 if (image = elem)
1184 then elem (* point fixe *)
1185 else fixpoint trans image
1186
1187 (* le point fixe pour les objets. was called ptFixForObjetct *)
1188 let rec fixpoint_for_object trans elem =
1189 let image = trans elem in
1190 if (image#equal elem) then elem (* point fixe *)
1191 else fixpoint_for_object trans image
1192
1193 let (add_hook: ('a -> ('a -> 'b) -> 'b) ref -> ('a -> ('a -> 'b) -> 'b) -> unit) =
1194 fun var f ->
1195 let oldvar = !var in
1196 var := fun arg k -> f arg (fun x -> oldvar x k)
1197
1198 let (add_hook_action: ('a -> unit) -> ('a -> unit) list ref -> unit) =
1199 fun f hooks ->
1200 push2 f hooks
1201
1202 let (run_hooks_action: 'a -> ('a -> unit) list ref -> unit) =
1203 fun obj hooks ->
1204 !hooks +> List.iter (fun f -> try f obj with _ -> ())
1205
1206
1207 type 'a mylazy = (unit -> 'a)
1208
1209 (* a la emacs *)
1210 let save_excursion reference f =
1211 let old = !reference in
1212 let res = f() in
1213 reference := old;
1214 res
1215
1216
1217
1218 let memoized h k f =
1219 try Hashtbl.find h k
1220 with Not_found ->
1221 let v = f () in
1222 begin
1223 Hashtbl.add h k v;
1224 v
1225 end
1226
1227 let cache_in_ref myref f =
1228 match !myref with
1229 | Some e -> e
1230 | None ->
1231 let e = f () in
1232 myref := Some e;
1233 e
1234
1235 let once f =
1236 let already = ref false in
1237 (fun x ->
1238 if not !already
1239 then begin already := true; f x end
1240 )
1241
1242 (* cache_file, cf below *)
1243
1244 let before_leaving f x =
1245 f x;
1246 x
1247
1248 (* finalize, cf prelude *)
1249
1250
1251 (* cheat *)
1252 let rec y f = fun x -> f (y f) x
1253
1254 (*****************************************************************************)
1255 (* Concurrency *)
1256 (*****************************************************************************)
1257
1258 (* from http://en.wikipedia.org/wiki/File_locking
1259 *
1260 * "When using file locks, care must be taken to ensure that operations
1261 * are atomic. When creating the lock, the process must verify that it
1262 * does not exist and then create it, but without allowing another
1263 * process the opportunity to create it in the meantime. Various
1264 * schemes are used to implement this, such as taking advantage of
1265 * system calls designed for this purpose (but such system calls are
1266 * not usually available to shell scripts) or by creating the lock file
1267 * under a temporary name and then attempting to move it into place."
1268 *
1269 * => can't use 'if(not (file_exist xxx)) then create_file xxx' because
1270 * file_exist/create_file are not in atomic section (classic problem).
1271 *
1272 * from man open:
1273 *
1274 * "O_EXCL When used with O_CREAT, if the file already exists it
1275 * is an error and the open() will fail. In this context, a
1276 * symbolic link exists, regardless of where it points to.
1277 * O_EXCL is broken on NFS file systems; programs which
1278 * rely on it for performing locking tasks will contain a
1279 * race condition. The solution for performing atomic file
1280 * locking using a lockfile is to create a unique file on
1281 * the same file system (e.g., incorporating host- name and
1282 * pid), use link(2) to make a link to the lockfile. If
1283 * link(2) returns 0, the lock is successful. Otherwise,
1284 * use stat(2) on the unique file to check if its link
1285 * count has increased to 2, in which case the lock is also
1286 * successful."
1287
1288 *)
1289
1290 exception FileAlreadyLocked
1291
1292 (* Racy if lock file on NFS!!! But still racy with recent Linux ? *)
1293 let acquire_file_lock filename =
1294 pr2 ("Locking file: " ^ filename);
1295 try
1296 let _fd = Unix.openfile filename [Unix.O_CREAT;Unix.O_EXCL] 0o777 in
1297 ()
1298 with Unix.Unix_error (e, fm, argm) ->
1299 pr2 (spf "exn Unix_error: %s %s %s\n" (Unix.error_message e) fm argm);
1300 raise FileAlreadyLocked
1301
1302
1303 let release_file_lock filename =
1304 pr2 ("Releasing file: " ^ filename);
1305 Unix.unlink filename;
1306 ()
1307
1308
1309
1310 (*****************************************************************************)
1311 (* Error managment *)
1312 (*****************************************************************************)
1313
1314 exception Todo
1315 exception Impossible
1316 exception Here
1317 exception ReturnExn
1318
1319 exception Multi_found (* to be consistent with Not_found *)
1320
1321 exception WrongFormat of string
1322
1323 (* old: let _TODO () = failwith "TODO", now via fix_caml with raise Todo *)
1324
1325 let internal_error s = failwith ("internal error: "^s)
1326 let error_cant_have x = internal_error ("cant have this case" ^(dump x))
1327 let myassert cond = if cond then () else failwith "assert error"
1328
1329
1330
1331 (* before warning I was forced to do stuff like this:
1332 *
1333 * let (fixed_int_to_posmap: fixed_int -> posmap) = fun fixed ->
1334 * let v = ((fix_to_i fixed) / (power 2 16)) in
1335 * let _ = Printf.printf "coord xy = %d\n" v in
1336 * v
1337 *
1338 * The need for printf make me force to name stuff :(
1339 * How avoid ? use 'it' special keyword ?
1340 * In fact dont have to name it, use +> (fun v -> ...) so when want
1341 * erase debug just have to erase one line.
1342 *)
1343 let warning s v = (pr2 ("Warning: " ^ s ^ "; value = " ^ (dump v)); v)
1344
1345
1346
1347
1348 let exn_to_s exn =
1349 Printexc.to_string exn
1350
1351 (* alias *)
1352 let string_of_exn exn = exn_to_s exn
1353
1354
1355 (* want or of merd, but cant cos cant put die ... in b (strict call) *)
1356 let (|||) a b = try a with _ -> b
1357
1358 (* emacs/lisp inspiration, (vouillon does that too in unison I think) *)
1359
1360 (* now in Prelude:
1361 * let unwind_protect f cleanup = ...
1362 * let finalize f cleanup = ...
1363 *)
1364
1365 type error = Error of string
1366
1367 (* sometimes to get help from ocaml compiler to tell me places where
1368 * I should update, we sometimes need to change some type from pair
1369 * to triple, hence this kind of fake type.
1370 *)
1371 type evotype = unit
1372 let evoval = ()
1373
1374 (*****************************************************************************)
1375 (* Environment *)
1376 (*****************************************************************************)
1377
1378 let check_stack = ref true
1379 let check_stack_size limit =
1380 if !check_stack then begin
1381 pr2 "checking stack size (do ulimit -s 50000 if problem)";
1382 let rec aux i =
1383 if i = limit
1384 then 0
1385 else 1 + aux (i + 1)
1386 in
1387 assert(aux 0 = limit);
1388 ()
1389 end
1390
1391 let test_check_stack_size limit =
1392 (* bytecode: 100000000 *)
1393 (* native: 10000000 *)
1394 check_stack_size (int_of_string limit)
1395
1396
1397 (* only relevant in bytecode, in native the stacklimit is the os stacklimit
1398 * (adjustable by ulimit -s)
1399 *)
1400 let _init_gc_stack =
1401 Gc.set {(Gc.get ()) with Gc.stack_limit = 100 * 1024 * 1024}
1402
1403
1404 (* if process a big set of files then dont want get overflow in the middle
1405 * so for this we are ready to spend some extra time at the beginning that
1406 * could save far more later.
1407 *)
1408 let check_stack_nbfiles nbfiles =
1409 if nbfiles > 200
1410 then check_stack_size 10000000
1411
1412 (*****************************************************************************)
1413 (* Arguments/options and command line (cocci and acomment) *)
1414 (*****************************************************************************)
1415
1416 (*
1417 * Why define wrappers ? Arg not good enough ? Well the Arg.Rest is not that
1418 * good and I need a way sometimes to get a list of argument.
1419 *
1420 * I could define maybe a new Arg.spec such as
1421 * | String_list of (string list -> unit), but the action may require
1422 * some flags to be set, so better to process this after all flags have
1423 * been set by parse_options. So have to split. Otherwise it would impose
1424 * an order of the options such as
1425 * -verbose_parsing -parse_c file1 file2. and I really like to use bash
1426 * history and add just at the end of my command a -profile for instance.
1427 *
1428 *
1429 * Why want a -action arg1 arg2 arg3 ? (which in turn requires this
1430 * convulated scheme ...) Why not use Arg.String action such as
1431 * "-parse_c", Arg.String (fun file -> ...) ?
1432 * I want something that looks like ocaml function but at the UNIX
1433 * command line level. So natural to have this scheme instead of
1434 * -taxo_file arg2 -sample_file arg3 -parse_c arg1.
1435 *
1436 *
1437 * Why not use the toplevel ?
1438 * - because to debug, ocamldebug is far superior to the toplevel
1439 * (can go back, can go directly to a specific point, etc).
1440 * I want a kind of testing at cmdline level.
1441 * - Also I don't have file completion when in the ocaml toplevel.
1442 * I have to type "/path/to/xxx" without help.
1443 *
1444 *
1445 * Why having variable flags ? Why use 'if !verbose_parsing then ...' ?
1446 * why not use strings and do stuff like the following
1447 * 'if (get_config "verbose_parsing") then ...'
1448 * Because I want to make the interface for flags easier for the code
1449 * that use it. The programmer should not be bothered wether this
1450 * flag is set via args cmd line or a config file, so I want to make it
1451 * as simple as possible, just use a global plain caml ref variable.
1452 *
1453 * Same spirit a little for the action. Instead of having function such as
1454 * test_parsing_c, I could do it only via string. But I still prefer
1455 * to have plain caml test functions. Also it makes it easier to call
1456 * those functions from a toplevel for people who prefer the toplevel.
1457 *
1458 *
1459 * So have flag_spec and action_spec. And in flag have debug_xxx flags,
1460 * verbose_xxx flags and other flags.
1461 *
1462 * I would like to not have to separate the -xxx actions spec from the
1463 * corresponding actions, but those actions may need more than one argument
1464 * and so have to wait for parse_options, which in turn need the options
1465 * spec, so circle.
1466 *
1467 * Also I dont want to mix code with data structures, so it's better that the
1468 * options variable contain just a few stuff and have no side effects except
1469 * setting global variables.
1470 *
1471 * Why not have a global variable such as Common.actions that
1472 * other modules modify ? No, I prefer to do less stuff behind programmer's
1473 * back so better to let the user merge the different options at call
1474 * site, but at least make it easier by providing shortcut for set of options.
1475 *
1476 *
1477 *
1478 *
1479 * todo? isn't unison or scott-mcpeak-lib-in-cil handles that kind of
1480 * stuff better ? That is the need to localize command line argument
1481 * while still being able to gathering them. Same for logging.
1482 * Similiar to the type prof = PALL | PNONE | PSOME of string list.
1483 * Same spirit of fine grain config in log4j ?
1484 *
1485 * todo? how mercurial/cvs/git manage command line options ? because they
1486 * all have a kind of DSL around arguments with some common options,
1487 * specific options, conventions, etc.
1488 *
1489 *
1490 * todo? generate the corresponding noxxx options ?
1491 * todo? generate list of options and show their value ?
1492 *
1493 * todo? make it possible to set this value via a config file ?
1494 *
1495 *
1496 *)
1497
1498 type arg_spec_full = Arg.key * Arg.spec * Arg.doc
1499 type cmdline_options = arg_spec_full list
1500
1501 (* the format is a list of triples:
1502 * (title of section * (optional) explanation of sections * options)
1503 *)
1504 type options_with_title = string * string * arg_spec_full list
1505 type cmdline_sections = options_with_title list
1506
1507
1508 (* ---------------------------------------------------------------------- *)
1509
1510 (* now I use argv as I like at the call sites to show that
1511 * this function internally use argv.
1512 *)
1513 let parse_options options usage_msg argv =
1514 let args = ref [] in
1515 (try
1516 Arg.parse_argv argv options (fun file -> args := file::!args) usage_msg;
1517 args := List.rev !args;
1518 !args
1519 with
1520 | Arg.Bad msg -> eprintf "%s" msg; exit 2
1521 | Arg.Help msg -> printf "%s" msg; exit 0
1522 )
1523
1524
1525
1526
1527 let usage usage_msg options =
1528 Arg.usage (Arg.align options) usage_msg
1529
1530
1531 (* for coccinelle *)
1532
1533 (* If you don't want the -help and --help that are appended by Arg.align *)
1534 let arg_align2 xs =
1535 Arg.align xs +> List.rev +> drop 2 +> List.rev
1536
1537
1538 let short_usage usage_msg ~short_opt =
1539 usage usage_msg short_opt
1540
1541 let long_usage usage_msg ~short_opt ~long_opt =
1542 pr usage_msg;
1543 pr "";
1544 let all_options_with_title =
1545 (("main options", "", short_opt)::long_opt) in
1546 all_options_with_title +> List.iter
1547 (fun (title, explanations, xs) ->
1548 pr title;
1549 pr_xxxxxxxxxxxxxxxxx();
1550 if explanations <> ""
1551 then begin pr explanations; pr "" end;
1552 arg_align2 xs +> List.iter (fun (key,action,s) ->
1553 pr (" " ^ key ^ s)
1554 );
1555 pr "";
1556 );
1557 ()
1558
1559
1560 (* copy paste of Arg.parse. Don't want the default -help msg *)
1561 let arg_parse2 l msg short_usage_fun =
1562 let args = ref [] in
1563 let f = (fun file -> args := file::!args) in
1564 let l = Arg.align l in
1565 (try begin
1566 Arg.parse_argv Sys.argv l f msg;
1567 args := List.rev !args;
1568 !args
1569 end
1570 with
1571 | Arg.Bad msg -> (* eprintf "%s" msg; exit 2; *)
1572 let xs = lines msg in
1573 (* take only head, it's where the error msg is *)
1574 pr2 (List.hd xs);
1575 short_usage_fun();
1576 raise (UnixExit (2))
1577 | Arg.Help msg -> (* printf "%s" msg; exit 0; *)
1578 raise Impossible (* -help is specified in speclist *)
1579 )
1580
1581
1582 (* ---------------------------------------------------------------------- *)
1583 (* kind of unit testing framework, or toplevel like functionnality
1584 * at shell command line. I realize than in fact It follows a current trend
1585 * to have a main cmdline program where can then select different actions,
1586 * as in cvs/hg/git where do hg <action> <arguments>, and the shell even
1587 * use a curried syntax :)
1588 *
1589 *
1590 * Not-perfect-but-basic-feels-right: an action
1591 * spec looks like this:
1592 *
1593 * let actions () = [
1594 * "-parse_taxo", " <file>",
1595 * Common.mk_action_1_arg test_parse_taxo;
1596 * ...
1597 * ]
1598 *
1599 * Not-perfect-but-basic-feels-right because for such functionality we
1600 * need a way to transform a string into a caml function and pass arguments
1601 * and the preceding design does exactly that, even if then the
1602 * functions that use this design are not so convenient to use (there
1603 * are 2 places where we need to pass those data, in the options and in the
1604 * main dispatcher).
1605 *
1606 * Also it's not too much intrusive. Still have an
1607 * action ref variable in the main.ml and can still use the previous
1608 * simpler way to do where the match args with in main.ml do the
1609 * dispatch.
1610 *
1611 * Use like this at option place:
1612 * (Common.options_of_actions actionref (Test_parsing_c.actions())) ++
1613 * Use like this at dispatch action place:
1614 * | xs when List.mem !action (Common.action_list all_actions) ->
1615 * Common.do_action !action xs all_actions
1616 *
1617 *)
1618
1619 type flag_spec = Arg.key * Arg.spec * Arg.doc
1620 type action_spec = Arg.key * Arg.doc * action_func
1621 and action_func = (string list -> unit)
1622
1623 type cmdline_actions = action_spec list
1624 exception WrongNumberOfArguments
1625
1626 let options_of_actions action_ref actions =
1627 actions +> List.map (fun (key, doc, _func) ->
1628 (key, (Arg.Unit (fun () -> action_ref := key)), doc)
1629 )
1630
1631 let (action_list: cmdline_actions -> Arg.key list) = fun xs ->
1632 List.map (fun (a,b,c) -> a) xs
1633
1634 let (do_action: Arg.key -> string list (* args *) -> cmdline_actions -> unit) =
1635 fun key args xs ->
1636 let assoc = xs +> List.map (fun (a,b,c) -> (a,c)) in
1637 let action_func = List.assoc key assoc in
1638 action_func args
1639
1640
1641 (* todo? if have a function with default argument ? would like a
1642 * mk_action_0_or_1_arg ?
1643 *)
1644
1645 let mk_action_0_arg f =
1646 (function
1647 | [] -> f ()
1648 | _ -> raise WrongNumberOfArguments
1649 )
1650
1651 let mk_action_1_arg f =
1652 (function
1653 | [file] -> f file
1654 | _ -> raise WrongNumberOfArguments
1655 )
1656
1657 let mk_action_2_arg f =
1658 (function
1659 | [file1;file2] -> f file1 file2
1660 | _ -> raise WrongNumberOfArguments
1661 )
1662
1663 let mk_action_3_arg f =
1664 (function
1665 | [file1;file2;file3] -> f file1 file2 file3
1666 | _ -> raise WrongNumberOfArguments
1667 )
1668
1669 let mk_action_n_arg f = f
1670
1671
1672 (*****************************************************************************)
1673 (* Equality *)
1674 (*****************************************************************************)
1675
1676 (* Using the generic (=) is tempting, but it backfires, so better avoid it *)
1677
1678 (* To infer all the code that use an equal, and that should be
1679 * transformed, is not that easy, because (=) is used by many
1680 * functions, such as List.find, List.mem, and so on. So the strategy
1681 * is to turn what you were previously using into a function, because
1682 * (=) return an exception when applied to a function. Then you simply
1683 * use ocamldebug to infer where the code has to be transformed.
1684 *)
1685
1686 (* src: caml mailing list ? *)
1687 let (=|=) : int -> int -> bool = (=)
1688 let (=<=) : char -> char -> bool = (=)
1689 let (=$=) : string -> string -> bool = (=)
1690 let (=:=) : bool -> bool -> bool = (=)
1691
1692 (* the evil generic (=). I define another symbol to more easily detect
1693 * it, cos the '=' sign is syntaxically overloaded in caml. It is also
1694 * used to define function.
1695 *)
1696 let (=*=) = (=)
1697
1698 (* if really want to forbid to use '='
1699 let (=) = (=|=)
1700 *)
1701 let (=) () () = false
1702
1703
1704
1705
1706
1707
1708
1709
1710 (*###########################################################################*)
1711 (* And now basic types *)
1712 (*###########################################################################*)
1713
1714
1715
1716 (*****************************************************************************)
1717 (* Bool *)
1718 (*****************************************************************************)
1719 let (==>) b1 b2 = if b1 then b2 else true (* could use too => *)
1720
1721 (* superseded by another <=> below
1722 let (<=>) a b = if a =*= b then 0 else if a < b then -1 else 1
1723 *)
1724
1725 let xor a b = not (a =*= b)
1726
1727
1728 (*****************************************************************************)
1729 (* Char *)
1730 (*****************************************************************************)
1731
1732 let string_of_char c = String.make 1 c
1733
1734 let is_single = String.contains ",;()[]{}_`"
1735 let is_symbol = String.contains "!@#$%&*+./<=>?\\^|:-~"
1736 let is_space = String.contains "\n\t "
1737 let cbetween min max c =
1738 (int_of_char c) <= (int_of_char max) &&
1739 (int_of_char c) >= (int_of_char min)
1740 let is_upper = cbetween 'A' 'Z'
1741 let is_lower = cbetween 'a' 'z'
1742 let is_alpha c = is_upper c || is_lower c
1743 let is_digit = cbetween '0' '9'
1744
1745 let string_of_chars cs = cs +> List.map (String.make 1) +> String.concat ""
1746
1747
1748
1749 (*****************************************************************************)
1750 (* Num *)
1751 (*****************************************************************************)
1752
1753 (* since 3.08, div by 0 raise Div_by_rezo, and not anymore a hardware trap :)*)
1754 let (/!) x y = if y =|= 0 then (log "common.ml: div by 0"; 0) else x / y
1755
1756 (* now in prelude
1757 * let rec (do_n: int -> (unit -> unit) -> unit) = fun i f ->
1758 * if i = 0 then () else (f(); do_n (i-1) f)
1759 *)
1760
1761 (* now in prelude
1762 * let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i ->
1763 * if i = 0 then acc else foldn f (f acc i) (i-1)
1764 *)
1765
1766 let sum_float = List.fold_left (+.) 0.0
1767 let sum_int = List.fold_left (+) 0
1768
1769 let pi = 3.14159265358979323846
1770 let pi2 = pi /. 2.0
1771 let pi4 = pi /. 4.0
1772
1773 (* 180 = pi *)
1774 let (deg_to_rad: float -> float) = fun deg ->
1775 (deg *. pi) /. 180.0
1776
1777 let clampf = function
1778 | n when n < 0.0 -> 0.0
1779 | n when n > 1.0 -> 1.0
1780 | n -> n
1781
1782 let square x = x *. x
1783
1784 let rec power x n = if n =|= 0 then 1 else x * power x (n-1)
1785
1786 let between i min max = i > min && i < max
1787
1788 let (between_strict: int -> int -> int -> bool) = fun a b c ->
1789 a < b && b < c
1790
1791
1792 let bitrange x p = let v = power 2 p in between x (-v) v
1793
1794 (* descendant *)
1795 let (prime1: int -> int option) = fun x ->
1796 let rec prime1_aux n =
1797 if n =|= 1 then None
1798 else
1799 if (x / n) * n =|= x then Some n else prime1_aux (n-1)
1800 in if x =|= 1 then None else if x < 0 then failwith "negative" else prime1_aux (x-1)
1801
1802 (* montant, better *)
1803 let (prime: int -> int option) = fun x ->
1804 let rec prime_aux n =
1805 if n =|= x then None
1806 else
1807 if (x / n) * n =|= x then Some n else prime_aux (n+1)
1808 in if x =|= 1 then None else if x < 0 then failwith "negative" else prime_aux 2
1809
1810 let sum xs = List.fold_left (+) 0 xs
1811 let product = List.fold_left ( * ) 1
1812
1813
1814 let decompose x =
1815 let rec decompose x =
1816 if x =|= 1 then []
1817 else
1818 (match prime x with
1819 | None -> [x]
1820 | Some n -> n::decompose (x / n)
1821 )
1822 in assert (product (decompose x) =|= x); decompose x
1823
1824 let mysquare x = x * x
1825 let sqr a = a *. a
1826
1827
1828 type compare = Equal | Inf | Sup
1829 let (<=>) a b = if a =*= b then Equal else if a < b then Inf else Sup
1830 let (<==>) a b = if a =*= b then 0 else if a < b then -1 else 1
1831
1832 type uint = int
1833
1834
1835 let int_of_stringchar s =
1836 fold_left_with_index (fun acc e i -> acc + (Char.code e*(power 8 i))) 0 (List.rev (list_of_string s))
1837
1838 let int_of_base s base =
1839 fold_left_with_index (fun acc e i ->
1840 let j = Char.code e - Char.code '0' in
1841 if j >= base then failwith "not in good base"
1842 else acc + (j*(power base i))
1843 )
1844 0 (List.rev (list_of_string s))
1845
1846 let int_of_stringbits s = int_of_base s 2
1847 let _ = example (int_of_stringbits "1011" =|= 1*8 + 1*2 + 1*1)
1848
1849 let int_of_octal s = int_of_base s 8
1850 let _ = example (int_of_octal "017" =|= 15)
1851
1852 (* let int_of_hex s = int_of_base s 16, NONONONO cos 'A' - '0' does not give 10 !! *)
1853
1854 let int_of_all s =
1855 if String.length s >= 2 && (String.get s 0 =<= '0') && is_digit (String.get s 1)
1856 then int_of_octal s else int_of_string s
1857
1858
1859 let (+=) ref v = ref := !ref + v
1860 let (-=) ref v = ref := !ref - v
1861
1862 let pourcent x total =
1863 (x * 100) / total
1864 let pourcent_float x total =
1865 ((float_of_int x) *. 100.0) /. (float_of_int total)
1866
1867 let pourcent_float_of_floats x total =
1868 (x *. 100.0) /. total
1869
1870
1871 let pourcent_good_bad good bad =
1872 (good * 100) / (good + bad)
1873
1874 let pourcent_good_bad_float good bad =
1875 (float_of_int good *. 100.0) /. (float_of_int good +. float_of_int bad)
1876
1877 type 'a max_with_elem = int ref * 'a ref
1878 let update_max_with_elem (aref, aelem) ~is_better (newv, newelem) =
1879 if is_better newv aref
1880 then begin
1881 aref := newv;
1882 aelem := newelem;
1883 end
1884
1885 (*****************************************************************************)
1886 (* Numeric/overloading *)
1887 (*****************************************************************************)
1888
1889 type 'a numdict =
1890 NumDict of (('a-> 'a -> 'a) *
1891 ('a-> 'a -> 'a) *
1892 ('a-> 'a -> 'a) *
1893 ('a -> 'a));;
1894
1895 let add (NumDict(a, m, d, n)) = a;;
1896 let mul (NumDict(a, m, d, n)) = m;;
1897 let div (NumDict(a, m, d, n)) = d;;
1898 let neg (NumDict(a, m, d, n)) = n;;
1899
1900 let numd_int = NumDict(( + ),( * ),( / ),( ~- ));;
1901 let numd_float = NumDict(( +. ),( *. ), ( /. ),( ~-. ));;
1902 let testd dict n =
1903 let ( * ) x y = mul dict x y in
1904 let ( / ) x y = div dict x y in
1905 let ( + ) x y = add dict x y in
1906 (* Now you can define all sorts of things in terms of *, /, + *)
1907 let f num = (num * num) / (num + num) in
1908 f n;;
1909
1910
1911
1912 module ArithFloatInfix = struct
1913 let (+..) = (+)
1914 let (-..) = (-)
1915 let (/..) = (/)
1916 let ( *.. ) = ( * )
1917
1918
1919 let (+) = (+.)
1920 let (-) = (-.)
1921 let (/) = (/.)
1922 let ( * ) = ( *. )
1923
1924 let (+=) ref v = ref := !ref + v
1925 let (-=) ref v = ref := !ref - v
1926
1927 end
1928
1929
1930
1931 (*****************************************************************************)
1932 (* Tuples *)
1933 (*****************************************************************************)
1934
1935 type 'a pair = 'a * 'a
1936 type 'a triple = 'a * 'a * 'a
1937
1938 let fst3 (x,_,_) = x
1939 let snd3 (_,y,_) = y
1940 let thd3 (_,_,z) = z
1941
1942 let sndthd (a,b,c) = (b,c)
1943
1944 let map_fst f (x, y) = f x, y
1945 let map_snd f (x, y) = x, f y
1946
1947 let pair f (x,y) = (f x, f y)
1948
1949 (* for my ocamlbeautify script *)
1950 let snd = snd
1951 let fst = fst
1952
1953 let double a = a,a
1954 let swap (x,y) = (y,x)
1955
1956
1957 let tuple_of_list1 = function [a] -> a | _ -> failwith "tuple_of_list1"
1958 let tuple_of_list2 = function [a;b] -> a,b | _ -> failwith "tuple_of_list2"
1959 let tuple_of_list3 = function [a;b;c] -> a,b,c | _ -> failwith "tuple_of_list3"
1960 let tuple_of_list4 = function [a;b;c;d] -> a,b,c,d | _ -> failwith "tuple_of_list4"
1961 let tuple_of_list5 = function [a;b;c;d;e] -> a,b,c,d,e | _ -> failwith "tuple_of_list5"
1962 let tuple_of_list6 = function [a;b;c;d;e;f] -> a,b,c,d,e,f | _ -> failwith "tuple_of_list6"
1963
1964
1965 (*****************************************************************************)
1966 (* Maybe *)
1967 (*****************************************************************************)
1968
1969 (* type 'a maybe = Just of 'a | None *)
1970
1971 type ('a,'b) either = Left of 'a | Right of 'b
1972 (* with sexp *)
1973 type ('a, 'b, 'c) either3 = Left3 of 'a | Middle3 of 'b | Right3 of 'c
1974 (* with sexp *)
1975
1976 let just = function
1977 | (Some x) -> x
1978 | _ -> failwith "just: pb"
1979
1980 let some = just
1981
1982
1983 let fmap f = function
1984 | None -> None
1985 | Some x -> Some (f x)
1986 let map_option = fmap
1987
1988 let do_option f = function
1989 | None -> ()
1990 | Some x -> f x
1991
1992 let optionise f =
1993 try Some (f ()) with Not_found -> None
1994
1995
1996
1997 (* pixel *)
1998 let some_or = function
1999 | None -> id
2000 | Some e -> fun _ -> e
2001
2002
2003 let partition_either f l =
2004 let rec part_either left right = function
2005 | [] -> (List.rev left, List.rev right)
2006 | x :: l ->
2007 (match f x with
2008 | Left e -> part_either (e :: left) right l
2009 | Right e -> part_either left (e :: right) l) in
2010 part_either [] [] l
2011
2012
2013 (* pixel *)
2014 let rec filter_some = function
2015 | [] -> []
2016 | None :: l -> filter_some l
2017 | Some e :: l -> e :: filter_some l
2018
2019 let map_filter f xs = xs +> List.map f +> filter_some
2020
2021 let rec find_some p = function
2022 | [] -> raise Not_found
2023 | x :: l ->
2024 match p x with
2025 | Some v -> v
2026 | None -> find_some p l
2027
2028 (* same
2029 let map_find f xs =
2030 xs +> List.map f +> List.find (function Some x -> true | None -> false)
2031 +> (function Some x -> x | None -> raise Impossible)
2032 *)
2033
2034
2035 let list_to_single_or_exn xs =
2036 match xs with
2037 | [] -> raise Not_found
2038 | x::y::zs -> raise Multi_found
2039 | [x] -> x
2040
2041 (*****************************************************************************)
2042 (* TriBool *)
2043 (*****************************************************************************)
2044
2045 type bool3 = True3 | False3 | TrueFalsePb3 of string
2046
2047
2048
2049 (*****************************************************************************)
2050 (* Regexp, can also use PCRE *)
2051 (*****************************************************************************)
2052
2053 (* Note: OCaml Str regexps are different from Perl regexp:
2054 * - The OCaml regexp must match the entire way.
2055 * So "testBee" =~ "Bee" is wrong
2056 * but "testBee" =~ ".*Bee" is right
2057 * Can have the perl behavior if use Str.search_forward instead of
2058 * Str.string_match.
2059 * - Must add some additional \ in front of some special char. So use
2060 * \\( \\| and also \\b
2061 * - It does not always handle newlines very well.
2062 * - \\b does consider _ but not numbers in indentifiers.
2063 *
2064 * Note: PCRE regexps are then different from Str regexps ...
2065 * - just use '(' ')' for grouping, not '\\)'
2066 * - still need \\b for word boundary, but this time it works ...
2067 * so can match some word that have some digits in them.
2068 *
2069 *)
2070
2071 (* put before String section because String section use some =~ *)
2072
2073 (* let gsubst = global_replace *)
2074
2075
2076 let (==~) s re = Str.string_match re s 0
2077
2078 let _memo_compiled_regexp = Hashtbl.create 101
2079 let candidate_match_func s re =
2080 (* old: Str.string_match (Str.regexp re) s 0 *)
2081 let compile_re =
2082 memoized _memo_compiled_regexp re (fun () -> Str.regexp re)
2083 in
2084 Str.string_match compile_re s 0
2085
2086 let match_func s re =
2087 profile_code "Common.=~" (fun () -> candidate_match_func s re)
2088
2089 let (=~) s re =
2090 match_func s re
2091
2092
2093
2094
2095
2096 let string_match_substring re s =
2097 try let _i = Str.search_forward re s 0 in true
2098 with Not_found -> false
2099
2100 let _ =
2101 example(string_match_substring (Str.regexp "foo") "a foo b")
2102 let _ =
2103 example(string_match_substring (Str.regexp "\\bfoo\\b") "a foo b")
2104 let _ =
2105 example(string_match_substring (Str.regexp "\\bfoo\\b") "a\n\nfoo b")
2106 let _ =
2107 example(string_match_substring (Str.regexp "\\bfoo_bar\\b") "a\n\nfoo_bar b")
2108 (* does not work :(
2109 let _ =
2110 example(string_match_substring (Str.regexp "\\bfoo_bar2\\b") "a\n\nfoo_bar2 b")
2111 *)
2112
2113
2114
2115 let (regexp_match: string -> string -> string) = fun s re ->
2116 assert(s =~ re);
2117 Str.matched_group 1 s
2118
2119 (* beurk, side effect code, but hey, it is convenient *)
2120 (* now in prelude
2121 * let (matched: int -> string -> string) = fun i s ->
2122 * Str.matched_group i s
2123 *
2124 * let matched1 = fun s -> matched 1 s
2125 * let matched2 = fun s -> (matched 1 s, matched 2 s)
2126 * let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s)
2127 * let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s)
2128 * let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s)
2129 * let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s)
2130 *)
2131
2132
2133
2134 let split sep s = Str.split (Str.regexp sep) s
2135 let _ = example (split "/" "" =*= [])
2136 let join sep xs = String.concat sep xs
2137 let _ = example (join "/" ["toto"; "titi"; "tata"] =$= "toto/titi/tata")
2138 (*
2139 let rec join str = function
2140 | [] -> ""
2141 | [x] -> x
2142 | x::xs -> x ^ str ^ (join str xs)
2143 *)
2144
2145
2146 let (split_list_regexp: string -> string list -> (string * string list) list) =
2147 fun re xs ->
2148 let rec split_lr_aux (heading, accu) = function
2149 | [] -> [(heading, List.rev accu)]
2150 | x::xs ->
2151 if x =~ re
2152 then (heading, List.rev accu)::split_lr_aux (x, []) xs
2153 else split_lr_aux (heading, x::accu) xs
2154 in
2155 split_lr_aux ("__noheading__", []) xs
2156 +> (fun xs -> if (List.hd xs) =*= ("__noheading__",[]) then List.tl xs else xs)
2157
2158
2159
2160 let regexp_alpha = Str.regexp
2161 "^[a-zA-Z_][A-Za-z_0-9]*$"
2162
2163
2164 let all_match re s =
2165 let regexp = Str.regexp re in
2166 let res = ref [] in
2167 let _ = Str.global_substitute regexp (fun _s ->
2168 let substr = Str.matched_string s in
2169 assert(substr ==~ regexp); (* @Effect: also use it's side effect *)
2170 let paren_matched = matched1 substr in
2171 push2 paren_matched res;
2172 "" (* @Dummy *)
2173 ) s in
2174 List.rev !res
2175
2176 let _ = example (all_match "\\(@[A-Za-z]+\\)" "ca va @Et toi @Comment"
2177 =*= ["@Et";"@Comment"])
2178
2179
2180 let global_replace_regexp re f_on_substr s =
2181 let regexp = Str.regexp re in
2182 Str.global_substitute regexp (fun _wholestr ->
2183
2184 let substr = Str.matched_string s in
2185 f_on_substr substr
2186 ) s
2187
2188
2189 let regexp_word_str =
2190 "\\([a-zA-Z_][A-Za-z_0-9]*\\)"
2191 let regexp_word = Str.regexp regexp_word_str
2192
2193 let regular_words s =
2194 all_match regexp_word_str s
2195
2196 let contain_regular_word s =
2197 let xs = regular_words s in
2198 List.length xs >= 1
2199
2200
2201
2202 (*****************************************************************************)
2203 (* Strings *)
2204 (*****************************************************************************)
2205
2206 let slength = String.length
2207 let concat = String.concat
2208
2209 (* ruby *)
2210 let i_to_s = string_of_int
2211 let s_to_i = int_of_string
2212
2213
2214 (* strings take space in memory. Better when can share the space used by
2215 similar strings *)
2216 let _shareds = Hashtbl.create 100
2217 let (shared_string: string -> string) = fun s ->
2218 try Hashtbl.find _shareds s
2219 with Not_found -> (Hashtbl.add _shareds s s; s)
2220
2221 let chop = function
2222 | "" -> ""
2223 | s -> String.sub s 0 (String.length s - 1)
2224
2225
2226 let chop_dirsymbol = function
2227 | s when s =~ "\\(.*\\)/$" -> matched1 s
2228 | s -> s
2229
2230
2231 let (<!!>) s (i,j) =
2232 String.sub s i (if j < 0 then String.length s - i + j + 1 else j - i)
2233 (* let _ = example ( "tototati"<!!>(3,-2) = "otat" ) *)
2234
2235 let (<!>) s i = String.get s i
2236
2237 (* pixel *)
2238 let rec split_on_char c s =
2239 try
2240 let sp = String.index s c in
2241 String.sub s 0 sp ::
2242 split_on_char c (String.sub s (sp+1) (String.length s - sp - 1))
2243 with Not_found -> [s]
2244
2245
2246 let lowercase = String.lowercase
2247
2248 let quote s = "\"" ^ s ^ "\""
2249
2250 (* easier to have this to be passed as hof, because ocaml dont have
2251 * haskell "section" operators
2252 *)
2253 let null_string s =
2254 s =$= ""
2255
2256 let is_blank_string s =
2257 s =~ "^\\([ \t]\\)*$"
2258
2259 (* src: lablgtk2/examples/entrycompletion.ml *)
2260 let is_string_prefix s1 s2 =
2261 (String.length s1 <= String.length s2) &&
2262 (String.sub s2 0 (String.length s1) =$= s1)
2263
2264 let plural i s =
2265 if i =|= 1
2266 then Printf.sprintf "%d %s" i s
2267 else Printf.sprintf "%d %ss" i s
2268
2269 let showCodeHex xs = List.iter (fun i -> printf "%02x" i) xs
2270
2271 let take_string n s =
2272 String.sub s 0 (n-1)
2273
2274 let take_string_safe n s =
2275 if n > String.length s
2276 then s
2277 else take_string n s
2278
2279
2280
2281 (* used by LFS *)
2282 let size_mo_ko i =
2283 let ko = (i / 1024) mod 1024 in
2284 let mo = (i / 1024) / 1024 in
2285 (if mo > 0
2286 then sprintf "%dMo%dKo" mo ko
2287 else sprintf "%dKo" ko
2288 )
2289
2290 let size_ko i =
2291 let ko = i / 1024 in
2292 sprintf "%dKo" ko
2293
2294
2295
2296
2297
2298
2299 (* done in summer 2007 for julia
2300 * Reference: P216 of gusfeld book
2301 * For two strings S1 and S2, D(i,j) is defined to be the edit distance of S1[1..i] to S2[1..j]
2302 * So edit distance of S1 (of length n) and S2 (of length m) is D(n,m)
2303 *
2304 * Dynamic programming technique
2305 * base:
2306 * D(i,0) = i for all i (cos to go from S1[1..i] to 0 characteres of S2 you have to delete all characters from S1[1..i]
2307 * D(0,j) = j for all j (cos j characters must be inserted)
2308 * recurrence:
2309 * D(i,j) = min([D(i-1, j)+1, D(i, j - 1 + 1), D(i-1, j-1) + t(i,j)])
2310 * where t(i,j) is equal to 1 if S1(i) != S2(j) and 0 if equal
2311 * intuition = there is 4 possible action = deletion, insertion, substitution, or match
2312 * so Lemma =
2313 *
2314 * D(i,j) must be one of the three
2315 * D(i, j-1) + 1
2316 * D(i-1, j)+1
2317 * D(i-1, j-1) +
2318 * t(i,j)
2319 *
2320 *
2321 *)
2322 let matrix_distance s1 s2 =
2323 let n = (String.length s1) in
2324 let m = (String.length s2) in
2325 let mat = Array.make_matrix (n+1) (m+1) 0 in
2326 let t i j =
2327 if String.get s1 (i-1) =<= String.get s2 (j-1)
2328 then 0
2329 else 1
2330 in
2331 let min3 a b c = min (min a b) c in
2332
2333 begin
2334 for i = 0 to n do
2335 mat.(i).(0) <- i
2336 done;
2337 for j = 0 to m do
2338 mat.(0).(j) <- j;
2339 done;
2340 for i = 1 to n do
2341 for j = 1 to m do
2342 mat.(i).(j) <-
2343 min3 (mat.(i).(j-1) + 1) (mat.(i-1).(j) + 1) (mat.(i-1).(j-1) + t i j)
2344 done
2345 done;
2346 mat
2347 end
2348 let edit_distance s1 s2 =
2349 (matrix_distance s1 s2).(String.length s1).(String.length s2)
2350
2351
2352 let test = edit_distance "vintner" "writers"
2353 let _ = assert (edit_distance "winter" "winter" =|= 0)
2354 let _ = assert (edit_distance "vintner" "writers" =|= 5)
2355
2356
2357 (*****************************************************************************)
2358 (* Filenames *)
2359 (*****************************************************************************)
2360
2361 let dirname = Filename.dirname
2362 let basename = Filename.basename
2363
2364 type filename = string (* TODO could check that exist :) type sux *)
2365 (* with sexp *)
2366 type dirname = string (* TODO could check that exist :) type sux *)
2367 (* with sexp *)
2368
2369 module BasicType = struct
2370 type filename = string
2371 end
2372
2373
2374 let (filesuffix: filename -> string) = fun s ->
2375 (try regexp_match s ".+\\.\\([a-zA-Z0-9_]+\\)$" with _ -> "NOEXT")
2376 let (fileprefix: filename -> string) = fun s ->
2377 (try regexp_match s "\\(.+\\)\\.\\([a-zA-Z0-9_]+\\)?$" with _ -> s)
2378
2379 let _ = example (filesuffix "toto.c" =$= "c")
2380 let _ = example (fileprefix "toto.c" =$= "toto")
2381
2382 (*
2383 assert (s = fileprefix s ^ filesuffix s)
2384
2385 let withoutExtension s = global_replace (regexp "\\..*$") "" s
2386 let () = example "without"
2387 (withoutExtension "toto.s.toto" = "toto")
2388 *)
2389
2390 let adjust_ext_if_needed filename ext =
2391 if String.get ext 0 <> '.'
2392 then failwith "I need an extension such as .c not just c";
2393
2394 if not (filename =~ (".*\\" ^ ext))
2395 then filename ^ ext
2396 else filename
2397
2398
2399
2400 let db_of_filename file =
2401 dirname file, basename file
2402
2403 let filename_of_db (basedir, file) =
2404 Filename.concat basedir file
2405
2406
2407
2408 let dbe_of_filename file =
2409 (* raise Invalid_argument if no ext, so safe to use later the unsafe
2410 * fileprefix and filesuffix functions.
2411 *)
2412 ignore(Filename.chop_extension file);
2413 Filename.dirname file,
2414 Filename.basename file +> fileprefix,
2415 Filename.basename file +> filesuffix
2416
2417 let filename_of_dbe (dir, base, ext) =
2418 Filename.concat dir (base ^ "." ^ ext)
2419
2420
2421 let dbe_of_filename_safe file =
2422 try Left (dbe_of_filename file)
2423 with Invalid_argument _ ->
2424 Right (Filename.dirname file, Filename.basename file)
2425
2426
2427 let dbe_of_filename_nodot file =
2428 let (d,b,e) = dbe_of_filename file in
2429 let d = if d =$= "." then "" else d in
2430 d,b,e
2431
2432
2433
2434
2435
2436 let replace_ext file oldext newext =
2437 let (d,b,e) = dbe_of_filename file in
2438 assert(e =$= oldext);
2439 filename_of_dbe (d,b,newext)
2440
2441
2442 let normalize_path file =
2443 let (dir, filename) = Filename.dirname file, Filename.basename file in
2444 let xs = split "/" dir in
2445 let rec aux acc = function
2446 | [] -> List.rev acc
2447 | x::xs ->
2448 (match x with
2449 | "." -> aux acc xs
2450 | ".." -> aux (List.tl acc) xs
2451 | x -> aux (x::acc) xs
2452 )
2453 in
2454 let xs' = aux [] xs in
2455 Filename.concat (join "/" xs') filename
2456
2457
2458
2459 (*
2460 let relative_to_absolute s =
2461 if Filename.is_relative s
2462 then
2463 begin
2464 let old = Sys.getcwd () in
2465 Sys.chdir s;
2466 let current = Sys.getcwd () in
2467 Sys.chdir old;
2468 s
2469 end
2470 else s
2471 *)
2472
2473 let relative_to_absolute s =
2474 if Filename.is_relative s
2475 then Sys.getcwd () ^ "/" ^ s
2476 else s
2477
2478 let is_relative s = Filename.is_relative s
2479 let is_absolute s = not (is_relative s)
2480
2481
2482 (* @Pre: prj_path must not contain regexp symbol *)
2483 let filename_without_leading_path prj_path s =
2484 let prj_path = chop_dirsymbol prj_path in
2485 if s =~ ("^" ^ prj_path ^ "/\\(.*\\)$")
2486 then matched1 s
2487 else
2488 failwith
2489 (spf "cant find filename_without_project_path: %s %s" prj_path s)
2490
2491
2492 (*****************************************************************************)
2493 (* i18n *)
2494 (*****************************************************************************)
2495 type langage =
2496 | English
2497 | Francais
2498 | Deutsch
2499
2500 (* gettext ? *)
2501
2502
2503 (*****************************************************************************)
2504 (* Dates *)
2505 (*****************************************************************************)
2506
2507 (* maybe I should use ocamlcalendar, but I don't like all those functors ... *)
2508
2509 type month =
2510 | Jan | Feb | Mar | Apr | May | Jun
2511 | Jul | Aug | Sep | Oct | Nov | Dec
2512 type year = Year of int
2513 type day = Day of int
2514 type wday = Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday
2515
2516 type date_dmy = DMY of day * month * year
2517
2518 type hour = Hour of int
2519 type minute = Min of int
2520 type second = Sec of int
2521
2522 type time_hms = HMS of hour * minute * second
2523
2524 type full_date = date_dmy * time_hms
2525
2526
2527 (* intervalle *)
2528 type days = Days of int
2529
2530 type time_dmy = TimeDMY of day * month * year
2531
2532
2533 type float_time = float
2534
2535
2536
2537 let check_date_dmy (DMY (day, month, year)) =
2538 raise Todo
2539
2540 let check_time_dmy (TimeDMY (day, month, year)) =
2541 raise Todo
2542
2543 let check_time_hms (HMS (x,y,a)) =
2544 raise Todo
2545
2546
2547
2548 (* ---------------------------------------------------------------------- *)
2549
2550 (* older code *)
2551 let int_to_month i =
2552 assert (i <= 12 && i >= 1);
2553 match i with
2554
2555 | 1 -> "Jan"
2556 | 2 -> "Feb"
2557 | 3 -> "Mar"
2558 | 4 -> "Apr"
2559 | 5 -> "May"
2560 | 6 -> "Jun"
2561 | 7 -> "Jul"
2562 | 8 -> "Aug"
2563 | 9 -> "Sep"
2564 | 10 -> "Oct"
2565 | 11 -> "Nov"
2566 | 12 -> "Dec"
2567 (*
2568 | 1 -> "January"
2569 | 2 -> "February"
2570 | 3 -> "March"
2571 | 4 -> "April"
2572 | 5 -> "May"
2573 | 6 -> "June"
2574 | 7 -> "July"
2575 | 8 -> "August"
2576 | 9 -> "September"
2577 | 10 -> "October"
2578 | 11 -> "November"
2579 | 12 -> "December"
2580 *)
2581 | _ -> raise Impossible
2582
2583
2584 let month_info = [
2585 1 , Jan, "Jan", "January", 31;
2586 2 , Feb, "Feb", "February", 28;
2587 3 , Mar, "Mar", "March", 31;
2588 4 , Apr, "Apr", "April", 30;
2589 5 , May, "May", "May", 31;
2590 6 , Jun, "Jun", "June", 30;
2591 7 , Jul, "Jul", "July", 31;
2592 8 , Aug, "Aug", "August", 31;
2593 9 , Sep, "Sep", "September", 30;
2594 10 , Oct, "Oct", "October", 31;
2595 11 , Nov, "Nov", "November", 30;
2596 12 , Dec, "Dec", "December", 31;
2597 ]
2598
2599 let week_day_info = [
2600 0 , Sunday , "Sun" , "Dim" , "Sunday";
2601 1 , Monday , "Mon" , "Lun" , "Monday";
2602 2 , Tuesday , "Tue" , "Mar" , "Tuesday";
2603 3 , Wednesday , "Wed" , "Mer" , "Wednesday";
2604 4 , Thursday , "Thu" ,"Jeu" ,"Thursday";
2605 5 , Friday , "Fri" , "Ven" , "Friday";
2606 6 , Saturday , "Sat" ,"Sam" , "Saturday";
2607 ]
2608
2609 let i_to_month_h =
2610 month_info +> List.map (fun (i,month,monthstr,mlong,days) -> i, month)
2611 let s_to_month_h =
2612 month_info +> List.map (fun (i,month,monthstr,mlong,days) -> monthstr, month)
2613 let slong_to_month_h =
2614 month_info +> List.map (fun (i,month,monthstr,mlong,days) -> mlong, month)
2615 let month_to_s_h =
2616 month_info +> List.map (fun (i,month,monthstr,mlong,days) -> month, monthstr)
2617 let month_to_i_h =
2618 month_info +> List.map (fun (i,month,monthstr,mlong,days) -> month, i)
2619
2620 let i_to_wday_h =
2621 week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> i, day)
2622 let wday_to_en_h =
2623 week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> day, dayen)
2624 let wday_to_fr_h =
2625 week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> day, dayfr)
2626
2627 let month_of_string s =
2628 List.assoc s s_to_month_h
2629
2630 let month_of_string_long s =
2631 List.assoc s slong_to_month_h
2632
2633 let string_of_month s =
2634 List.assoc s month_to_s_h
2635
2636 let month_of_int i =
2637 List.assoc i i_to_month_h
2638
2639 let int_of_month m =
2640 List.assoc m month_to_i_h
2641
2642
2643 let wday_of_int i =
2644 List.assoc i i_to_wday_h
2645
2646 let string_en_of_wday wday =
2647 List.assoc wday wday_to_en_h
2648 let string_fr_of_wday wday =
2649 List.assoc wday wday_to_fr_h
2650
2651 (* ---------------------------------------------------------------------- *)
2652
2653 let wday_str_of_int ~langage i =
2654 let wday = wday_of_int i in
2655 match langage with
2656 | English -> string_en_of_wday wday
2657 | Francais -> string_fr_of_wday wday
2658 | Deutsch -> raise Todo
2659
2660
2661
2662 let string_of_date_dmy (DMY (Day n, month, Year y)) =
2663 (spf "%02d-%s-%d" n (string_of_month month) y)
2664
2665
2666 let string_of_unix_time ?(langage=English) tm =
2667 let y = tm.Unix.tm_year + 1900 in
2668 let mon = string_of_month (month_of_int (tm.Unix.tm_mon + 1)) in
2669 let d = tm.Unix.tm_mday in
2670 let h = tm.Unix.tm_hour in
2671 let min = tm.Unix.tm_min in
2672 let s = tm.Unix.tm_sec in
2673
2674 let wday = wday_str_of_int ~langage tm.Unix.tm_wday in
2675
2676 spf "%02d/%03s/%04d (%s) %02d:%02d:%02d" d mon y wday h min s
2677
2678 (* ex: 21/Jul/2008 (Lun) 21:25:12 *)
2679 let unix_time_of_string s =
2680 if s =~
2681 ("\\([0-9][0-9]\\)/\\(...\\)/\\([0-9][0-9][0-9][0-9]\\) " ^
2682 "\\(.*\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)")
2683 then
2684 let (sday, smonth, syear, _sday, shour, smin, ssec) = matched7 s in
2685
2686 let y = s_to_i syear - 1900 in
2687 let mon =
2688 smonth +> month_of_string +> int_of_month +> (fun i -> i -1)
2689 in
2690
2691 let tm = Unix.localtime (Unix.time ()) in
2692 { tm with
2693 Unix.tm_year = y;
2694 Unix.tm_mon = mon;
2695 Unix.tm_mday = s_to_i sday;
2696 Unix.tm_hour = s_to_i shour;
2697 Unix.tm_min = s_to_i smin;
2698 Unix.tm_sec = s_to_i ssec;
2699 }
2700 else failwith ("unix_time_of_string: " ^ s)
2701
2702
2703
2704 let short_string_of_unix_time ?(langage=English) tm =
2705 let y = tm.Unix.tm_year + 1900 in
2706 let mon = string_of_month (month_of_int (tm.Unix.tm_mon + 1)) in
2707 let d = tm.Unix.tm_mday in
2708 let _h = tm.Unix.tm_hour in
2709 let _min = tm.Unix.tm_min in
2710 let _s = tm.Unix.tm_sec in
2711
2712 let wday = wday_str_of_int ~langage tm.Unix.tm_wday in
2713
2714 spf "%02d/%03s/%04d (%s)" d mon y wday
2715
2716
2717 let string_of_unix_time_lfs time =
2718 spf "%02d--%s--%d"
2719 time.Unix.tm_mday
2720 (int_to_month (time.Unix.tm_mon + 1))
2721 (time.Unix.tm_year + 1900)
2722
2723
2724 (* ---------------------------------------------------------------------- *)
2725 let string_of_floattime ?langage i =
2726 let tm = Unix.localtime i in
2727 string_of_unix_time ?langage tm
2728
2729 let short_string_of_floattime ?langage i =
2730 let tm = Unix.localtime i in
2731 short_string_of_unix_time ?langage tm
2732
2733 let floattime_of_string s =
2734 let tm = unix_time_of_string s in
2735 let (sec,_tm) = Unix.mktime tm in
2736 sec
2737
2738
2739 (* ---------------------------------------------------------------------- *)
2740 let days_in_week_of_day day =
2741 let tm = Unix.localtime day in
2742
2743 let wday = tm.Unix.tm_wday in
2744 let wday = if wday =|= 0 then 6 else wday -1 in
2745
2746 let mday = tm.Unix.tm_mday in
2747
2748 let start_d = mday - wday in
2749 let end_d = mday + (6 - wday) in
2750
2751 enum start_d end_d +> List.map (fun mday ->
2752 Unix.mktime {tm with Unix.tm_mday = mday} +> fst
2753 )
2754
2755 let first_day_in_week_of_day day =
2756 List.hd (days_in_week_of_day day)
2757
2758 let last_day_in_week_of_day day =
2759 last (days_in_week_of_day day)
2760
2761
2762 (* ---------------------------------------------------------------------- *)
2763
2764 (* (modified) copy paste from ocamlcalendar/src/date.ml *)
2765 let days_month =
2766 [| 0; 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334(*; 365*) |]
2767
2768
2769 let rough_days_since_jesus (DMY (Day nday, month, Year year)) =
2770 let n =
2771 nday +
2772 (days_month.(int_of_month month -1)) +
2773 year * 365
2774 in
2775 Days n
2776
2777
2778
2779 let is_more_recent d1 d2 =
2780 let (Days n1) = rough_days_since_jesus d1 in
2781 let (Days n2) = rough_days_since_jesus d2 in
2782 (n1 > n2)
2783
2784
2785 let max_dmy d1 d2 =
2786 if is_more_recent d1 d2
2787 then d1
2788 else d2
2789
2790 let min_dmy d1 d2 =
2791 if is_more_recent d1 d2
2792 then d2
2793 else d1
2794
2795
2796 let maximum_dmy ds =
2797 foldl1 max_dmy ds
2798
2799 let minimum_dmy ds =
2800 foldl1 min_dmy ds
2801
2802
2803
2804 let rough_days_between_dates d1 d2 =
2805 let (Days n1) = rough_days_since_jesus d1 in
2806 let (Days n2) = rough_days_since_jesus d2 in
2807 Days (n2 - n1)
2808
2809 let _ = example
2810 (rough_days_between_dates
2811 (DMY (Day 7, Jan, Year 1977))
2812 (DMY (Day 13, Jan, Year 1977)) =*= Days 6)
2813
2814 (* because of rough days, it is a bit buggy, here it should return 1 *)
2815 (*
2816 let _ = assert_equal
2817 (rough_days_between_dates
2818 (DMY (Day 29, Feb, Year 1977))
2819 (DMY (Day 1, Mar , Year 1977)))
2820 (Days 1)
2821 *)
2822
2823
2824 (* from julia, in gitsort.ml *)
2825
2826 (*
2827 let antimonths =
2828 [(1,31);(2,28);(3,31);(4,30);(5,31); (6,6);(7,7);(8,31);(9,30);(10,31);
2829 (11,30);(12,31);(0,31)]
2830
2831 let normalize (year,month,day,hour,minute,second) =
2832 if hour < 0
2833 then
2834 let (day,hour) = (day - 1,hour + 24) in
2835 if day = 0
2836 then
2837 let month = month - 1 in
2838 let day = List.assoc month antimonths in
2839 let day =
2840 if month = 2 && year / 4 * 4 = year && not (year / 100 * 100 = year)
2841 then 29
2842 else day in
2843 if month = 0
2844 then (year-1,12,day,hour,minute,second)
2845 else (year,month,day,hour,minute,second)
2846 else (year,month,day,hour,minute,second)
2847 else (year,month,day,hour,minute,second)
2848
2849 *)
2850
2851
2852 let mk_date_dmy day month year =
2853 let date = DMY (Day day, month_of_int month, Year year) in
2854 (* check_date_dmy date *)
2855 date
2856
2857
2858 (* ---------------------------------------------------------------------- *)
2859 (* conversion to unix.tm *)
2860
2861 let dmy_to_unixtime (DMY (Day n, month, Year year)) =
2862 let tm = {
2863 Unix.tm_sec = 0; (** Seconds 0..60 *)
2864 tm_min = 0; (** Minutes 0..59 *)
2865 tm_hour = 12; (** Hours 0..23 *)
2866 tm_mday = n; (** Day of month 1..31 *)
2867 tm_mon = (int_of_month month -1); (** Month of year 0..11 *)
2868 tm_year = year - 1900; (** Year - 1900 *)
2869 tm_wday = 0; (** Day of week (Sunday is 0) *)
2870 tm_yday = 0; (** Day of year 0..365 *)
2871 tm_isdst = false; (** Daylight time savings in effect *)
2872 } in
2873 Unix.mktime tm
2874
2875 let unixtime_to_dmy tm =
2876 let n = tm.Unix.tm_mday in
2877 let month = month_of_int (tm.Unix.tm_mon + 1) in
2878 let year = tm.Unix.tm_year + 1900 in
2879
2880 DMY (Day n, month, Year year)
2881
2882
2883 let unixtime_to_floattime tm =
2884 Unix.mktime tm +> fst
2885
2886 let floattime_to_unixtime sec =
2887 Unix.localtime sec
2888
2889
2890 let sec_to_days sec =
2891 let minfactor = 60 in
2892 let hourfactor = 60 * 60 in
2893 let dayfactor = 60 * 60 * 24 in
2894
2895 let days = sec / dayfactor in
2896 let hours = (sec mod dayfactor) / hourfactor in
2897 let mins = (sec mod hourfactor) / minfactor in
2898 let sec = (sec mod 60) in
2899 (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *)
2900 (if days > 0 then plural days "day" ^ " " else "") ^
2901 (if hours > 0 then plural hours "hour" ^ " " else "") ^
2902 (if mins > 0 then plural mins "min" ^ " " else "") ^
2903 (spf "%dsec" sec)
2904
2905 let sec_to_hours sec =
2906 let minfactor = 60 in
2907 let hourfactor = 60 * 60 in
2908
2909 let hours = sec / hourfactor in
2910 let mins = (sec mod hourfactor) / minfactor in
2911 let sec = (sec mod 60) in
2912 (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *)
2913 (if hours > 0 then plural hours "hour" ^ " " else "") ^
2914 (if mins > 0 then plural mins "min" ^ " " else "") ^
2915 (spf "%dsec" sec)
2916
2917
2918
2919 let test_date_1 () =
2920 let date = DMY (Day 17, Sep, Year 1991) in
2921 let float, tm = dmy_to_unixtime date in
2922 pr2 (spf "date: %.0f" float);
2923 ()
2924
2925
2926 (* src: ferre in logfun/.../date.ml *)
2927
2928 let day_secs : float = 86400.
2929
2930 let today : unit -> float = fun () -> (Unix.time () )
2931 let yesterday : unit -> float = fun () -> (Unix.time () -. day_secs)
2932 let tomorrow : unit -> float = fun () -> (Unix.time () +. day_secs)
2933
2934 let lastweek : unit -> float = fun () -> (Unix.time () -. (7.0 *. day_secs))
2935 let lastmonth : unit -> float = fun () -> (Unix.time () -. (30.0 *. day_secs))
2936
2937
2938 let week_before : float_time -> float_time = fun d ->
2939 (d -. (7.0 *. day_secs))
2940 let month_before : float_time -> float_time = fun d ->
2941 (d -. (30.0 *. day_secs))
2942
2943 let week_after : float_time -> float_time = fun d ->
2944 (d +. (7.0 *. day_secs))
2945
2946
2947
2948 (*****************************************************************************)
2949 (* Lines/words/strings *)
2950 (*****************************************************************************)
2951
2952 (* now in prelude:
2953 * let (list_of_string: string -> char list) = fun s ->
2954 * (enum 0 ((String.length s) - 1) +> List.map (String.get s))
2955 *)
2956
2957 let _ = example (list_of_string "abcd" =*= ['a';'b';'c';'d'])
2958
2959 (*
2960 let rec (list_of_stream: ('a Stream.t) -> 'a list) =
2961 parser
2962 | [< 'c ; stream >] -> c :: list_of_stream stream
2963 | [<>] -> []
2964
2965 let (list_of_string: string -> char list) =
2966 Stream.of_string $ list_of_stream
2967 *)
2968
2969 (* now in prelude:
2970 * let (lines: string -> string list) = fun s -> ...
2971 *)
2972
2973 let (lines_with_nl: string -> string list) = fun s ->
2974 let rec lines_aux = function
2975 | [] -> []
2976 | [x] -> if x =$= "" then [] else [x ^ "\n"] (* old: [x] *)
2977 | x::xs ->
2978 let e = x ^ "\n" in
2979 e::lines_aux xs
2980 in
2981 (time_func (fun () -> Str.split_delim (Str.regexp "\n") s)) +> lines_aux
2982
2983 (* in fact better make it return always complete lines, simplify *)
2984 (* Str.split, but lines "\n1\n2\n" dont return the \n and forget the first \n => split_delim better than split *)
2985 (* +> List.map (fun s -> s ^ "\n") but add an \n even at the end => lines_aux *)
2986 (* old: slow
2987 let chars = list_of_string s in
2988 chars +> List.fold_left (fun (acc, lines) char ->
2989 let newacc = acc ^ (String.make 1 char) in
2990 if char = '\n'
2991 then ("", newacc::lines)
2992 else (newacc, lines)
2993 ) ("", [])
2994 +> (fun (s, lines) -> List.rev (s::lines))
2995 *)
2996
2997 (* CHECK: unlines (lines x) = x *)
2998 let (unlines: string list -> string) = fun s ->
2999 (String.concat "\n" s) ^ "\n"
3000 let (words: string -> string list) = fun s ->
3001 Str.split (Str.regexp "[ \t()\";]+") s
3002 let (unwords: string list -> string) = fun s ->
3003 String.concat "" s
3004
3005 let (split_space: string -> string list) = fun s ->
3006 Str.split (Str.regexp "[ \t\n]+") s
3007
3008
3009 (* todo opti ? *)
3010 let nblines s =
3011 lines s +> List.length
3012 let _ = example (nblines "" =|= 0)
3013 let _ = example (nblines "toto" =|= 1)
3014 let _ = example (nblines "toto\n" =|= 1)
3015 let _ = example (nblines "toto\ntata" =|= 2)
3016 let _ = example (nblines "toto\ntata\n" =|= 2)
3017
3018 (*****************************************************************************)
3019 (* Process/Files *)
3020 (*****************************************************************************)
3021 let cat_orig file =
3022 let chan = open_in file in
3023 let rec cat_orig_aux () =
3024 try
3025 (* cant do input_line chan::aux() cos ocaml eval from right to left ! *)
3026 let l = input_line chan in
3027 l :: cat_orig_aux ()
3028 with End_of_file -> [] in
3029 cat_orig_aux()
3030
3031 (* tail recursive efficient version *)
3032 let cat file =
3033 let chan = open_in file in
3034 let rec cat_aux acc () =
3035 (* cant do input_line chan::aux() cos ocaml eval from right to left ! *)
3036 let (b, l) = try (true, input_line chan) with End_of_file -> (false, "") in
3037 if b
3038 then cat_aux (l::acc) ()
3039 else acc
3040 in
3041 cat_aux [] () +> List.rev +> (fun x -> close_in chan; x)
3042
3043 let cat_array file =
3044 (""::cat file) +> Array.of_list
3045
3046
3047 let interpolate str =
3048 begin
3049 command2 ("printf \"%s\\n\" " ^ str ^ ">/tmp/caml");
3050 cat "/tmp/caml"
3051 end
3052
3053 (* could do a print_string but printf dont like print_string *)
3054 let echo s = printf "%s" s; flush stdout; s
3055
3056 let usleep s = for i = 1 to s do () done
3057
3058 let sleep_little () =
3059 (*old: *)
3060 Unix.sleep 1
3061 (*ignore(Sys.command ("usleep " ^ !_sleep_time))*)
3062
3063
3064 (* now in prelude:
3065 * let command2 s = ignore(Sys.command s)
3066 *)
3067
3068 let do_in_fork f =
3069 let pid = Unix.fork () in
3070 if pid =|= 0
3071 then
3072 begin
3073 (* Unix.setsid(); *)
3074 Sys.set_signal Sys.sigint (Sys.Signal_handle (fun _ ->
3075 pr2 "being killed";
3076 Unix.kill 0 Sys.sigkill;
3077 ));
3078 f();
3079 exit 0;
3080 end
3081 else pid
3082
3083
3084 let process_output_to_list2 = fun command ->
3085 let chan = Unix.open_process_in command in
3086 let res = ref ([] : string list) in
3087 let rec process_otl_aux () =
3088 let e = input_line chan in
3089 res := e::!res;
3090 process_otl_aux() in
3091 try process_otl_aux ()
3092 with End_of_file ->
3093 let stat = Unix.close_process_in chan in (List.rev !res,stat)
3094 let cmd_to_list command =
3095 let (l,_) = process_output_to_list2 command in l
3096 let process_output_to_list = cmd_to_list
3097 let cmd_to_list_and_status = process_output_to_list2
3098
3099 (* now in prelude:
3100 * let command2 s = ignore(Sys.command s)
3101 *)
3102
3103
3104 let _batch_mode = ref false
3105 let command2_y_or_no cmd =
3106 if !_batch_mode then begin command2 cmd; true end
3107 else begin
3108
3109 pr2 (cmd ^ " [y/n] ?");
3110 match read_line () with
3111 | "y" | "yes" | "Y" -> command2 cmd; true
3112 | "n" | "no" | "N" -> false
3113 | _ -> failwith "answer by yes or no"
3114 end
3115
3116 let command2_y_or_no_exit_if_no cmd =
3117 let res = command2_y_or_no cmd in
3118 if res
3119 then ()
3120 else raise (UnixExit (1))
3121
3122
3123
3124
3125 let mkdir ?(mode=0o770) file =
3126 Unix.mkdir file mode
3127
3128 let read_file_orig file = cat file +> unlines
3129 let read_file file =
3130 let ic = open_in file in
3131 let size = in_channel_length ic in
3132 let buf = String.create size in
3133 really_input ic buf 0 size;
3134 close_in ic;
3135 buf
3136
3137
3138 let write_file ~file s =
3139 let chan = open_out file in
3140 (output_string chan s; close_out chan)
3141
3142 let filesize file =
3143 (Unix.stat file).Unix.st_size
3144
3145 let filemtime file =
3146 (Unix.stat file).Unix.st_mtime
3147
3148 (* opti? use wc -l ? *)
3149 let nblines_file file =
3150 cat file +> List.length
3151
3152 let lfile_exists filename =
3153 try
3154 (match (Unix.lstat filename).Unix.st_kind with
3155 | (Unix.S_REG | Unix.S_LNK) -> true
3156 | _ -> false
3157 )
3158 with Unix.Unix_error (Unix.ENOENT, _, _) -> false
3159
3160 let is_directory file =
3161 (Unix.stat file).Unix.st_kind =*= Unix.S_DIR
3162
3163
3164 (* src: from chailloux et al book *)
3165 let capsule_unix f args =
3166 try (f args)
3167 with Unix.Unix_error (e, fm, argm) ->
3168 log (Printf.sprintf "exn Unix_error: %s %s %s\n" (Unix.error_message e) fm argm)
3169
3170
3171 let (readdir_to_kind_list: string -> Unix.file_kind -> string list) =
3172 fun path kind ->
3173 Sys.readdir path
3174 +> Array.to_list
3175 +> List.filter (fun s ->
3176 try
3177 let stat = Unix.lstat (path ^ "/" ^ s) in
3178 stat.Unix.st_kind =*= kind
3179 with e ->
3180 pr2 ("EXN pb stating file: " ^ s);
3181 false
3182 )
3183
3184 let (readdir_to_dir_list: string -> string list) = fun path ->
3185 readdir_to_kind_list path Unix.S_DIR
3186
3187 let (readdir_to_file_list: string -> string list) = fun path ->
3188 readdir_to_kind_list path Unix.S_REG
3189
3190 let (readdir_to_link_list: string -> string list) = fun path ->
3191 readdir_to_kind_list path Unix.S_LNK
3192
3193
3194 let (readdir_to_dir_size_list: string -> (string * int) list) = fun path ->
3195 Sys.readdir path
3196 +> Array.to_list
3197 +> map_filter (fun s ->
3198 let stat = Unix.lstat (path ^ "/" ^ s) in
3199 if stat.Unix.st_kind =*= Unix.S_DIR
3200 then Some (s, stat.Unix.st_size)
3201 else None
3202 )
3203
3204 (* could be in control section too *)
3205
3206 (* Why a use_cache argument ? because sometimes want disable it but dont
3207 * want put the cache_computation funcall in comment, so just easier to
3208 * pass this extra option.
3209 *)
3210 let cache_computation2 ?(verbose=false) ?(use_cache=true) file ext_cache f =
3211 if not use_cache
3212 then f ()
3213 else begin
3214 if not (Sys.file_exists file)
3215 then failwith ("can't find: " ^ file);
3216 let file_cache = (file ^ ext_cache) in
3217 if Sys.file_exists file_cache &&
3218 filemtime file_cache >= filemtime file
3219 then begin
3220 if verbose then pr2 ("using cache: " ^ file_cache);
3221 get_value file_cache
3222 end
3223 else begin
3224 let res = f () in
3225 write_value res file_cache;
3226 res
3227 end
3228 end
3229 let cache_computation ?verbose ?use_cache a b c =
3230 profile_code "Common.cache_computation" (fun () ->
3231 cache_computation2 ?verbose ?use_cache a b c)
3232
3233
3234 let cache_computation_robust2
3235 file ext_cache
3236 (need_no_changed_files, need_no_changed_variables) ext_depend
3237 f =
3238 if not (Sys.file_exists file)
3239 then failwith ("can't find: " ^ file);
3240
3241 let file_cache = (file ^ ext_cache) in
3242 let dependencies_cache = (file ^ ext_depend) in
3243
3244 let dependencies =
3245 (* could do md5sum too *)
3246 ((file::need_no_changed_files) +> List.map (fun f -> f, filemtime f),
3247 need_no_changed_variables)
3248 in
3249
3250 if Sys.file_exists dependencies_cache &&
3251 get_value dependencies_cache =*= dependencies
3252 then get_value file_cache
3253 else begin
3254 pr2 ("cache computation recompute " ^ file);
3255 let res = f () in
3256 write_value dependencies dependencies_cache;
3257 write_value res file_cache;
3258 res
3259 end
3260
3261 let cache_computation_robust a b c d e =
3262 profile_code "Common.cache_computation_robust" (fun () ->
3263 cache_computation_robust2 a b c d e)
3264
3265
3266
3267
3268 (* dont forget that cmd_to_list call bash and so pattern may contain
3269 * '*' symbols that will be expanded, so can do glob "*.c"
3270 *)
3271 let glob pattern =
3272 cmd_to_list ("ls -1 " ^ pattern)
3273
3274
3275 (* update: have added the -type f, so normally need less the sanity_check_xxx
3276 * function below *)
3277 let files_of_dir_or_files ext xs =
3278 xs +> List.map (fun x ->
3279 if is_directory x
3280 then cmd_to_list ("find " ^ x ^" -noleaf -type f -name \"*." ^ext^"\"")
3281 else [x]
3282 ) +> List.concat
3283
3284
3285 let files_of_dir_or_files_no_vcs ext xs =
3286 xs +> List.map (fun x ->
3287 if is_directory x
3288 then
3289 cmd_to_list
3290 ("find " ^ x ^" -noleaf -type f -name \"*." ^ext^"\"" ^
3291 "| grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/ |grep -v /_darcs/"
3292 )
3293 else [x]
3294 ) +> List.concat
3295
3296
3297 let files_of_dir_or_files_no_vcs_post_filter regex xs =
3298 xs +> List.map (fun x ->
3299 if is_directory x
3300 then
3301 cmd_to_list
3302 ("find " ^ x ^
3303 " -noleaf -type f | grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/"
3304 )
3305 +> List.filter (fun s -> s =~ regex)
3306 else [x]
3307 ) +> List.concat
3308
3309
3310 let sanity_check_files_and_adjust ext files =
3311 let files = files +> List.filter (fun file ->
3312 if not (file =~ (".*\\."^ext))
3313 then begin
3314 pr2 ("warning: seems not a ."^ext^" file");
3315 false
3316 end
3317 else
3318 if is_directory file
3319 then begin
3320 pr2 (spf "warning: %s is a directory" file);
3321 false
3322 end
3323 else true
3324 ) in
3325 files
3326
3327
3328
3329
3330 (* taken from mlfuse, the predecessor of ocamlfuse *)
3331 type rwx = [`R|`W|`X] list
3332 let file_perm_of : u:rwx -> g:rwx -> o:rwx -> Unix.file_perm =
3333 fun ~u ~g ~o ->
3334 let to_oct l =
3335 List.fold_left (fun acc p -> acc lor ((function `R -> 4 | `W -> 2 | `X -> 1) p)) 0 l in
3336 let perm =
3337 ((to_oct u) lsl 6) lor
3338 ((to_oct g) lsl 3) lor
3339 (to_oct o)
3340 in
3341 perm
3342
3343
3344 (* pixel *)
3345 let has_env var =
3346 try
3347 let _ = Sys.getenv var in true
3348 with Not_found -> false
3349
3350 (* emacs/lisp inspiration (eric cooper and yaron minsky use that too) *)
3351 let (with_open_outfile: filename -> (((string -> unit) * out_channel) -> 'a) -> 'a) =
3352 fun file f ->
3353 let chan = open_out file in
3354 let pr s = output_string chan s in
3355 unwind_protect (fun () ->
3356 let res = f (pr, chan) in
3357 close_out chan;
3358 res)
3359 (fun e -> close_out chan)
3360
3361 let (with_open_infile: filename -> ((in_channel) -> 'a) -> 'a) = fun file f ->
3362 let chan = open_in file in
3363 unwind_protect (fun () ->
3364 let res = f chan in
3365 close_in chan;
3366 res)
3367 (fun e -> close_in chan)
3368
3369
3370 let (with_open_outfile_append: filename -> (((string -> unit) * out_channel) -> 'a) -> 'a) =
3371 fun file f ->
3372 let chan = open_out_gen [Open_creat;Open_append] 0o666 file in
3373 let pr s = output_string chan s in
3374 unwind_protect (fun () ->
3375 let res = f (pr, chan) in
3376 close_out chan;
3377 res)
3378 (fun e -> close_out chan)
3379
3380
3381 (* now in prelude:
3382 * exception Timeout
3383 *)
3384
3385 (* it seems that the toplevel block such signals, even with this explicit
3386 * command :(
3387 * let _ = Unix.sigprocmask Unix.SIG_UNBLOCK [Sys.sigalrm]
3388 *)
3389
3390 (* could be in Control section *)
3391
3392 (* subtil: have to make sure that timeout is not intercepted before here, so
3393 * avoid exn handle such as try (...) with _ -> cos timeout will not bubble up
3394 * enough. In such case, add a case before such as
3395 * with Timeout -> raise Timeout | _ -> ...
3396 *
3397 * question: can we have a signal and so exn when in a exn handler ?
3398 *)
3399 let timeout_function timeoutval = fun f ->
3400 try
3401 begin
3402 Sys.set_signal Sys.sigalrm (Sys.Signal_handle (fun _ -> raise Timeout ));
3403 ignore(Unix.alarm timeoutval);
3404 let x = f() in
3405 ignore(Unix.alarm 0);
3406 x
3407 end
3408 with Timeout ->
3409 begin
3410 log "timeout (we abort)";
3411 raise Timeout;
3412 end
3413 | e ->
3414 (* subtil: important to disable the alarm before relaunching the exn,
3415 * otherwise the alarm is still running.
3416 *
3417 * robust?: and if alarm launched after the log (...) ?
3418 * Maybe signals are disabled when process an exception handler ?
3419 *)
3420 begin
3421 ignore(Unix.alarm 0);
3422 (* log ("exn while in transaction (we abort too, even if ...) = " ^
3423 Printexc.to_string e);
3424 *)
3425 log "exn while in timeout_function";
3426 raise e
3427 end
3428
3429 let timeout_function_opt timeoutvalopt f =
3430 match timeoutvalopt with
3431 | None -> f()
3432 | Some x -> timeout_function x f
3433
3434
3435
3436 (* creation of tmp files, a la gcc *)
3437
3438 let _temp_files_created = ref []
3439
3440 (* ex: new_temp_file "cocci" ".c" will give "/tmp/cocci-3252-434465.c" *)
3441 let new_temp_file prefix suffix =
3442 let processid = i_to_s (Unix.getpid ()) in
3443 let tmp_file = Filename.temp_file (prefix ^ "-" ^ processid ^ "-") suffix in
3444 push2 tmp_file _temp_files_created;
3445 tmp_file
3446
3447
3448 let save_tmp_files = ref false
3449 let erase_temp_files () =
3450 if not !save_tmp_files then begin
3451 !_temp_files_created +> List.iter (fun s ->
3452 (* pr2 ("erasing: " ^ s); *)
3453 command2 ("rm -f " ^ s)
3454 );
3455 _temp_files_created := []
3456 end
3457
3458 (* now in prelude: exception UnixExit of int *)
3459 let exn_to_real_unixexit f =
3460 try f()
3461 with UnixExit x -> exit x
3462
3463
3464
3465
3466 let uncat xs file =
3467 with_open_outfile file (fun (pr,_chan) ->
3468 xs +> List.iter (fun s -> pr s; pr "\n");
3469
3470 )
3471
3472
3473
3474
3475
3476
3477 (*****************************************************************************)
3478 (* List *)
3479 (*****************************************************************************)
3480
3481 (* pixel *)
3482 let uncons l = (List.hd l, List.tl l)
3483
3484 (* pixel *)
3485 let safe_tl l = try List.tl l with _ -> []
3486
3487 let push l v =
3488 l := v :: !l
3489
3490 let rec zip xs ys =
3491 match (xs,ys) with
3492 | ([],[]) -> []
3493 | ([],_) -> failwith "zip: not same length"
3494 | (_,[]) -> failwith "zip: not same length"
3495 | (x::xs,y::ys) -> (x,y)::zip xs ys
3496
3497 let rec zip_safe xs ys =
3498 match (xs,ys) with
3499 | ([],_) -> []
3500 | (_,[]) -> []
3501 | (x::xs,y::ys) -> (x,y)::zip_safe xs ys
3502
3503 let rec unzip zs =
3504 List.fold_right (fun e (xs, ys) ->
3505 (fst e::xs), (snd e::ys)) zs ([],[])
3506
3507
3508 let map_withkeep f xs =
3509 xs +> List.map (fun x -> f x, x)
3510
3511 (* now in prelude
3512 * let rec take n xs =
3513 * match (n,xs) with
3514 * | (0,_) -> []
3515 * | (_,[]) -> failwith "take: not enough"
3516 * | (n,x::xs) -> x::take (n-1) xs
3517 *)
3518
3519 let rec take_safe n xs =
3520 match (n,xs) with
3521 | (0,_) -> []
3522 | (_,[]) -> []
3523 | (n,x::xs) -> x::take_safe (n-1) xs
3524
3525 let rec take_until p = function
3526 | [] -> []
3527 | x::xs -> if p x then [] else x::(take_until p xs)
3528
3529 let take_while p = take_until (p $ not)
3530
3531
3532 (* now in prelude: let rec drop n xs = ... *)
3533 let _ = example (drop 3 [1;2;3;4] =*= [4])
3534
3535 let rec drop_while p = function
3536 | [] -> []
3537 | x::xs -> if p x then drop_while p xs else x::xs
3538
3539
3540 let rec drop_until p xs =
3541 drop_while (fun x -> not (p x)) xs
3542 let _ = example (drop_until (fun x -> x =|= 3) [1;2;3;4;5] =*= [3;4;5])
3543
3544
3545 let span p xs = (take_while p xs, drop_while p xs)
3546
3547
3548 let rec (span: ('a -> bool) -> 'a list -> 'a list * 'a list) =
3549 fun p -> function
3550 | [] -> ([], [])
3551 | x::xs ->
3552 if p x then
3553 let (l1, l2) = span p xs in
3554 (x::l1, l2)
3555 else ([], x::xs)
3556 let _ = example ((span (fun x -> x <= 3) [1;2;3;4;1;2] =*= ([1;2;3],[4;1;2])))
3557
3558 let rec groupBy eq l =
3559 match l with
3560 | [] -> []
3561 | x::xs ->
3562 let (xs1,xs2) = List.partition (fun x' -> eq x x') xs in
3563 (x::xs1)::(groupBy eq xs2)
3564
3565 let rec group_by_mapped_key fkey l =
3566 match l with
3567 | [] -> []
3568 | x::xs ->
3569 let k = fkey x in
3570 let (xs1,xs2) = List.partition (fun x' -> let k2 = fkey x' in k=*=k2) xs
3571 in
3572 (k, (x::xs1))::(group_by_mapped_key fkey xs2)
3573
3574
3575
3576
3577 let (exclude_but_keep_attached: ('a -> bool) -> 'a list -> ('a * 'a list) list)=
3578 fun f xs ->
3579 let rec aux_filter acc = function
3580 | [] -> [] (* drop what was accumulated because nothing to attach to *)
3581 | x::xs ->
3582 if f x
3583 then aux_filter (x::acc) xs
3584 else (x, List.rev acc)::aux_filter [] xs
3585 in
3586 aux_filter [] xs
3587 let _ = example
3588 (exclude_but_keep_attached (fun x -> x =|= 3) [3;3;1;3;2;3;3;3] =*=
3589 [(1,[3;3]);(2,[3])])
3590
3591 let (group_by_post: ('a -> bool) -> 'a list -> ('a list * 'a) list * 'a list)=
3592 fun f xs ->
3593 let rec aux_filter grouped_acc acc = function
3594 | [] ->
3595 List.rev grouped_acc, List.rev acc
3596 | x::xs ->
3597 if f x
3598 then
3599 aux_filter ((List.rev acc,x)::grouped_acc) [] xs
3600 else
3601 aux_filter grouped_acc (x::acc) xs
3602 in
3603 aux_filter [] [] xs
3604
3605 let _ = example
3606 (group_by_post (fun x -> x =|= 3) [1;1;3;2;3;4;5;3;6;6;6] =*=
3607 ([([1;1],3);([2],3);[4;5],3], [6;6;6]))
3608
3609 let (group_by_pre: ('a -> bool) -> 'a list -> 'a list * ('a * 'a list) list)=
3610 fun f xs ->
3611 let xs' = List.rev xs in
3612 let (ys, unclassified) = group_by_post f xs' in
3613 List.rev unclassified,
3614 ys +> List.rev +> List.map (fun (xs, x) -> x, List.rev xs )
3615
3616 let _ = example
3617 (group_by_pre (fun x -> x =|= 3) [1;1;3;2;3;4;5;3;6;6;6] =*=
3618 ([1;1], [(3,[2]); (3,[4;5]); (3,[6;6;6])]))
3619
3620
3621 let rec (split_when: ('a -> bool) -> 'a list -> 'a list * 'a * 'a list) =
3622 fun p -> function
3623 | [] -> raise Not_found
3624 | x::xs ->
3625 if p x then
3626 [], x, xs
3627 else
3628 let (l1, a, l2) = split_when p xs in
3629 (x::l1, a, l2)
3630 let _ = example (split_when (fun x -> x =|= 3)
3631 [1;2;3;4;1;2] =*= ([1;2],3,[4;1;2]))
3632
3633
3634 (* not so easy to come up with ... used in aComment for split_paragraph *)
3635 let rec split_gen_when_aux f acc xs =
3636 match xs with
3637 | [] ->
3638 if null acc
3639 then []
3640 else [List.rev acc]
3641 | (x::xs) ->
3642 (match f (x::xs) with
3643 | None ->
3644 split_gen_when_aux f (x::acc) xs
3645 | Some (rest) ->
3646 let before = List.rev acc in
3647 if null before
3648 then split_gen_when_aux f [] rest
3649 else before::split_gen_when_aux f [] rest
3650 )
3651 (* could avoid introduce extra aux function by using ?(acc = []) *)
3652 let split_gen_when f xs =
3653 split_gen_when_aux f [] xs
3654
3655
3656
3657 (* generate exception (Failure "tl") if there is no element satisfying p *)
3658 let rec (skip_until: ('a list -> bool) -> 'a list -> 'a list) = fun p xs ->
3659 if p xs then xs else skip_until p (List.tl xs)
3660 let _ = example
3661 (skip_until (function 1::2::xs -> true | _ -> false)
3662 [1;3;4;1;2;4;5] =*= [1;2;4;5])
3663
3664 let rec skipfirst e = function
3665 | [] -> []
3666 | e'::l when e =*= e' -> skipfirst e l
3667 | l -> l
3668
3669
3670 (* now in prelude:
3671 * let rec enum x n = ...
3672 *)
3673
3674
3675 let index_list xs =
3676 if null xs then [] (* enum 0 (-1) generate an exception *)
3677 else zip xs (enum 0 ((List.length xs) -1))
3678
3679 let index_list_and_total xs =
3680 let total = List.length xs in
3681 if null xs then [] (* enum 0 (-1) generate an exception *)
3682 else zip xs (enum 0 ((List.length xs) -1))
3683 +> List.map (fun (a,b) -> (a,b,total))
3684
3685 let index_list_1 xs =
3686 xs +> index_list +> List.map (fun (x,i) -> x, i+1)
3687
3688 let or_list = List.fold_left (||) false
3689 let and_list = List.fold_left (&&) true
3690
3691 let avg_list xs =
3692 let sum = sum_int xs in
3693 (float_of_int sum) /. (float_of_int (List.length xs))
3694
3695 let snoc x xs = xs @ [x]
3696 let cons x xs = x::xs
3697
3698 let head_middle_tail xs =
3699 match xs with
3700 | x::y::xs ->
3701 let head = x in
3702 let reversed = List.rev (y::xs) in
3703 let tail = List.hd reversed in
3704 let middle = List.rev (List.tl reversed) in
3705 head, middle, tail
3706 | _ -> failwith "head_middle_tail, too small list"
3707
3708 let _ = assert_equal (head_middle_tail [1;2;3]) (1, [2], 3)
3709 let _ = assert_equal (head_middle_tail [1;3]) (1, [], 3)
3710
3711 (* now in prelude
3712 * let (++) = (@)
3713 *)
3714
3715 (* let (++) = (@), could do that, but if load many times the common, then pb *)
3716 (* let (++) l1 l2 = List.fold_right (fun x acc -> x::acc) l1 l2 *)
3717
3718 let remove x xs =
3719 let newxs = List.filter (fun y -> y <> x) xs in
3720 assert (List.length newxs =|= List.length xs - 1);
3721 newxs
3722
3723
3724 let exclude p xs =
3725 List.filter (fun x -> not (p x)) xs
3726
3727 (* now in prelude
3728 *)
3729
3730 let fold_k f lastk acc xs =
3731 let rec fold_k_aux acc = function
3732 | [] -> lastk acc
3733 | x::xs ->
3734 f acc x (fun acc -> fold_k_aux acc xs)
3735 in
3736 fold_k_aux acc xs
3737
3738
3739 let rec list_init = function
3740 | [] -> raise Not_found
3741 | [x] -> []
3742 | x::y::xs -> x::(list_init (y::xs))
3743
3744 let rec list_last = function
3745 | [] -> raise Not_found
3746 | [x] -> x
3747 | x::y::xs -> list_last (y::xs)
3748
3749 (* pixel *)
3750 (* now in prelude
3751 * let last_n n l = List.rev (take n (List.rev l))
3752 * let last l = List.hd (last_n 1 l)
3753 *)
3754
3755 let rec join_gen a = function
3756 | [] -> []
3757 | [x] -> [x]
3758 | x::xs -> x::a::(join_gen a xs)
3759
3760
3761 (* todo: foldl, foldr (a more consistent foldr) *)
3762
3763 (* start pixel *)
3764 let iter_index f l =
3765 let rec iter_ n = function
3766 | [] -> ()
3767 | e::l -> f e n ; iter_ (n+1) l
3768 in iter_ 0 l
3769
3770 let map_index f l =
3771 let rec map_ n = function
3772 | [] -> []
3773 | e::l -> f e n :: map_ (n+1) l
3774 in map_ 0 l
3775
3776
3777 (* pixel *)
3778 let filter_index f l =
3779 let rec filt i = function
3780 | [] -> []
3781 | e::l -> if f i e then e :: filt (i+1) l else filt (i+1) l
3782 in
3783 filt 0 l
3784
3785 (* pixel *)
3786 let do_withenv doit f env l =
3787 let r_env = ref env in
3788 let l' = doit (fun e ->
3789 let e', env' = f !r_env e in
3790 r_env := env' ; e'
3791 ) l in
3792 l', !r_env
3793
3794 (* now in prelude:
3795 * let fold_left_with_index f acc = ...
3796 *)
3797
3798 let map_withenv f env e = do_withenv List.map f env e
3799
3800 let rec collect_accu f accu = function
3801 | [] -> accu
3802 | e::l -> collect_accu f (List.rev_append (f e) accu) l
3803
3804 let collect f l = List.rev (collect_accu f [] l)
3805
3806 (* cf also List.partition *)
3807
3808 let rec fpartition p l =
3809 let rec part yes no = function
3810 | [] -> (List.rev yes, List.rev no)
3811 | x :: l ->
3812 (match p x with
3813 | None -> part yes (x :: no) l
3814 | Some v -> part (v :: yes) no l) in
3815 part [] [] l
3816
3817 (* end pixel *)
3818
3819 let rec removelast = function
3820 | [] -> failwith "removelast"
3821 | [_] -> []
3822 | e::l -> e :: removelast l
3823
3824 let remove x = List.filter (fun y -> y != x)
3825 let empty list = null list
3826
3827
3828 let rec inits = function
3829 | [] -> [[]]
3830 | e::l -> [] :: List.map (fun l -> e::l) (inits l)
3831
3832 let rec tails = function
3833 | [] -> [[]]
3834 | (_::xs) as xxs -> xxs :: tails xs
3835
3836
3837 let reverse = List.rev
3838 let rev = List.rev
3839
3840 let nth = List.nth
3841 let fold_left = List.fold_left
3842 let rev_map = List.rev_map
3843
3844 (* pixel *)
3845 let rec fold_right1 f = function
3846 | [] -> failwith "fold_right1"
3847 | [e] -> e
3848 | e::l -> f e (fold_right1 f l)
3849
3850 let maximum l = foldl1 max l
3851 let minimum l = foldl1 min l
3852
3853 (* do a map tail recursive, and result is reversed, it is a tail recursive map => efficient *)
3854 let map_eff_rev = fun f l ->
3855 let rec map_eff_aux acc =
3856 function
3857 | [] -> acc
3858 | x::xs -> map_eff_aux ((f x)::acc) xs
3859 in
3860 map_eff_aux [] l
3861
3862 let acc_map f l =
3863 let rec loop acc = function
3864 [] -> List.rev acc
3865 | x::xs -> loop ((f x)::acc) xs in
3866 loop [] l
3867
3868
3869 let rec (generate: int -> 'a -> 'a list) = fun i el ->
3870 if i =|= 0 then []
3871 else el::(generate (i-1) el)
3872
3873 let rec uniq = function
3874 | [] -> []
3875 | e::l -> if List.mem e l then uniq l else e :: uniq l
3876
3877 let has_no_duplicate xs =
3878 List.length xs =|= List.length (uniq xs)
3879 let is_set_as_list = has_no_duplicate
3880
3881
3882 let rec get_duplicates xs =
3883 match xs with
3884 | [] -> []
3885 | x::xs ->
3886 if List.mem x xs
3887 then x::get_duplicates xs (* todo? could x from xs to avoid double dups?*)
3888 else get_duplicates xs
3889
3890 let rec all_assoc e = function
3891 | [] -> []
3892 | (e',v) :: l when e=*=e' -> v :: all_assoc e l
3893 | _ :: l -> all_assoc e l
3894
3895 let prepare_want_all_assoc l =
3896 List.map (fun n -> n, uniq (all_assoc n l)) (uniq (List.map fst l))
3897
3898 let rotate list = List.tl list ++ [(List.hd list)]
3899
3900 let or_list = List.fold_left (||) false
3901 let and_list = List.fold_left (&&) true
3902
3903 let rec (return_when: ('a -> 'b option) -> 'a list -> 'b) = fun p -> function
3904 | [] -> raise Not_found
3905 | x::xs -> (match p x with None -> return_when p xs | Some b -> b)
3906
3907 let rec splitAt n xs =
3908 if n =|= 0 then ([],xs)
3909 else
3910 (match xs with
3911 | [] -> ([],[])
3912 | (x::xs) -> let (a,b) = splitAt (n-1) xs in (x::a, b)
3913 )
3914
3915 let pack n xs =
3916 let rec pack_aux l i = function
3917 | [] -> failwith "not on a boundary"
3918 | [x] -> if i =|= n then [l++[x]] else failwith "not on a boundary"
3919 | x::xs ->
3920 if i =|= n
3921 then (l++[x])::(pack_aux [] 1 xs)
3922 else pack_aux (l++[x]) (i+1) xs
3923 in
3924 pack_aux [] 1 xs
3925
3926 let min_with f = function
3927 | [] -> raise Not_found
3928 | e :: l ->
3929 let rec min_with_ min_val min_elt = function
3930 | [] -> min_elt
3931 | e::l ->
3932 let val_ = f e in
3933 if val_ < min_val
3934 then min_with_ val_ e l
3935 else min_with_ min_val min_elt l
3936 in min_with_ (f e) e l
3937
3938 let two_mins_with f = function
3939 | e1 :: e2 :: l ->
3940 let rec min_with_ min_val min_elt min_val2 min_elt2 = function
3941 | [] -> min_elt, min_elt2
3942 | e::l ->
3943 let val_ = f e in
3944 if val_ < min_val2
3945 then
3946 if val_ < min_val
3947 then min_with_ val_ e min_val min_elt l
3948 else min_with_ min_val min_elt val_ e l
3949 else min_with_ min_val min_elt min_val2 min_elt2 l
3950 in
3951 let v1 = f e1 in
3952 let v2 = f e2 in
3953 if v1 < v2 then min_with_ v1 e1 v2 e2 l else min_with_ v2 e2 v1 e1 l
3954 | _ -> raise Not_found
3955
3956 let grep_with_previous f = function
3957 | [] -> []
3958 | e::l ->
3959 let rec grep_with_previous_ previous = function
3960 | [] -> []
3961 | e::l -> if f previous e then e :: grep_with_previous_ e l else grep_with_previous_ previous l
3962 in e :: grep_with_previous_ e l
3963
3964 let iter_with_previous f = function
3965 | [] -> ()
3966 | e::l ->
3967 let rec iter_with_previous_ previous = function
3968 | [] -> ()
3969 | e::l -> f previous e ; iter_with_previous_ e l
3970 in iter_with_previous_ e l
3971
3972
3973 let iter_with_before_after f xs =
3974 let rec aux before_rev after =
3975 match after with
3976 | [] -> ()
3977 | x::xs ->
3978 f before_rev x xs;
3979 aux (x::before_rev) xs
3980 in
3981 aux [] xs
3982
3983
3984
3985 (* kind of cartesian product of x*x *)
3986 let rec (get_pair: ('a list) -> (('a * 'a) list)) = function
3987 | [] -> []
3988 | x::xs -> (List.map (fun y -> (x,y)) xs) ++ (get_pair xs)
3989
3990
3991 (* retourne le rang dans une liste d'un element *)
3992 let rang elem liste =
3993 let rec rang_rec elem accu = function
3994 | [] -> raise Not_found
3995 | a::l -> if a =*= elem then accu
3996 else rang_rec elem (accu+1) l in
3997 rang_rec elem 1 liste
3998
3999 (* retourne vrai si une liste contient des doubles *)
4000 let rec doublon = function
4001 | [] -> false
4002 | a::l -> if List.mem a l then true
4003 else doublon l
4004
4005 let rec (insert_in: 'a -> 'a list -> 'a list list) = fun x -> function
4006 | [] -> [[x]]
4007 | y::ys -> (x::y::ys) :: (List.map (fun xs -> y::xs) (insert_in x ys))
4008 (* insert_in 3 [1;2] = [[3; 1; 2]; [1; 3; 2]; [1; 2; 3]] *)
4009
4010 let rec (permutation: 'a list -> 'a list list) = function
4011 | [] -> []
4012 | [x] -> [[x]]
4013 | x::xs -> List.flatten (List.map (insert_in x) (permutation xs))
4014 (* permutation [1;2;3] =
4015 * [[1; 2; 3]; [2; 1; 3]; [2; 3; 1]; [1; 3; 2]; [3; 1; 2]; [3; 2; 1]]
4016 *)
4017
4018
4019 let rec remove_elem_pos pos xs =
4020 match (pos, xs) with
4021 | _, [] -> failwith "remove_elem_pos"
4022 | 0, x::xs -> xs
4023 | n, x::xs -> x::(remove_elem_pos (n-1) xs)
4024
4025 let rec insert_elem_pos (e, pos) xs =
4026 match (pos, xs) with
4027 | 0, xs -> e::xs
4028 | n, x::xs -> x::(insert_elem_pos (e, (n-1)) xs)
4029 | n, [] -> failwith "insert_elem_pos"
4030
4031 let rec uncons_permut xs =
4032 let indexed = index_list xs in
4033 indexed +> List.map (fun (x, pos) -> (x, pos), remove_elem_pos pos xs)
4034 let _ =
4035 example
4036 (uncons_permut ['a';'b';'c'] =*=
4037 [('a', 0), ['b';'c'];
4038 ('b', 1), ['a';'c'];
4039 ('c', 2), ['a';'b']
4040 ])
4041
4042 let rec uncons_permut_lazy xs =
4043 let indexed = index_list xs in
4044 indexed +> List.map (fun (x, pos) ->
4045 (x, pos),
4046 lazy (remove_elem_pos pos xs)
4047 )
4048
4049
4050
4051
4052 (* pixel *)
4053 let rec map_flatten f l =
4054 let rec map_flatten_aux accu = function
4055 | [] -> accu
4056 | e :: l -> map_flatten_aux (List.rev (f e) ++ accu) l
4057 in List.rev (map_flatten_aux [] l)
4058
4059
4060 let rec repeat e n =
4061 let rec repeat_aux acc = function
4062 | 0 -> acc
4063 | n when n < 0 -> failwith "repeat"
4064 | n -> repeat_aux (e::acc) (n-1) in
4065 repeat_aux [] n
4066
4067 let rec map2 f = function
4068 | [] -> []
4069 | x::xs -> let r = f x in r::map2 f xs
4070
4071 let rec map3 f l =
4072 let rec map3_aux acc = function
4073 | [] -> acc
4074 | x::xs -> map3_aux (f x::acc) xs in
4075 map3_aux [] l
4076
4077 (*
4078 let tails2 xs = map rev (inits (rev xs))
4079 let res = tails2 [1;2;3;4]
4080 let res = tails [1;2;3;4]
4081 let id x = x
4082 *)
4083
4084 let pack_sorted same xs =
4085 let rec pack_s_aux acc xs =
4086 match (acc,xs) with
4087 | ((cur,rest),[]) -> cur::rest
4088 | ((cur,rest), y::ys) ->
4089 if same (List.hd cur) y then pack_s_aux (y::cur, rest) ys
4090 else pack_s_aux ([y], cur::rest) ys
4091 in pack_s_aux ([List.hd xs],[]) (List.tl xs) +> List.rev
4092 let test = pack_sorted (=*=) [1;1;1;2;2;3;4]
4093
4094
4095 let rec keep_best f =
4096 let rec partition e = function
4097 | [] -> e, []
4098 | e' :: l ->
4099 match f(e,e') with
4100 | None -> let (e'', l') = partition e l in e'', e' :: l'
4101 | Some e'' -> partition e'' l
4102 in function
4103 | [] -> []
4104 | e::l ->
4105 let (e', l') = partition e l in
4106 e' :: keep_best f l'
4107
4108 let rec sorted_keep_best f = function
4109 | [] -> []
4110 | [a] -> [a]
4111 | a :: b :: l ->
4112 match f a b with
4113 | None -> a :: sorted_keep_best f (b :: l)
4114 | Some e -> sorted_keep_best f (e :: l)
4115
4116
4117
4118 let (cartesian_product: 'a list -> 'b list -> ('a * 'b) list) = fun xs ys ->
4119 xs +> List.map (fun x -> ys +> List.map (fun y -> (x,y)))
4120 +> List.flatten
4121
4122 let _ = assert_equal
4123 (cartesian_product [1;2] ["3";"4";"5"])
4124 [1,"3";1,"4";1,"5"; 2,"3";2,"4";2,"5"]
4125
4126 let sort_prof a b =
4127 profile_code "Common.sort_by_xxx" (fun () -> List.sort a b)
4128
4129 let sort_by_val_highfirst xs =
4130 sort_prof (fun (k1,v1) (k2,v2) -> compare v2 v1) xs
4131 let sort_by_val_lowfirst xs =
4132 sort_prof (fun (k1,v1) (k2,v2) -> compare v1 v2) xs
4133
4134 let sort_by_key_highfirst xs =
4135 sort_prof (fun (k1,v1) (k2,v2) -> compare k2 k1) xs
4136 let sort_by_key_lowfirst xs =
4137 sort_prof (fun (k1,v1) (k2,v2) -> compare k1 k2) xs
4138
4139 let _ = example (sort_by_key_lowfirst [4, (); 7,()] =*= [4,(); 7,()])
4140 let _ = example (sort_by_key_highfirst [4,(); 7,()] =*= [7,(); 4,()])
4141
4142
4143 let sortgen_by_key_highfirst xs =
4144 sort_prof (fun (k1,v1) (k2,v2) -> compare k2 k1) xs
4145 let sortgen_by_key_lowfirst xs =
4146 sort_prof (fun (k1,v1) (k2,v2) -> compare k1 k2) xs
4147
4148 (*----------------------------------*)
4149
4150 (* sur surEnsemble [p1;p2] [[p1;p2;p3] [p1;p2] ....] -> [[p1;p2;p3] ... *)
4151 (* mais pas p2;p3 *)
4152 (* (aop) *)
4153 let surEnsemble liste_el liste_liste_el =
4154 List.filter
4155 (function liste_elbis ->
4156 List.for_all (function el -> List.mem el liste_elbis) liste_el
4157 ) liste_liste_el;;
4158
4159
4160
4161 (*----------------------------------*)
4162 (* combinaison/product/.... (aop) *)
4163 (* 123 -> 123 12 13 23 1 2 3 *)
4164 let rec realCombinaison = function
4165 | [] -> []
4166 | [a] -> [[a]]
4167 | a::l ->
4168 let res = realCombinaison l in
4169 let res2 = List.map (function x -> a::x) res in
4170 res2 ++ res ++ [[a]]
4171
4172 (* genere toutes les combinaisons possible de paire *)
4173 (* par exemple combinaison [1;2;4] -> [1, 2; 1, 4; 2, 4] *)
4174 let rec combinaison = function
4175 | [] -> []
4176 | [a] -> []
4177 | [a;b] -> [(a, b)]
4178 | a::b::l -> (List.map (function elem -> (a, elem)) (b::l)) ++
4179 (combinaison (b::l))
4180
4181 (*----------------------------------*)
4182
4183 (* list of list(aop) *)
4184 (* insere elem dans la liste de liste (si elem est deja present dans une de *)
4185 (* ces listes, on ne fait rien *)
4186 let rec insere elem = function
4187 | [] -> [[elem]]
4188 | a::l ->
4189 if (List.mem elem a) then a::l
4190 else a::(insere elem l)
4191
4192 let rec insereListeContenant lis el = function
4193 | [] -> [el::lis]
4194 | a::l ->
4195 if List.mem el a then
4196 (List.append lis a)::l
4197 else a::(insereListeContenant lis el l)
4198
4199 (* fusionne les listes contenant et1 et et2 dans la liste de liste*)
4200 let rec fusionneListeContenant (et1, et2) = function
4201 | [] -> [[et1; et2]]
4202 | a::l ->
4203 (* si les deux sont deja dedans alors rien faire *)
4204 if List.mem et1 a then
4205 if List.mem et2 a then a::l
4206 else
4207 insereListeContenant a et2 l
4208 else if List.mem et2 a then
4209 insereListeContenant a et1 l
4210 else a::(fusionneListeContenant (et1, et2) l)
4211
4212 (*****************************************************************************)
4213 (* Arrays *)
4214 (*****************************************************************************)
4215
4216 (* do bound checking ? *)
4217 let array_find_index f a =
4218 let rec array_find_index_ i =
4219 if f i then i else array_find_index_ (i+1)
4220 in
4221 try array_find_index_ 0 with _ -> raise Not_found
4222
4223 let array_find_index_via_elem f a =
4224 let rec array_find_index_ i =
4225 if f a.(i) then i else array_find_index_ (i+1)
4226 in
4227 try array_find_index_ 0 with _ -> raise Not_found
4228
4229
4230
4231 type idx = Idx of int
4232 let next_idx (Idx i) = (Idx (i+1))
4233 let int_of_idx (Idx i) = i
4234
4235 let array_find_index_typed f a =
4236 let rec array_find_index_ i =
4237 if f i then i else array_find_index_ (next_idx i)
4238 in
4239 try array_find_index_ (Idx 0) with _ -> raise Not_found
4240
4241
4242
4243 (*****************************************************************************)
4244 (* Matrix *)
4245 (*****************************************************************************)
4246
4247 type 'a matrix = 'a array array
4248
4249 let map_matrix f mat =
4250 mat +> Array.map (fun arr -> arr +> Array.map f)
4251
4252 let (make_matrix_init:
4253 nrow:int -> ncolumn:int -> (int -> int -> 'a) -> 'a matrix) =
4254 fun ~nrow ~ncolumn f ->
4255 Array.init nrow (fun i ->
4256 Array.init ncolumn (fun j ->
4257 f i j
4258 )
4259 )
4260
4261 let iter_matrix f m =
4262 Array.iteri (fun i e ->
4263 Array.iteri (fun j x ->
4264 f i j x
4265 ) e
4266 ) m
4267
4268 let nb_rows_matrix m =
4269 Array.length m
4270
4271 let nb_columns_matrix m =
4272 assert(Array.length m > 0);
4273 Array.length m.(0)
4274
4275 (* check all nested arrays have the same size *)
4276 let invariant_matrix m =
4277 raise Todo
4278
4279 let (rows_of_matrix: 'a matrix -> 'a list list) = fun m ->
4280 Array.to_list m +> List.map Array.to_list
4281
4282 let (columns_of_matrix: 'a matrix -> 'a list list) = fun m ->
4283 let nbcols = nb_columns_matrix m in
4284 let nbrows = nb_rows_matrix m in
4285 (enum 0 (nbcols -1)) +> List.map (fun j ->
4286 (enum 0 (nbrows -1)) +> List.map (fun i ->
4287 m.(i).(j)
4288 ))
4289
4290
4291 let all_elems_matrix_by_row m =
4292 rows_of_matrix m +> List.flatten
4293
4294
4295 let ex_matrix1 =
4296 [|
4297 [|0;1;2|];
4298 [|3;4;5|];
4299 [|6;7;8|];
4300 |]
4301 let ex_rows1 =
4302 [
4303 [0;1;2];
4304 [3;4;5];
4305 [6;7;8];
4306 ]
4307 let ex_columns1 =
4308 [
4309 [0;3;6];
4310 [1;4;7];
4311 [2;5;8];
4312 ]
4313 let _ = example (rows_of_matrix ex_matrix1 =*= ex_rows1)
4314 let _ = example (columns_of_matrix ex_matrix1 =*= ex_columns1)
4315
4316
4317 (*****************************************************************************)
4318 (* Fast array *)
4319 (*****************************************************************************)
4320 (*
4321 module B_Array = Bigarray.Array2
4322 *)
4323
4324 (*
4325 open B_Array
4326 open Bigarray
4327 *)
4328
4329
4330 (* for the string_of auto generation of camlp4
4331 val b_array_string_of_t : 'a -> 'b -> string
4332 val bigarray_string_of_int16_unsigned_elt : 'a -> string
4333 val bigarray_string_of_c_layout : 'a -> string
4334 let b_array_string_of_t f a = "<>"
4335 let bigarray_string_of_int16_unsigned_elt a = "<>"
4336 let bigarray_string_of_c_layout a = "<>"
4337
4338 *)
4339
4340
4341 (*****************************************************************************)
4342 (* Set. Have a look too at set*.mli *)
4343 (*****************************************************************************)
4344 type 'a set = 'a list
4345 (* with sexp *)
4346
4347 let (empty_set: 'a set) = []
4348 let (insert_set: 'a -> 'a set -> 'a set) = fun x xs ->
4349 if List.mem x xs
4350 then (* let _ = print_string "warning insert: already exist" in *)
4351 xs
4352 else x::xs
4353
4354 let is_set xs =
4355 has_no_duplicate xs
4356
4357 let (single_set: 'a -> 'a set) = fun x -> insert_set x empty_set
4358 let (set: 'a list -> 'a set) = fun xs ->
4359 xs +> List.fold_left (flip insert_set) empty_set
4360
4361 let (exists_set: ('a -> bool) -> 'a set -> bool) = List.exists
4362 let (forall_set: ('a -> bool) -> 'a set -> bool) = List.for_all
4363 let (filter_set: ('a -> bool) -> 'a set -> 'a set) = List.filter
4364 let (fold_set: ('a -> 'b -> 'a) -> 'a -> 'b set -> 'a) = List.fold_left
4365 let (map_set: ('a -> 'b) -> 'a set -> 'b set) = List.map
4366 let (member_set: 'a -> 'a set -> bool) = List.mem
4367
4368 let find_set = List.find
4369 let sort_set = List.sort
4370 let iter_set = List.iter
4371
4372 let (top_set: 'a set -> 'a) = List.hd
4373
4374 let (inter_set: 'a set -> 'a set -> 'a set) = fun s1 s2 ->
4375 s1 +> fold_set (fun acc x -> if member_set x s2 then insert_set x acc else acc) empty_set
4376 let (union_set: 'a set -> 'a set -> 'a set) = fun s1 s2 ->
4377 s2 +> fold_set (fun acc x -> if member_set x s1 then acc else insert_set x acc) s1
4378 let (minus_set: 'a set -> 'a set -> 'a set) = fun s1 s2 ->
4379 s1 +> filter_set (fun x -> not (member_set x s2))
4380
4381
4382 let union_all l = List.fold_left union_set [] l
4383
4384 let big_union_set f xs = xs +> map_set f +> fold_set union_set empty_set
4385
4386 let (card_set: 'a set -> int) = List.length
4387
4388 let (include_set: 'a set -> 'a set -> bool) = fun s1 s2 ->
4389 (s1 +> forall_set (fun p -> member_set p s2))
4390
4391 let equal_set s1 s2 = include_set s1 s2 && include_set s2 s1
4392
4393 let (include_set_strict: 'a set -> 'a set -> bool) = fun s1 s2 ->
4394 (card_set s1 < card_set s2) && (include_set s1 s2)
4395
4396 let ($*$) = inter_set
4397 let ($+$) = union_set
4398 let ($-$) = minus_set
4399 let ($?$) a b = profile_code "$?$" (fun () -> member_set a b)
4400 let ($<$) = include_set_strict
4401 let ($<=$) = include_set
4402 let ($=$) = equal_set
4403
4404 (* as $+$ but do not check for memberness, allow to have set of func *)
4405 let ($@$) = fun a b -> a @ b
4406
4407 let rec nub = function
4408 [] -> []
4409 | x::xs -> if List.mem x xs then nub xs else x::(nub xs)
4410
4411 (*****************************************************************************)
4412 (* Set as normal list *)
4413 (*****************************************************************************)
4414 (*
4415 let (union: 'a list -> 'a list -> 'a list) = fun l1 l2 ->
4416 List.fold_left (fun acc x -> if List.mem x l1 then acc else x::acc) l1 l2
4417
4418 let insert_normal x xs = union xs [x]
4419
4420 (* retourne lis1 - lis2 *)
4421 let minus l1 l2 = List.filter (fun x -> not (List.mem x l2)) l1
4422
4423 let inter l1 l2 = List.fold_left (fun acc x -> if List.mem x l2 then x::acc else acc) [] l1
4424
4425 let union_list = List.fold_left union []
4426
4427 let uniq lis =
4428 List.fold_left (function acc -> function el -> union [el] acc) [] lis
4429
4430 (* pixel *)
4431 let rec non_uniq = function
4432 | [] -> []
4433 | e::l -> if mem e l then e :: non_uniq l else non_uniq l
4434
4435 let rec inclu lis1 lis2 =
4436 List.for_all (function el -> List.mem el lis2) lis1
4437
4438 let equivalent lis1 lis2 =
4439 (inclu lis1 lis2) && (inclu lis2 lis1)
4440
4441 *)
4442
4443
4444 (*****************************************************************************)
4445 (* Set as sorted list *)
4446 (*****************************************************************************)
4447 (* liste trie, cos we need to do intersection, and insertion (it is a set
4448 cos when introduce has, if we create a new has => must do a recurse_rep
4449 and another categ can have to this has => must do an union
4450 *)
4451 (*
4452 let rec insert x = function
4453 | [] -> [x]
4454 | y::ys ->
4455 if x = y then y::ys
4456 else (if x < y then x::y::ys else y::(insert x ys))
4457
4458 (* same, suppose sorted list *)
4459 let rec intersect x y =
4460 match(x,y) with
4461 | [], y -> []
4462 | x, [] -> []
4463 | x::xs, y::ys ->
4464 if x = y then x::(intersect xs ys)
4465 else
4466 (if x < y then intersect xs (y::ys)
4467 else intersect (x::xs) ys
4468 )
4469 (* intersect [1;3;7] [2;3;4;7;8];; *)
4470 *)
4471
4472 (*****************************************************************************)
4473 (* Assoc *)
4474 (*****************************************************************************)
4475 type ('a,'b) assoc = ('a * 'b) list
4476 (* with sexp *)
4477
4478
4479 let (assoc_to_function: ('a, 'b) assoc -> ('a -> 'b)) = fun xs ->
4480 xs +> List.fold_left (fun acc (k, v) ->
4481 (fun k' ->
4482 if k =*= k' then v else acc k'
4483 )) (fun k -> failwith "no key in this assoc")
4484 (* simpler:
4485 let (assoc_to_function: ('a, 'b) assoc -> ('a -> 'b)) = fun xs ->
4486 fun k -> List.assoc k xs
4487 *)
4488
4489 let (empty_assoc: ('a, 'b) assoc) = []
4490 let fold_assoc = List.fold_left
4491 let insert_assoc = fun x xs -> x::xs
4492 let map_assoc = List.map
4493 let filter_assoc = List.filter
4494
4495 let assoc = List.assoc
4496 let keys xs = List.map fst xs
4497
4498 let lookup = assoc
4499
4500 (* assert unique key ?*)
4501 let del_assoc key xs = xs +> List.filter (fun (k,v) -> k <> key)
4502 let replace_assoc (key, v) xs = insert_assoc (key, v) (del_assoc key xs)
4503
4504 let apply_assoc key f xs =
4505 let old = assoc key xs in
4506 replace_assoc (key, f old) xs
4507
4508 let big_union_assoc f xs = xs +> map_assoc f +> fold_assoc union_set empty_set
4509
4510 (* todo: pb normally can suppr fun l -> .... l but if do that, then strange type _a
4511 => assoc_map is strange too => equal dont work
4512 *)
4513 let (assoc_reverse: (('a * 'b) list) -> (('b * 'a) list)) = fun l ->
4514 List.map (fun(x,y) -> (y,x)) l
4515
4516 let (assoc_map: (('a * 'b) list) -> (('a * 'b) list) -> (('a * 'a) list)) =
4517 fun l1 l2 ->
4518 let (l1bis, l2bis) = (assoc_reverse l1, assoc_reverse l2) in
4519 List.map (fun (x,y) -> (y, List.assoc x l2bis )) l1bis
4520
4521 let rec (lookup_list: 'a -> ('a , 'b) assoc list -> 'b) = fun el -> function
4522 | [] -> raise Not_found
4523 | (xs::xxs) -> try List.assoc el xs with Not_found -> lookup_list el xxs
4524
4525 let (lookup_list2: 'a -> ('a , 'b) assoc list -> ('b * int)) = fun el xxs ->
4526 let rec lookup_l_aux i = function
4527 | [] -> raise Not_found
4528 | (xs::xxs) ->
4529 try let res = List.assoc el xs in (res,i)
4530 with Not_found -> lookup_l_aux (i+1) xxs
4531 in lookup_l_aux 0 xxs
4532
4533 let _ = example
4534 (lookup_list2 "c" [["a",1;"b",2];["a",1;"b",3];["a",1;"c",7]] =*= (7,2))
4535
4536
4537 let assoc_option k l =
4538 optionise (fun () -> List.assoc k l)
4539
4540 let assoc_with_err_msg k l =
4541 try List.assoc k l
4542 with Not_found ->
4543 pr2 (spf "pb assoc_with_err_msg: %s" (dump k));
4544 raise Not_found
4545
4546 (*****************************************************************************)
4547 (* Assoc int -> xxx with binary tree. Have a look too at Mapb.mli *)
4548 (*****************************************************************************)
4549
4550 (* ex: type robot_list = robot_info IntMap.t *)
4551 module IntMap = Map.Make
4552 (struct
4553 type t = int
4554 let compare = compare
4555 end)
4556 let intmap_to_list m = IntMap.fold (fun id v acc -> (id, v) :: acc) m []
4557 let intmap_string_of_t f a = "<Not Yet>"
4558
4559 module IntIntMap = Map.Make
4560 (struct
4561 type t = int * int
4562 let compare = compare
4563 end)
4564
4565 let intintmap_to_list m = IntIntMap.fold (fun id v acc -> (id, v) :: acc) m []
4566 let intintmap_string_of_t f a = "<Not Yet>"
4567
4568
4569 (*****************************************************************************)
4570 (* Hash *)
4571 (*****************************************************************************)
4572
4573 (* il parait que better when choose a prime *)
4574 let hcreate () = Hashtbl.create 401
4575 let hadd (k,v) h = Hashtbl.add h k v
4576 let hmem k h = Hashtbl.mem h k
4577 let hfind k h = Hashtbl.find h k
4578 let hreplace (k,v) h = Hashtbl.replace h k v
4579 let hiter = Hashtbl.iter
4580 let hfold = Hashtbl.fold
4581 let hremove k h = Hashtbl.remove h k
4582
4583
4584 let hash_to_list h =
4585 Hashtbl.fold (fun k v acc -> (k,v)::acc) h []
4586 +> List.sort compare
4587
4588 let hash_to_list_unsorted h =
4589 Hashtbl.fold (fun k v acc -> (k,v)::acc) h []
4590
4591 let hash_of_list xs =
4592 let h = Hashtbl.create 101 in
4593 begin
4594 xs +> List.iter (fun (k, v) -> Hashtbl.add h k v);
4595 h
4596 end
4597
4598 let _ =
4599 let h = Hashtbl.create 101 in
4600 Hashtbl.add h "toto" 1;
4601 Hashtbl.add h "toto" 1;
4602 assert(hash_to_list h =*= ["toto",1; "toto",1])
4603
4604
4605 let hfind_default key value_if_not_found h =
4606 try Hashtbl.find h key
4607 with Not_found ->
4608 (Hashtbl.add h key (value_if_not_found ()); Hashtbl.find h key)
4609
4610 (* not as easy as Perl $h->{key}++; but still possible *)
4611 let hupdate_default key op value_if_not_found h =
4612 let old = hfind_default key value_if_not_found h in
4613 Hashtbl.replace h key (op old)
4614
4615
4616 let hfind_option key h =
4617 optionise (fun () -> Hashtbl.find h key)
4618
4619
4620 (* see below: let hkeys h = ... *)
4621
4622
4623 (*****************************************************************************)
4624 (* Hash sets *)
4625 (*****************************************************************************)
4626
4627 type 'a hashset = ('a, bool) Hashtbl.t
4628 (* with sexp *)
4629
4630
4631 let hash_hashset_add k e h =
4632 match optionise (fun () -> Hashtbl.find h k) with
4633 | Some hset -> Hashtbl.replace hset e true
4634 | None ->
4635 let hset = Hashtbl.create 11 in
4636 begin
4637 Hashtbl.add h k hset;
4638 Hashtbl.replace hset e true;
4639 end
4640
4641 let hashset_to_set baseset h =
4642 h +> hash_to_list +> List.map fst +> (fun xs -> baseset#fromlist xs)
4643
4644 let hashset_to_list h = hash_to_list h +> List.map fst
4645
4646 let hashset_of_list xs =
4647 xs +> List.map (fun x -> x, true) +> hash_of_list
4648
4649
4650
4651 let hkeys h =
4652 let hkey = Hashtbl.create 101 in
4653 h +> Hashtbl.iter (fun k v -> Hashtbl.replace hkey k true);
4654 hashset_to_list hkey
4655
4656
4657
4658 let group_assoc_bykey_eff2 xs =
4659 let h = Hashtbl.create 101 in
4660 xs +> List.iter (fun (k, v) -> Hashtbl.add h k v);
4661 let keys = hkeys h in
4662 keys +> List.map (fun k -> k, Hashtbl.find_all h k)
4663
4664 let group_assoc_bykey_eff xs =
4665 profile_code2 "Common.group_assoc_bykey_eff" (fun () ->
4666 group_assoc_bykey_eff2 xs)
4667
4668
4669 let test_group_assoc () =
4670 let xs = enum 0 10000 +> List.map (fun i -> i_to_s i, i) in
4671 let xs = ("0", 2)::xs in
4672 (* let _ys = xs +> Common.groupBy (fun (a,resa) (b,resb) -> a =$= b) *)
4673 let ys = xs +> group_assoc_bykey_eff
4674 in
4675 pr2_gen ys
4676
4677
4678 let uniq_eff xs =
4679 let h = Hashtbl.create 101 in
4680 xs +> List.iter (fun k ->
4681 Hashtbl.add h k true
4682 );
4683 hkeys h
4684
4685
4686
4687 let diff_two_say_set_eff xs1 xs2 =
4688 let h1 = hashset_of_list xs1 in
4689 let h2 = hashset_of_list xs2 in
4690
4691 let hcommon = Hashtbl.create 101 in
4692 let honly_in_h1 = Hashtbl.create 101 in
4693 let honly_in_h2 = Hashtbl.create 101 in
4694
4695 h1 +> Hashtbl.iter (fun k _ ->
4696 if Hashtbl.mem h2 k
4697 then Hashtbl.replace hcommon k true
4698 else Hashtbl.add honly_in_h1 k true
4699 );
4700 h2 +> Hashtbl.iter (fun k _ ->
4701 if Hashtbl.mem h1 k
4702 then Hashtbl.replace hcommon k true
4703 else Hashtbl.add honly_in_h2 k true
4704 );
4705 hashset_to_list hcommon,
4706 hashset_to_list honly_in_h1,
4707 hashset_to_list honly_in_h2
4708
4709
4710 (*****************************************************************************)
4711 (* Stack *)
4712 (*****************************************************************************)
4713 type 'a stack = 'a list
4714 (* with sexp *)
4715
4716 let (empty_stack: 'a stack) = []
4717 let (push: 'a -> 'a stack -> 'a stack) = fun x xs -> x::xs
4718 let (top: 'a stack -> 'a) = List.hd
4719 let (pop: 'a stack -> 'a stack) = List.tl
4720
4721 let top_option = function
4722 | [] -> None
4723 | x::xs -> Some x
4724
4725
4726
4727
4728 (* now in prelude:
4729 * let push2 v l = l := v :: !l
4730 *)
4731
4732 let pop2 l =
4733 let v = List.hd !l in
4734 begin
4735 l := List.tl !l;
4736 v
4737 end
4738
4739
4740 (*****************************************************************************)
4741 (* Undoable Stack *)
4742 (*****************************************************************************)
4743
4744 (* Okasaki use such structure also for having efficient data structure
4745 * supporting fast append.
4746 *)
4747
4748 type 'a undo_stack = 'a list * 'a list (* redo *)
4749
4750 let (empty_undo_stack: 'a undo_stack) =
4751 [], []
4752
4753 (* push erase the possible redo *)
4754 let (push_undo: 'a -> 'a undo_stack -> 'a undo_stack) = fun x (undo,redo) ->
4755 x::undo, []
4756
4757 let (top_undo: 'a undo_stack -> 'a) = fun (undo, redo) ->
4758 List.hd undo
4759
4760 let (pop_undo: 'a undo_stack -> 'a undo_stack) = fun (undo, redo) ->
4761 match undo with
4762 | [] -> failwith "empty undo stack"
4763 | x::xs ->
4764 xs, x::redo
4765
4766 let (undo_pop: 'a undo_stack -> 'a undo_stack) = fun (undo, redo) ->
4767 match redo with
4768 | [] -> failwith "empty redo, nothing to redo"
4769 | x::xs ->
4770 x::undo, xs
4771
4772 let redo_undo x = undo_pop x
4773
4774
4775 let top_undo_option = fun (undo, redo) ->
4776 match undo with
4777 | [] -> None
4778 | x::xs -> Some x
4779
4780 (*****************************************************************************)
4781 (* Binary tree *)
4782 (*****************************************************************************)
4783 type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)
4784
4785
4786 (*****************************************************************************)
4787 (* N-ary tree *)
4788 (*****************************************************************************)
4789
4790 (* no empty tree, must have one root at list *)
4791 type 'a tree = Tree of 'a * ('a tree) list
4792
4793 let rec (tree_iter: ('a -> unit) -> 'a tree -> unit) = fun f tree ->
4794 match tree with
4795 | Tree (node, xs) ->
4796 f node;
4797 xs +> List.iter (tree_iter f)
4798
4799
4800 (*****************************************************************************)
4801 (* N-ary tree with updatable childrens *)
4802 (*****************************************************************************)
4803
4804 (* no empty tree, must have one root at list *)
4805
4806 type 'a treeref =
4807 | NodeRef of 'a * 'a treeref list ref
4808
4809 let treeref_children_ref tree =
4810 match tree with
4811 | NodeRef (n, x) -> x
4812
4813
4814
4815 let rec (treeref_node_iter:
4816 (* (('a * ('a, 'b) treeref list ref) -> unit) ->
4817 ('a, 'b) treeref -> unit
4818 *) 'a)
4819 =
4820 fun f tree ->
4821 match tree with
4822 (* | LeafRef _ -> ()*)
4823 | NodeRef (n, xs) ->
4824 f (n, xs);
4825 !xs +> List.iter (treeref_node_iter f)
4826
4827
4828 let find_treeref f tree =
4829 let res = ref [] in
4830
4831 tree +> treeref_node_iter (fun (n, xs) ->
4832 if f (n,xs)
4833 then push2 (n, xs) res;
4834 );
4835 match !res with
4836 | [n,xs] -> NodeRef (n, xs)
4837 | [] -> raise Not_found
4838 | x::y::zs -> raise Multi_found
4839
4840 let rec (treeref_node_iter_with_parents:
4841 (* (('a * ('a, 'b) treeref list ref) -> ('a list) -> unit) ->
4842 ('a, 'b) treeref -> unit)
4843 *) 'a)
4844 =
4845 fun f tree ->
4846 let rec aux acc tree =
4847 match tree with
4848 (* | LeafRef _ -> ()*)
4849 | NodeRef (n, xs) ->
4850 f (n, xs) acc ;
4851 !xs +> List.iter (aux (n::acc))
4852 in
4853 aux [] tree
4854
4855
4856 (* ---------------------------------------------------------------------- *)
4857 (* Leaf can seem redundant, but sometimes want to directly see if
4858 * a children is a leaf without looking if the list is empty.
4859 *)
4860 type ('a, 'b) treeref2 =
4861 | NodeRef2 of 'a * ('a, 'b) treeref2 list ref
4862 | LeafRef2 of 'b
4863
4864
4865 let treeref2_children_ref tree =
4866 match tree with
4867 | LeafRef2 _ -> failwith "treeref_tail: leaf"
4868 | NodeRef2 (n, x) -> x
4869
4870
4871
4872 let rec (treeref_node_iter2:
4873 (('a * ('a, 'b) treeref2 list ref) -> unit) ->
4874 ('a, 'b) treeref2 -> unit) =
4875 fun f tree ->
4876 match tree with
4877 | LeafRef2 _ -> ()
4878 | NodeRef2 (n, xs) ->
4879 f (n, xs);
4880 !xs +> List.iter (treeref_node_iter2 f)
4881
4882
4883 let find_treeref2 f tree =
4884 let res = ref [] in
4885
4886 tree +> treeref_node_iter2 (fun (n, xs) ->
4887 if f (n,xs)
4888 then push2 (n, xs) res;
4889 );
4890 match !res with
4891 | [n,xs] -> NodeRef2 (n, xs)
4892 | [] -> raise Not_found
4893 | x::y::zs -> raise Multi_found
4894
4895
4896
4897
4898 let rec (treeref_node_iter_with_parents2:
4899 (('a * ('a, 'b) treeref2 list ref) -> ('a list) -> unit) ->
4900 ('a, 'b) treeref2 -> unit) =
4901 fun f tree ->
4902 let rec aux acc tree =
4903 match tree with
4904 | LeafRef2 _ -> ()
4905 | NodeRef2 (n, xs) ->
4906 f (n, xs) acc ;
4907 !xs +> List.iter (aux (n::acc))
4908 in
4909 aux [] tree
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923 let find_treeref_with_parents_some f tree =
4924 let res = ref [] in
4925
4926 tree +> treeref_node_iter_with_parents (fun (n, xs) parents ->
4927 match f (n,xs) parents with
4928 | Some v -> push2 v res;
4929 | None -> ()
4930 );
4931 match !res with
4932 | [v] -> v
4933 | [] -> raise Not_found
4934 | x::y::zs -> raise Multi_found
4935
4936 let find_multi_treeref_with_parents_some f tree =
4937 let res = ref [] in
4938
4939 tree +> treeref_node_iter_with_parents (fun (n, xs) parents ->
4940 match f (n,xs) parents with
4941 | Some v -> push2 v res;
4942 | None -> ()
4943 );
4944 match !res with
4945 | [v] -> !res
4946 | [] -> raise Not_found
4947 | x::y::zs -> !res
4948
4949
4950 (*****************************************************************************)
4951 (* Graph. Have a look too at Ograph_*.mli *)
4952 (*****************************************************************************)
4953 (* todo: generalise to put in common (need 'edge (and 'c ?),
4954 * and take in param a display func, cos caml sux, no overloading of show :(
4955 * Simple impelemntation. Can do also matrix, or adjacent list, or pointer(ref)
4956 * todo: do some check (dont exist already, ...)
4957 *)
4958
4959 type 'node graph = ('node set) * (('node * 'node) set)
4960
4961 let (add_node: 'a -> 'a graph -> 'a graph) = fun node (nodes, arcs) ->
4962 (node::nodes, arcs)
4963
4964 let (del_node: 'a -> 'a graph -> 'a graph) = fun node (nodes, arcs) ->
4965 (nodes $-$ set [node], arcs)
4966 (* could do more job:
4967 let _ = assert (successors node (nodes, arcs) = empty) in
4968 +> List.filter (fun (src, dst) -> dst != node))
4969 *)
4970 let (add_arc: ('a * 'a) -> 'a graph -> 'a graph) = fun arc (nodes, arcs) ->
4971 (nodes, set [arc] $+$ arcs)
4972
4973 let (del_arc: ('a * 'a) -> 'a graph -> 'a graph) = fun arc (nodes, arcs) ->
4974 (nodes, arcs +> List.filter (fun a -> not (arc =*= a)))
4975
4976 let (successors: 'a -> 'a graph -> 'a set) = fun x (nodes, arcs) ->
4977 arcs +> List.filter (fun (src, dst) -> src =*= x) +> List.map snd
4978
4979 let (predecessors: 'a -> 'a graph -> 'a set) = fun x (nodes, arcs) ->
4980 arcs +> List.filter (fun (src, dst) -> dst =*= x) +> List.map fst
4981
4982 let (nodes: 'a graph -> 'a set) = fun (nodes, arcs) -> nodes
4983
4984 (* pre: no cycle *)
4985 let rec (fold_upward: ('b -> 'a -> 'b) -> 'a set -> 'b -> 'a graph -> 'b) =
4986 fun f xs acc graph ->
4987 match xs with
4988 | [] -> acc
4989 | x::xs -> (f acc x)
4990 +> (fun newacc -> fold_upward f (graph +> predecessors x) newacc graph)
4991 +> (fun newacc -> fold_upward f xs newacc graph)
4992 (* TODO avoid already visited *)
4993
4994 let empty_graph = ([], [])
4995
4996
4997
4998 (*
4999 let (add_arcs_toward: int -> (int list) -> 'a graph -> 'a graph) = fun i xs ->
5000 function
5001 (nodes, arcs) -> (nodes, (List.map (fun j -> (j,i) ) xs)++arcs)
5002 let (del_arcs_toward: int -> (int list) -> 'a graph -> 'a graph)= fun i xs g ->
5003 List.fold_left (fun acc el -> del_arc (el, i) acc) g xs
5004 let (add_arcs_from: int -> (int list) -> 'a graph -> 'a graph) = fun i xs ->
5005 function
5006 (nodes, arcs) -> (nodes, (List.map (fun j -> (i,j) ) xs)++arcs)
5007
5008
5009 let (del_node: (int * 'node) -> 'node graph -> 'node graph) = fun node ->
5010 function (nodes, arcs) ->
5011 let newnodes = List.filter (fun a -> not (node = a)) nodes in
5012 if newnodes = nodes then (raise Not_found) else (newnodes, arcs)
5013 let (replace_node: int -> 'node -> 'node graph -> 'node graph) = fun i n ->
5014 function (nodes, arcs) ->
5015 let newnodes = List.filter (fun (j,_) -> not (i = j)) nodes in
5016 ((i,n)::newnodes, arcs)
5017 let (get_node: int -> 'node graph -> 'node) = fun i -> function
5018 (nodes, arcs) -> List.assoc i nodes
5019
5020 let (get_free: 'a graph -> int) = function
5021 (nodes, arcs) -> (maximum (List.map fst nodes))+1
5022 (* require no cycle !!
5023 TODO if cycle check that we have already visited a node *)
5024 let rec (succ_all: int -> 'a graph -> (int list)) = fun i -> function
5025 (nodes, arcs) as g ->
5026 let direct = succ i g in
5027 union direct (union_list (List.map (fun i -> succ_all i g) direct))
5028 let rec (pred_all: int -> 'a graph -> (int list)) = fun i -> function
5029 (nodes, arcs) as g ->
5030 let direct = pred i g in
5031 union direct (union_list (List.map (fun i -> pred_all i g) direct))
5032 (* require that the nodes are different !! *)
5033 let rec (equal: 'a graph -> 'a graph -> bool) = fun g1 g2 ->
5034 let ((nodes1, arcs1),(nodes2, arcs2)) = (g1,g2) in
5035 try
5036 (* do 2 things, check same length and to assoc *)
5037 let conv = assoc_map nodes1 nodes2 in
5038 List.for_all (fun (i1,i2) ->
5039 List.mem (List.assoc i1 conv, List.assoc i2 conv) arcs2)
5040 arcs1
5041 && (List.length arcs1 = List.length arcs2)
5042 (* could think that only forall is needed, but need check same lenth too*)
5043 with _ -> false
5044
5045 let (display: 'a graph -> ('a -> unit) -> unit) = fun g display_func ->
5046 let rec aux depth i =
5047 print_n depth " ";
5048 print_int i; print_string "->"; display_func (get_node i g);
5049 print_string "\n";
5050 List.iter (aux (depth+2)) (succ i g)
5051 in aux 0 1
5052
5053 let (display_dot: 'a graph -> ('a -> string) -> unit)= fun (nodes,arcs) func ->
5054 let file = open_out "test.dot" in
5055 output_string file "digraph misc {\n" ;
5056 List.iter (fun (n, node) ->
5057 output_int file n; output_string file " [label=\"";
5058 output_string file (func node); output_string file " \"];\n"; ) nodes;
5059 List.iter (fun (i1,i2) -> output_int file i1 ; output_string file " -> " ;
5060 output_int file i2 ; output_string file " ;\n"; ) arcs;
5061 output_string file "}\n" ;
5062 close_out file;
5063 let status = Unix.system "viewdot test.dot" in
5064 ()
5065 (* todo: faire = graphe (int can change !!! => cant make simply =)
5066 reassign number first !!
5067 *)
5068
5069 (* todo: mettre diff(modulo = !!) en rouge *)
5070 let (display_dot2: 'a graph -> 'a graph -> ('a -> string) -> unit) =
5071 fun (nodes1, arcs1) (nodes2, arcs2) func ->
5072 let file = open_out "test.dot" in
5073 output_string file "digraph misc {\n" ;
5074 output_string file "rotate = 90;\n";
5075 List.iter (fun (n, node) ->
5076 output_string file "100"; output_int file n;
5077 output_string file " [label=\"";
5078 output_string file (func node); output_string file " \"];\n"; ) nodes1;
5079 List.iter (fun (n, node) ->
5080 output_string file "200"; output_int file n;
5081 output_string file " [label=\"";
5082 output_string file (func node); output_string file " \"];\n"; ) nodes2;
5083 List.iter (fun (i1,i2) ->
5084 output_string file "100"; output_int file i1 ; output_string file " -> " ;
5085 output_string file "100"; output_int file i2 ; output_string file " ;\n";
5086 )
5087 arcs1;
5088 List.iter (fun (i1,i2) ->
5089 output_string file "200"; output_int file i1 ; output_string file " -> " ;
5090 output_string file "200"; output_int file i2 ; output_string file " ;\n"; )
5091 arcs2;
5092 (* output_string file "500 -> 1001; 500 -> 2001}\n" ; *)
5093 output_string file "}\n" ;
5094 close_out file;
5095 let status = Unix.system "viewdot test.dot" in
5096 ()
5097
5098
5099 *)
5100 (*****************************************************************************)
5101 (* Generic op *)
5102 (*****************************************************************************)
5103 (* overloading *)
5104
5105 let map = List.map (* note: really really slow, use rev_map if possible *)
5106 let filter = List.filter
5107 let fold = List.fold_left
5108 let member = List.mem
5109 let iter = List.iter
5110 let find = List.find
5111 let exists = List.exists
5112 let forall = List.for_all
5113 let big_union f xs = xs +> map f +> fold union_set empty_set
5114 (* let empty = [] *)
5115 let empty_list = []
5116 let sort = List.sort
5117 let length = List.length
5118 (* in prelude now: let null xs = match xs with [] -> true | _ -> false *)
5119 let head = List.hd
5120 let tail = List.tl
5121 let is_singleton = fun xs -> List.length xs =|= 1
5122
5123 (*****************************************************************************)
5124 (* Geometry (raytracer) *)
5125 (*****************************************************************************)
5126
5127 type vector = (float * float * float)
5128 type point = vector
5129 type color = vector (* color(0-1) *)
5130
5131 (* todo: factorise *)
5132 let (dotproduct: vector * vector -> float) =
5133 fun ((x1,y1,z1),(x2,y2,z2)) -> (x1*.x2 +. y1*.y2 +. z1*.z2)
5134 let (vector_length: vector -> float) =
5135 fun (x,y,z) -> sqrt (square x +. square y +. square z)
5136 let (minus_point: point * point -> vector) =
5137 fun ((x1,y1,z1),(x2,y2,z2)) -> ((x1 -. x2),(y1 -. y2),(z1 -. z2))
5138 let (distance: point * point -> float) =
5139 fun (x1, x2) -> vector_length (minus_point (x2,x1))
5140 let (normalise: vector -> vector) =
5141 fun (x,y,z) ->
5142 let len = vector_length (x,y,z) in (x /. len, y /. len, z /. len)
5143 let (mult_coeff: vector -> float -> vector) =
5144 fun (x,y,z) c -> (x *. c, y *. c, z *. c)
5145 let (add_vector: vector -> vector -> vector) =
5146 fun v1 v2 -> let ((x1,y1,z1),(x2,y2,z2)) = (v1,v2) in
5147 (x1+.x2, y1+.y2, z1+.z2)
5148 let (mult_vector: vector -> vector -> vector) =
5149 fun v1 v2 -> let ((x1,y1,z1),(x2,y2,z2)) = (v1,v2) in
5150 (x1*.x2, y1*.y2, z1*.z2)
5151 let sum_vector = List.fold_left add_vector (0.0,0.0,0.0)
5152
5153 (*****************************************************************************)
5154 (* Pics (raytracer) *)
5155 (*****************************************************************************)
5156
5157 type pixel = (int * int * int) (* RGB *)
5158
5159 (* required pixel list in row major order, line after line *)
5160 let (write_ppm: int -> int -> (pixel list) -> string -> unit) = fun
5161 width height xs filename ->
5162 let chan = open_out filename in
5163 begin
5164 output_string chan "P6\n";
5165 output_string chan ((string_of_int width) ^ "\n");
5166 output_string chan ((string_of_int height) ^ "\n");
5167 output_string chan "255\n";
5168 List.iter (fun (r,g,b) ->
5169 List.iter (fun byt -> output_byte chan byt) [r;g;b]
5170 ) xs;
5171 close_out chan
5172 end
5173
5174 let test_ppm1 () = write_ppm 100 100
5175 ((generate (50*100) (1,45,100)) ++ (generate (50*100) (1,1,100)))
5176 "img.ppm"
5177
5178 (*****************************************************************************)
5179 (* Diff (lfs) *)
5180 (*****************************************************************************)
5181 type diff = Match | BnotinA | AnotinB
5182
5183 let (diff: (int -> int -> diff -> unit)-> (string list * string list) -> unit)=
5184 fun f (xs,ys) ->
5185 let file1 = "/tmp/diff1-" ^ (string_of_int (Unix.getuid ())) in
5186 let file2 = "/tmp/diff2-" ^ (string_of_int (Unix.getuid ())) in
5187 let fileresult = "/tmp/diffresult-" ^ (string_of_int (Unix.getuid ())) in
5188 write_file file1 (unwords xs);
5189 write_file file2 (unwords ys);
5190 command2
5191 ("diff --side-by-side -W 1 " ^ file1 ^ " " ^ file2 ^ " > " ^ fileresult);
5192 let res = cat fileresult in
5193 let a = ref 0 in
5194 let b = ref 0 in
5195 res +> List.iter (fun s ->
5196 match s with
5197 | ("" | " ") -> f !a !b Match; incr a; incr b;
5198 | ">" -> f !a !b BnotinA; incr b;
5199 | ("|" | "/" | "\\" ) ->
5200 f !a !b BnotinA; f !a !b AnotinB; incr a; incr b;
5201 | "<" -> f !a !b AnotinB; incr a;
5202 | _ -> raise Impossible
5203 )
5204 (*
5205 let _ =
5206 diff
5207 ["0";"a";"b";"c";"d"; "f";"g";"h";"j";"q"; "z"]
5208 [ "a";"b";"c";"d";"e";"f";"g";"i";"j";"k";"r";"x";"y";"z"]
5209 (fun x y -> pr "match")
5210 (fun x y -> pr "a_not_in_b")
5211 (fun x y -> pr "b_not_in_a")
5212 *)
5213
5214 let (diff2: (int -> int -> diff -> unit) -> (string * string) -> unit) =
5215 fun f (xstr,ystr) ->
5216 write_file "/tmp/diff1" xstr;
5217 write_file "/tmp/diff2" ystr;
5218 command2
5219 ("diff --side-by-side --left-column -W 1 " ^
5220 "/tmp/diff1 /tmp/diff2 > /tmp/diffresult");
5221 let res = cat "/tmp/diffresult" in
5222 let a = ref 0 in
5223 let b = ref 0 in
5224 res +> List.iter (fun s ->
5225 match s with
5226 | "(" -> f !a !b Match; incr a; incr b;
5227 | ">" -> f !a !b BnotinA; incr b;
5228 | "|" -> f !a !b BnotinA; f !a !b AnotinB; incr a; incr b;
5229 | "<" -> f !a !b AnotinB; incr a;
5230 | _ -> raise Impossible
5231 )
5232
5233
5234 (*****************************************************************************)
5235 (* Parsers (aop-colcombet) *)
5236 (*****************************************************************************)
5237
5238 let parserCommon lexbuf parserer lexer =
5239 try
5240 let result = parserer lexer lexbuf in
5241 result
5242 with Parsing.Parse_error ->
5243 print_string "buf: "; print_string lexbuf.Lexing.lex_buffer;
5244 print_string "\n";
5245 print_string "current: "; print_int lexbuf.Lexing.lex_curr_pos;
5246 print_string "\n";
5247 raise Parsing.Parse_error
5248
5249
5250 (* marche pas ca neuneu *)
5251 (*
5252 let getDoubleParser parserer lexer string =
5253 let lexbuf1 = Lexing.from_string string in
5254 let chan = open_in string in
5255 let lexbuf2 = Lexing.from_channel chan in
5256 (parserCommon lexbuf1 parserer lexer , parserCommon lexbuf2 parserer lexer )
5257 *)
5258
5259 let getDoubleParser parserer lexer =
5260 (
5261 (function string ->
5262 let lexbuf1 = Lexing.from_string string in
5263 parserCommon lexbuf1 parserer lexer
5264 ),
5265 (function string ->
5266 let chan = open_in string in
5267 let lexbuf2 = Lexing.from_channel chan in
5268 parserCommon lexbuf2 parserer lexer
5269 ))
5270
5271
5272 (*****************************************************************************)
5273 (* parser combinators *)
5274 (*****************************************************************************)
5275
5276 (* cf parser_combinators.ml
5277 *
5278 * Could also use ocaml stream. but not backtrack and forced to do LL,
5279 * so combinators are better.
5280 *
5281 *)
5282
5283
5284 (*****************************************************************************)
5285 (* Parser related (cocci) *)
5286 (*****************************************************************************)
5287
5288 type parse_info = {
5289 str: string;
5290 charpos: int;
5291
5292 line: int;
5293 column: int;
5294 file: filename;
5295 }
5296 (* with sexp *)
5297
5298 let fake_parse_info = {
5299 charpos = -1; str = "";
5300 line = -1; column = -1; file = "";
5301 }
5302
5303 let string_of_parse_info x =
5304 spf "%s at %s:%d:%d" x.str x.file x.line x.column
5305 let string_of_parse_info_bis x =
5306 spf "%s:%d:%d" x.file x.line x.column
5307
5308 let (info_from_charpos2: int -> filename -> (int * int * string)) =
5309 fun charpos filename ->
5310
5311 (* Currently lexing.ml does not handle the line number position.
5312 * Even if there is some fields in the lexing structure, they are not
5313 * maintained by the lexing engine :( So the following code does not work:
5314 * let pos = Lexing.lexeme_end_p lexbuf in
5315 * sprintf "at file %s, line %d, char %d" pos.pos_fname pos.pos_lnum
5316 * (pos.pos_cnum - pos.pos_bol) in
5317 * Hence this function to overcome the previous limitation.
5318 *)
5319 let chan = open_in filename in
5320 let linen = ref 0 in
5321 let posl = ref 0 in
5322 let rec charpos_to_pos_aux last_valid =
5323 let s =
5324 try Some (input_line chan)
5325 with End_of_file when charpos =|= last_valid -> None in
5326 incr linen;
5327 match s with
5328 Some s ->
5329 let s = s ^ "\n" in
5330 if (!posl + slength s > charpos)
5331 then begin
5332 close_in chan;
5333 (!linen, charpos - !posl, s)
5334 end
5335 else begin
5336 posl := !posl + slength s;
5337 charpos_to_pos_aux !posl;
5338 end
5339 | None -> (!linen, charpos - !posl, "\n")
5340 in
5341 let res = charpos_to_pos_aux 0 in
5342 close_in chan;
5343 res
5344
5345 let info_from_charpos a b =
5346 profile_code "Common.info_from_charpos" (fun () -> info_from_charpos2 a b)
5347
5348
5349
5350 let (full_charpos_to_pos2: filename -> (int * int) array ) = fun filename ->
5351
5352 let arr = Array.create (filesize filename + 2) (0,0) in
5353
5354 let chan = open_in filename in
5355
5356 let charpos = ref 0 in
5357 let line = ref 0 in
5358
5359 let rec full_charpos_to_pos_aux () =
5360 try
5361 let s = (input_line chan) in
5362 incr line;
5363
5364 (* '... +1 do' cos input_line dont return the trailing \n *)
5365 for i = 0 to (slength s - 1) + 1 do
5366 arr.(!charpos + i) <- (!line, i);
5367 done;
5368 charpos := !charpos + slength s + 1;
5369 full_charpos_to_pos_aux();
5370
5371 with End_of_file ->
5372 for i = !charpos to Array.length arr - 1 do
5373 arr.(i) <- (!line, 0);
5374 done;
5375 ();
5376 in
5377 begin
5378 full_charpos_to_pos_aux ();
5379 close_in chan;
5380 arr
5381 end
5382 let full_charpos_to_pos a =
5383 profile_code "Common.full_charpos_to_pos" (fun () -> full_charpos_to_pos2 a)
5384
5385 let test_charpos file =
5386 full_charpos_to_pos file +> dump +> pr2
5387
5388
5389
5390 let complete_parse_info filename table x =
5391 { x with
5392 file = filename;
5393 line = fst (table.(x.charpos));
5394 column = snd (table.(x.charpos));
5395 }
5396
5397 (*---------------------------------------------------------------------------*)
5398 (* Decalage is here to handle stuff such as cpp which include file and who
5399 * can make shift.
5400 *)
5401 let (error_messagebis: filename -> (string * int) -> int -> string)=
5402 fun filename (lexeme, lexstart) decalage ->
5403
5404 let charpos = lexstart + decalage in
5405 let tok = lexeme in
5406 let (line, pos, linecontent) = info_from_charpos charpos filename in
5407 sprintf "File \"%s\", line %d, column %d, charpos = %d
5408 around = '%s', whole content = %s"
5409 filename line pos charpos tok (chop linecontent)
5410
5411 let error_message = fun filename (lexeme, lexstart) ->
5412 try error_messagebis filename (lexeme, lexstart) 0
5413 with
5414 End_of_file ->
5415 ("PB in Common.error_message, position " ^ i_to_s lexstart ^
5416 " given out of file:" ^ filename)
5417
5418
5419
5420 let error_message_short = fun filename (lexeme, lexstart) ->
5421 try
5422 let charpos = lexstart in
5423 let (line, pos, linecontent) = info_from_charpos charpos filename in
5424 sprintf "File \"%s\", line %d" filename line
5425
5426 with End_of_file ->
5427 begin
5428 ("PB in Common.error_message, position " ^ i_to_s lexstart ^
5429 " given out of file:" ^ filename);
5430 end
5431
5432
5433
5434 (*****************************************************************************)
5435 (* Regression testing bis (cocci) *)
5436 (*****************************************************************************)
5437
5438 (* todo: keep also size of file, compute md5sum ? cos maybe the file
5439 * has changed!.
5440 *
5441 * todo: could also compute the date, or some version info of the program,
5442 * can record the first date when was found a OK, the last date where
5443 * was ok, and then first date when found fail. So the
5444 * Common.Ok would have more information that would be passed
5445 * to the Common.Pb of date * date * date * string peut etre.
5446 *
5447 * todo? maybe use plain text file instead of marshalling.
5448 *)
5449
5450 type score_result = Ok | Pb of string
5451 (* with sexp *)
5452 type score = (string (* usually a filename *), score_result) Hashtbl.t
5453 (* with sexp *)
5454 type score_list = (string (* usually a filename *) * score_result) list
5455 (* with sexp *)
5456
5457 let empty_score () = (Hashtbl.create 101 : score)
5458
5459
5460
5461 let regression_testing_vs newscore bestscore =
5462
5463 let newbestscore = empty_score () in
5464
5465 let allres =
5466 (hash_to_list newscore +> List.map fst)
5467 $+$
5468 (hash_to_list bestscore +> List.map fst)
5469 in
5470 begin
5471 allres +> List.iter (fun res ->
5472 match
5473 optionise (fun () -> Hashtbl.find newscore res),
5474 optionise (fun () -> Hashtbl.find bestscore res)
5475 with
5476 | None, None -> raise Impossible
5477 | Some x, None ->
5478 Printf.printf "new test file appeared: %s\n" res;
5479 Hashtbl.add newbestscore res x;
5480 | None, Some x ->
5481 Printf.printf "old test file disappeared: %s\n" res;
5482 | Some newone, Some bestone ->
5483 (match newone, bestone with
5484 | Ok, Ok ->
5485 Hashtbl.add newbestscore res Ok
5486 | Pb x, Ok ->
5487 Printf.printf
5488 "PBBBBBBBB: a test file does not work anymore!!! : %s\n" res;
5489 Printf.printf "Error : %s\n" x;
5490 Hashtbl.add newbestscore res Ok
5491 | Ok, Pb x ->
5492 Printf.printf "Great: a test file now works: %s\n" res;
5493 Hashtbl.add newbestscore res Ok
5494 | Pb x, Pb y ->
5495 Hashtbl.add newbestscore res (Pb x);
5496 if not (x =$= y)
5497 then begin
5498 Printf.printf
5499 "Semipb: still error but not same error : %s\n" res;
5500 Printf.printf "%s\n" (chop ("Old error: " ^ y));
5501 Printf.printf "New error: %s\n" x;
5502 end
5503 )
5504 );
5505 flush stdout; flush stderr;
5506 newbestscore
5507 end
5508
5509 let regression_testing newscore best_score_file =
5510
5511 pr2 ("regression file: "^ best_score_file);
5512 let (bestscore : score) =
5513 if not (Sys.file_exists best_score_file)
5514 then write_value (empty_score()) best_score_file;
5515 get_value best_score_file
5516 in
5517 let newbestscore = regression_testing_vs newscore bestscore in
5518 write_value newbestscore (best_score_file ^ ".old");
5519 write_value newbestscore best_score_file;
5520 ()
5521
5522
5523
5524
5525 let string_of_score_result v =
5526 match v with
5527 | Ok -> "Ok"
5528 | Pb s -> "Pb: " ^ s
5529
5530 let total_scores score =
5531 let total = hash_to_list score +> List.length in
5532 let good = hash_to_list score +> List.filter
5533 (fun (s, v) -> v =*= Ok) +> List.length in
5534 good, total
5535
5536
5537 let print_total_score score =
5538 pr2 "--------------------------------";
5539 pr2 "total score";
5540 pr2 "--------------------------------";
5541 let (good, total) = total_scores score in
5542 pr2 (sprintf "good = %d/%d" good total)
5543
5544 let print_score score =
5545 score +> hash_to_list +> List.iter (fun (k, v) ->
5546 pr2 (sprintf "% s --> %s" k (string_of_score_result v))
5547 );
5548 print_total_score score;
5549 ()
5550
5551
5552 (*****************************************************************************)
5553 (* Scope managment (cocci) *)
5554 (*****************************************************************************)
5555
5556 (* could also make a function Common.make_scope_functions that return
5557 * the new_scope, del_scope, do_in_scope, add_env. Kind of functor :)
5558 *)
5559
5560 type ('a, 'b) scoped_env = ('a, 'b) assoc list
5561
5562 (*
5563 let rec lookup_env f env =
5564 match env with
5565 | [] -> raise Not_found
5566 | []::zs -> lookup_env f zs
5567 | (x::xs)::zs ->
5568 match f x with
5569 | None -> lookup_env f (xs::zs)
5570 | Some y -> y
5571
5572 let member_env_key k env =
5573 try
5574 let _ = lookup_env (fun (k',v) -> if k = k' then Some v else None) env in
5575 true
5576 with Not_found -> false
5577
5578 *)
5579
5580 let rec lookup_env k env =
5581 match env with
5582 | [] -> raise Not_found
5583 | []::zs -> lookup_env k zs
5584 | ((k',v)::xs)::zs ->
5585 if k =*= k'
5586 then v
5587 else lookup_env k (xs::zs)
5588
5589 let member_env_key k env =
5590 match optionise (fun () -> lookup_env k env) with
5591 | None -> false
5592 | Some _ -> true
5593
5594
5595 let new_scope scoped_env = scoped_env := []::!scoped_env
5596 let del_scope scoped_env = scoped_env := List.tl !scoped_env
5597
5598 let do_in_new_scope scoped_env f =
5599 begin
5600 new_scope scoped_env;
5601 let res = f() in
5602 del_scope scoped_env;
5603 res
5604 end
5605
5606 let add_in_scope scoped_env def =
5607 let (current, older) = uncons !scoped_env in
5608 scoped_env := (def::current)::older
5609
5610
5611
5612
5613
5614 (* note that ocaml hashtbl store also old value of a binding when add
5615 * add a newbinding; that's why del_scope works
5616 *)
5617
5618 type ('a, 'b) scoped_h_env = {
5619 scoped_h : ('a, 'b) Hashtbl.t;
5620 scoped_list : ('a, 'b) assoc list;
5621 }
5622
5623 let empty_scoped_h_env () = {
5624 scoped_h = Hashtbl.create 101;
5625 scoped_list = [[]];
5626 }
5627 let clone_scoped_h_env x =
5628 { scoped_h = Hashtbl.copy x.scoped_h;
5629 scoped_list = x.scoped_list;
5630 }
5631
5632 let rec lookup_h_env k env =
5633 Hashtbl.find env.scoped_h k
5634
5635 let member_h_env_key k env =
5636 match optionise (fun () -> lookup_h_env k env) with
5637 | None -> false
5638 | Some _ -> true
5639
5640
5641 let new_scope_h scoped_env =
5642 scoped_env := {!scoped_env with scoped_list = []::!scoped_env.scoped_list}
5643 let del_scope_h scoped_env =
5644 begin
5645 List.hd !scoped_env.scoped_list +> List.iter (fun (k, v) ->
5646 Hashtbl.remove !scoped_env.scoped_h k
5647 );
5648 scoped_env := {!scoped_env with scoped_list =
5649 List.tl !scoped_env.scoped_list
5650 }
5651 end
5652
5653 let do_in_new_scope_h scoped_env f =
5654 begin
5655 new_scope_h scoped_env;
5656 let res = f() in
5657 del_scope_h scoped_env;
5658 res
5659 end
5660
5661 (*
5662 let add_in_scope scoped_env def =
5663 let (current, older) = uncons !scoped_env in
5664 scoped_env := (def::current)::older
5665 *)
5666
5667 let add_in_scope_h x (k,v) =
5668 begin
5669 Hashtbl.add !x.scoped_h k v;
5670 x := { !x with scoped_list =
5671 ((k,v)::(List.hd !x.scoped_list))::(List.tl !x.scoped_list);
5672 };
5673 end
5674
5675 (*****************************************************************************)
5676 (* Terminal *)
5677 (*****************************************************************************)
5678
5679 (* let ansi_terminal = ref true *)
5680
5681 let (_execute_and_show_progress_func: (int (* length *) -> ((unit -> unit) -> unit) -> unit) ref)
5682 = ref
5683 (fun a b ->
5684 failwith "no execute yet, have you included common_extra.cmo?"
5685 )
5686
5687
5688
5689 let execute_and_show_progress len f =
5690 !_execute_and_show_progress_func len f
5691
5692
5693 (* now in common_extra.ml:
5694 * let execute_and_show_progress len f = ...
5695 *)
5696
5697 (*****************************************************************************)
5698 (* Random *)
5699 (*****************************************************************************)
5700
5701 let _init_random = Random.self_init ()
5702 (*
5703 let random_insert i l =
5704 let p = Random.int (length l +1)
5705 in let rec insert i p l =
5706 if (p = 0) then i::l else (hd l)::insert i (p-1) (tl l)
5707 in insert i p l
5708
5709 let rec randomize_list = function
5710 [] -> []
5711 | a::l -> random_insert a (randomize_list l)
5712 *)
5713 let random_list xs =
5714 List.nth xs (Random.int (length xs))
5715
5716 (* todo_opti: use fisher/yates algorithm.
5717 * ref: http://en.wikipedia.org/wiki/Knuth_shuffle
5718 *
5719 * public static void shuffle (int[] array)
5720 * {
5721 * Random rng = new Random ();
5722 * int n = array.length;
5723 * while (--n > 0)
5724 * {
5725 * int k = rng.nextInt(n + 1); // 0 <= k <= n (!)
5726 * int temp = array[n];
5727 * array[n] = array[k];
5728 * array[k] = temp;
5729 * }
5730 * }
5731
5732 *)
5733 let randomize_list xs =
5734 let permut = permutation xs in
5735 random_list permut
5736
5737
5738
5739 let random_subset_of_list num xs =
5740 let array = Array.of_list xs in
5741 let len = Array.length array in
5742
5743 let h = Hashtbl.create 101 in
5744 let cnt = ref num in
5745 while !cnt > 0 do
5746 let x = Random.int len in
5747 if not (Hashtbl.mem h (array.(x))) (* bugfix2: not just x :) *)
5748 then begin
5749 Hashtbl.add h (array.(x)) true; (* bugfix1: not just x :) *)
5750 decr cnt;
5751 end
5752 done;
5753 let objs = hash_to_list h +> List.map fst in
5754 objs
5755
5756
5757
5758 (*****************************************************************************)
5759 (* Flags and actions *)
5760 (*****************************************************************************)
5761
5762 (* I put it inside a func as it can help to give a chance to
5763 * change the globals before getting the options as some
5764 * options sometimes may want to show the default value.
5765 *)
5766 let cmdline_flags_devel () =
5767 [
5768 "-debugger", Arg.Set debugger ,
5769 " option to set if launched inside ocamldebug";
5770 "-profile", Arg.Unit (fun () -> profile := PALL),
5771 " gather timing information about important functions";
5772 ]
5773 let cmdline_flags_verbose () =
5774 [
5775 "-verbose_level", Arg.Set_int verbose_level,
5776 " <int> guess what";
5777 "-disable_pr2_once", Arg.Set disable_pr2_once,
5778 " to print more messages";
5779 "-show_trace_profile", Arg.Set show_trace_profile,
5780 " show trace";
5781 ]
5782
5783 let cmdline_flags_other () =
5784 [
5785 "-nocheck_stack", Arg.Clear check_stack,
5786 " ";
5787 "-batch_mode", Arg.Set _batch_mode,
5788 " no interactivity"
5789 ]
5790
5791 (* potentially other common options but not yet integrated:
5792
5793 "-timeout", Arg.Set_int timeout,
5794 " <sec> interrupt LFS or buggy external plugins";
5795
5796 (* can't be factorized because of the $ cvs stuff, we want the date
5797 * of the main.ml file, not common.ml
5798 *)
5799 "-version", Arg.Unit (fun () ->
5800 pr2 "version: _dollar_Date: 2008/06/14 00:54:22 _dollar_";
5801 raise (Common.UnixExit 0)
5802 ),
5803 " guess what";
5804
5805 "-shorthelp", Arg.Unit (fun () ->
5806 !short_usage_func();
5807 raise (Common.UnixExit 0)
5808 ),
5809 " see short list of options";
5810 "-longhelp", Arg.Unit (fun () ->
5811 !long_usage_func();
5812 raise (Common.UnixExit 0)
5813 ),
5814 "-help", Arg.Unit (fun () ->
5815 !long_usage_func();
5816 raise (Common.UnixExit 0)
5817 ),
5818 " ";
5819 "--help", Arg.Unit (fun () ->
5820 !long_usage_func();
5821 raise (Common.UnixExit 0)
5822 ),
5823 " ";
5824
5825 *)
5826
5827 let cmdline_actions () =
5828 [
5829 "-test_check_stack", " <limit>",
5830 mk_action_1_arg test_check_stack_size;
5831 ]
5832
5833
5834 (*****************************************************************************)
5835 (* Postlude *)
5836 (*****************************************************************************)
5837 (* stuff put here cos of of forward definition limitation of ocaml *)
5838
5839
5840 (* Infix trick, seen in jane street lib and harrop's code, and maybe in GMP *)
5841 module Infix = struct
5842 let (+>) = (+>)
5843 let (==~) = (==~)
5844 let (=~) = (=~)
5845 end
5846
5847
5848 let main_boilerplate f =
5849 if not (!Sys.interactive) then
5850 exn_to_real_unixexit (fun () ->
5851
5852 Sys.set_signal Sys.sigint (Sys.Signal_handle (fun _ ->
5853 pr2 "C-c intercepted, will do some cleaning before exiting";
5854 (* But if do some try ... with e -> and if do not reraise the exn,
5855 * the bubble never goes at top and so I cant really C-c.
5856 *
5857 * A solution would be to not raise, but do the erase_temp_file in the
5858 * syshandler, here, and then exit.
5859 * The current solution is to not do some wild try ... with e
5860 * by having in the exn handler a case: UnixExit x -> raise ... | e ->
5861 *)
5862 Sys.set_signal Sys.sigint Sys.Signal_default;
5863 raise (UnixExit (-1))
5864 ));
5865
5866 (* The finalize below makes it tedious to go back to exn when use
5867 * 'back' in the debugger. Hence this special case. But the
5868 * Common.debugger will be set in main(), so too late, so
5869 * have to be quicker
5870 *)
5871 if Sys.argv +> Array.to_list +> List.exists (fun x -> x =$= "-debugger")
5872 then debugger := true;
5873
5874 finalize (fun ()->
5875 pp_do_in_zero_box (fun () ->
5876 f(); (* <---- here it is *)
5877 ))
5878 (fun()->
5879 if !profile <> PNONE
5880 then pr2 (profile_diagnostic ());
5881 erase_temp_files ();
5882 )
5883 )
5884 (* let _ = if not !Sys.interactive then (main ()) *)
5885
5886
5887 (* based on code found in cameleon from maxence guesdon *)
5888 let md5sum_of_string s =
5889 let com = spf "echo %s | md5sum | cut -d\" \" -f 1"
5890 (Filename.quote s)
5891 in
5892 match cmd_to_list com with
5893 | [s] ->
5894 (*pr2 s;*)
5895 s
5896 | _ -> failwith "md5sum_of_string wrong output"
5897
5898
5899 (*****************************************************************************)
5900 (* Misc/test *)
5901 (*****************************************************************************)
5902
5903 let (generic_print: 'a -> string -> string) = fun v typ ->
5904 write_value v "/tmp/generic_print";
5905 command2
5906 ("printf 'let (v:" ^ typ ^ ")= Common.get_value \"/tmp/generic_print\" " ^
5907 " in v;;' " ^
5908 " | calc.top > /tmp/result_generic_print");
5909 cat "/tmp/result_generic_print"
5910 +> drop_while (fun e -> not (e =~ "^#.*")) +> tail
5911 +> unlines
5912 +> (fun s ->
5913 if (s =~ ".*= \\(.+\\)")
5914 then matched1 s
5915 else "error in generic_print, not good format:" ^ s)
5916
5917 (* let main () = pr (generic_print [1;2;3;4] "int list") *)
5918
5919 class ['a] olist (ys: 'a list) =
5920 object(o)
5921 val xs = ys
5922 method view = xs
5923 (* method fold f a = List.fold_left f a xs *)
5924 method fold : 'b. ('b -> 'a -> 'b) -> 'b -> 'b =
5925 fun f accu -> List.fold_left f accu xs
5926 end
5927
5928
5929 (* let _ = write_value ((new setb[])#add 1) "/tmp/test" *)
5930 let typing_sux_test () =
5931 let x = Obj.magic [1;2;3] in
5932 let f1 xs = List.iter print_int xs in
5933 let f2 xs = List.iter print_string xs in
5934 (f1 x; f2 x)
5935
5936 (* let (test: 'a osetb -> 'a ocollection) = fun o -> (o :> 'a ocollection) *)
5937 (* let _ = test (new osetb (Setb.empty)) *)