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