3 * Copyright (C) 1998-2009 Yoann Padioleau
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * version 2.1 as published by the Free Software Foundation, with the
8 * special exception on linking described in file license.txt.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
13 * license.txt for more details.
16 (*****************************************************************************)
18 (*****************************************************************************)
22 (* ---------------------------------------------------------------------- *)
23 (* Maybe could split common.ml and use include tricks as in ofullcommon.ml or
24 * Jane Street core lib. But then harder to bundle simple scripts like my
25 * make_full_linux_kernel.ml because would then need to pass all the files
26 * either to ocamlc or either to some #load. Also as the code of many
27 * functions depends on other functions from this common, it would
28 * be tedious to add those dependencies. Here simpler (have just the
29 * pb of the Prelude, but it's a small problem).
31 * pixel means code from Pascal Rigaux
32 * julia means code from Julia Lawall
34 (* ---------------------------------------------------------------------- *)
36 (*****************************************************************************)
38 (*****************************************************************************)
41 * - Pervasives, of course
51 * - =, <=, max min, abs, ...
52 * - List.rev, List.mem, List.partition,
53 * - List.fold*, List.concat, ...
54 * - Str.global_replace
55 * - Filename.is_relative
56 * - String.uppercase, String.lowercase
59 * The Format library allows to hide passing an indent_level variable.
60 * You use as usual the print_string function except that there is
61 * this automatic indent_level variable handled for you (and maybe
62 * more services). src: julia in coccinelle unparse_cocci.
66 * - ocamlgtk, and gtksourceview
77 * Many functions in this file were inspired by Haskell or Lisp librairies.
80 (*****************************************************************************)
82 (*****************************************************************************)
84 (* The following functions should be in their respective sections but
85 * because some functions in some sections use functions in other
86 * sections, and because I don't want to take care of the order of
87 * those sections, of those dependencies, I put the functions causing
88 * dependency problem here. C is better than caml on this with the
89 * ability to declare prototype, enabling some form of forward
96 exception UnixExit
of int
98 let rec (do_n
: int -> (unit -> unit) -> unit) = fun i f
->
99 if i
= 0 then () else (f
(); do_n
(i
-1) f
)
100 let rec (foldn
: ('a
-> int -> 'a
) -> 'a
-> int -> 'a
) = fun f acc i
->
101 if i
= 0 then acc
else foldn f
(f acc i
) (i
-1)
103 let sum_int = List.fold_left
(+) 0
105 (* could really call it 'for' :) *)
106 let fold_left_with_index f acc
=
107 let rec fold_lwi_aux acc n
= function
109 | x
::xs
-> fold_lwi_aux (f acc x n
) (n
+1) xs
110 in fold_lwi_aux acc
0
116 | (_
,[]) -> failwith
"drop: not enough"
117 | (n
,x
::xs
) -> drop (n
-1) xs
119 let rec enum_orig x n
= if x
= n
then [n
] else x
::enum_orig (x
+1) n
123 then failwith
(Printf.sprintf
"bad values in enum, expect %d <= %d" x n
);
124 let rec enum_aux acc x n
=
125 if x
= n
then n
::acc
else enum_aux (x
::acc
) (x
+1) n
127 List.rev
(enum_aux [] x n
)
132 | (_
,[]) -> failwith
"take: not enough"
133 | (n
,x
::xs
) -> x
::take (n
-1) xs
136 let last_n n l
= List.rev
(take n
(List.rev l
))
137 let last l
= List.hd
(last_n 1 l
)
140 let (list_of_string
: string -> char list
) = function
142 | s
-> (enum 0 ((String.length s
) - 1) +> List.map
(String.get s
))
144 let (lines
: string -> string list
) = fun s
->
145 let rec lines_aux = function
147 | [x
] -> if x
= "" then [] else [x
]
151 Str.split_delim
(Str.regexp
"\n") s
+> lines_aux
157 let null xs
= match xs
with [] -> true | _
-> false
162 let debugger = ref false
164 let unwind_protect f cleanup
=
165 if !debugger then f
() else
167 with e
-> begin cleanup e
; raise e
end
169 let finalize f cleanup
=
170 if !debugger then f
() else
179 let command2 s
= ignore
(Sys.command s
)
182 let (matched
: int -> string -> string) = fun i s
->
183 Str.matched_group i s
185 let matched1 = fun s
-> matched
1 s
186 let matched2 = fun s
-> (matched
1 s
, matched
2 s
)
187 let matched3 = fun s
-> (matched
1 s
, matched
2 s
, matched
3 s
)
188 let matched4 = fun s
-> (matched
1 s
, matched
2 s
, matched
3 s
, matched
4 s
)
189 let matched5 = fun s
-> (matched
1 s
, matched
2 s
, matched
3 s
, matched
4 s
, matched
5 s
)
190 let matched6 = fun s
-> (matched
1 s
, matched
2 s
, matched
3 s
, matched
4 s
, matched
5 s
, matched
6 s
)
191 let matched7 = fun s
-> (matched
1 s
, matched
2 s
, matched
3 s
, matched
4 s
, matched
5 s
, matched
6 s
, matched
7 s
)
193 let (with_open_stringbuf
: (((string -> unit) * Buffer.t
) -> unit) -> string) =
195 let buf = Buffer.create
1000 in
196 let pr s
= Buffer.add_string
buf (s ^
"\n") in
201 let foldl1 p
= function x
::xs
-> List.fold_left p x xs
| _
-> failwith
"foldl1"
203 (*****************************************************************************)
204 (* Debugging/logging *)
205 (*****************************************************************************)
207 (* I used this in coccinelle where the huge logging of stuff ask for
208 * a more organized solution that use more visual indentation hints.
210 * todo? could maybe use log4j instead ? or use Format module more
214 let _tab_level_print = ref 0
218 let _prefix_pr = ref ""
221 _tab_level_print := !_tab_level_print + _tab_indent;
223 (fun () -> _tab_level_print := !_tab_level_print - _tab_indent;)
227 print_string
!_prefix_pr;
228 do_n
!_tab_level_print (fun () -> print_string
" ");
234 print_string
!_prefix_pr;
235 do_n
!_tab_level_print (fun () -> print_string
" ");
244 let _chan_pr2 = ref (None
: out_channel
option)
246 let out_chan_pr2 ?
(newline
=true) s
=
247 match !_chan_pr2 with
250 output_string chan
(s ^
(if newline
then "\n" else ""));
255 prerr_string
!_prefix_pr;
256 do_n
!_tab_level_print (fun () -> prerr_string
" ");
264 prerr_string
!_prefix_pr;
265 do_n
!_tab_level_print (fun () -> prerr_string
" ");
268 out_chan_pr2 ~newline
:false s
;
272 let pr_xxxxxxxxxxxxxxxxx () =
273 pr "-----------------------------------------------------------------------"
275 let pr2_xxxxxxxxxxxxxxxxx () =
276 pr2 "-----------------------------------------------------------------------"
279 let reset_pr_indent () =
280 _tab_level_print := 0
283 * let pr s = (print_string s; print_string "\n"; flush stdout)
284 * let pr2 s = (prerr_string s; prerr_string "\n"; flush stderr)
287 (* ---------------------------------------------------------------------- *)
289 (* I can not use the _xxx ref tech that I use for common_extra.ml here because
290 * ocaml don't like the polymorphism of Dumper mixed with refs.
292 * let (_dump_func : ('a -> string) ref) = ref
293 * (fun x -> failwith "no dump yet, have you included common_extra.cmo?")
294 * let (dump : 'a -> string) = fun x ->
297 * So I have included directly dumper.ml in common.ml. It's more practical
298 * when want to give script that use my common.ml, I just have to give
302 (* start of dumper.ml *)
304 (* Dump an OCaml value into a printable string.
305 * By Richard W.M. Jones (rich@annexia.org).
306 * dumper.ml 1.2 2005/02/06 12:38:21 rich Exp
313 string_of_int
(magic r
: int)
315 let rec get_fields acc
= function
317 | n
-> let n = n-1 in get_fields (field r
n :: acc
) n
321 if (magic r
: int) = 0 then true (* [] *)
324 let s = size r
and t
= tag r
in
325 if t
= 0 && s = 2 then is_list (field r
1) (* h :: t *)
331 else let h = field r
0 and t
= get_list (field r
1) in h :: t
334 (* XXX In future, print the address of value 'r'. Not possible in
335 * pure OCaml at the moment.
340 let s = size r
and t
= tag r
in
342 (* From the tag, determine the type of block. *)
343 if is_list r
then ( (* List. *)
344 let fields = get_list r
in
345 "[" ^
String.concat
"; " (List.map
dump fields) ^
"]"
347 else if t
= 0 then ( (* Tuple, array, record. *)
348 let fields = get_fields [] s in
349 "(" ^
String.concat
", " (List.map
dump fields) ^
")"
352 (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
353 * clear if very large constructed values could have the same
355 else if t
= lazy_tag
then opaque "lazy"
356 else if t
= closure_tag
then opaque "closure"
357 else if t
= object_tag
then ( (* Object. *)
358 let fields = get_fields [] s in
359 let clasz, id
, slots
=
360 match fields with h::h'
::t
-> h, h'
, t
| _
-> assert false in
361 (* No information on decoding the class (first field). So just print
362 * out the ID and the slots.
364 "Object #" ^
dump id ^
365 " (" ^
String.concat
", " (List.map
dump slots
) ^
")"
367 else if t
= infix_tag
then opaque "infix"
368 else if t
= forward_tag
then opaque "forward"
370 else if t
< no_scan_tag
then ( (* Constructed value. *)
371 let fields = get_fields [] s in
372 "Tag" ^ string_of_int t ^
373 " (" ^
String.concat
", " (List.map
dump fields) ^
")"
375 else if t
= string_tag
then (
376 "\"" ^
String.escaped
(magic r
: string) ^
"\""
378 else if t
= double_tag
then (
379 string_of_float
(magic r
: float)
381 else if t
= abstract_tag
then opaque "abstract"
382 else if t
= custom_tag
then opaque "custom"
383 else if t
= final_tag
then opaque "final"
384 else failwith
("dump: impossible tag (" ^ string_of_int t ^
")")
387 let dump v
= dump (repr v
)
389 (* end of dumper.ml *)
392 let (dump : 'a -> string) = fun x ->
397 (* ---------------------------------------------------------------------- *)
398 let pr2_gen x
= pr2 (dump x
)
402 (* ---------------------------------------------------------------------- *)
405 let _already_printed = Hashtbl.create
101
406 let disable_pr2_once = ref false
409 if !disable_pr2_once then pr2 s
411 if not
(Hashtbl.mem
_already_printed s)
413 Hashtbl.add
_already_printed s true;
417 let pr2_once s = xxx_once pr2 s
419 (* ---------------------------------------------------------------------- *)
420 let mk_pr2_wrappers aref
=
425 (* just to the log file *)
432 xxx_once out_chan_pr2 s
437 (* ---------------------------------------------------------------------- *)
438 (* could also be in File section *)
440 let redirect_stdout_stderr file f
=
442 let chan = open_out file
in
443 let descr = Unix.descr_of_out_channel
chan in
445 let saveout = Unix.dup
Unix.stdout
in
446 let saveerr = Unix.dup
Unix.stderr
in
447 Unix.dup2
descr Unix.stdout
;
448 Unix.dup2
descr Unix.stderr
;
449 flush stdout
; flush stderr
;
451 flush stdout
; flush stderr
;
452 Unix.dup2
saveout Unix.stdout
;
453 Unix.dup2
saveerr Unix.stderr
;
457 let redirect_stdin file f
=
459 let chan = open_in file
in
460 let descr = Unix.descr_of_in_channel
chan in
462 let savein = Unix.dup
Unix.stdin
in
463 Unix.dup2
descr Unix.stdin
;
465 Unix.dup2
savein Unix.stdin
;
469 let redirect_stdin_opt optfile f
=
472 | Some infile
-> redirect_stdin infile f
476 let with_pr2_to_string f =
480 (* ---------------------------------------------------------------------- *)
484 (* cf common.mli, fprintf, printf, eprintf, sprintf.
485 * also what is this ?
486 * val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a
487 * val kprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b
497 (* ---------------------------------------------------------------------- *)
499 let _chan = ref stderr
500 let start_log_file () =
501 let filename = (spf "/tmp/debugml%d:%d" (Unix.getuid
()) (Unix.getpid
())) in
502 pr2 (spf "now using %s for logging" filename);
503 _chan := open_out
filename
506 let dolog s = output_string
!_chan (s ^
"\n"); flush
!_chan
508 let verbose_level = ref 1
509 let log s = if !verbose_level >= 1 then dolog s
510 let log2 s = if !verbose_level >= 2 then dolog s
511 let log3 s = if !verbose_level >= 3 then dolog s
512 let log4 s = if !verbose_level >= 4 then dolog s
514 let if_log f
= if !verbose_level >= 1 then f
()
515 let if_log2 f
= if !verbose_level >= 2 then f
()
516 let if_log3 f
= if !verbose_level >= 3 then f
()
517 let if_log4 f
= if !verbose_level >= 4 then f
()
519 (* ---------------------------------------------------------------------- *)
521 let pause () = (pr2 "pause: type return"; ignore
(read_line
()))
523 (* src: from getopt from frish *)
524 let bip () = Printf.printf
"\007"; flush stdout
525 let wait () = Unix.sleep
1
527 (* was used by fix_caml *)
528 let _trace_var = ref 0
529 let add_var() = incr
_trace_var
530 let dec_var() = decr
_trace_var
531 let get_var() = !_trace_var
533 let (print_n
: int -> string -> unit) = fun i
s ->
534 do_n i
(fun () -> print_string
s)
535 let (printerr_n
: int -> string -> unit) = fun i
s ->
536 do_n i
(fun () -> prerr_string
s)
538 let _debug = ref true
539 let debugon () = _debug := true
540 let debugoff () = _debug := false
541 let debug f
= if !_debug then f
() else ()
546 * let debugger = ref false
550 (*****************************************************************************)
552 (*****************************************************************************)
555 command2("grep VmData /proc/" ^ string_of_int
(Unix.getpid
()) ^
"/status")
558 let stat = Gc.stat() in
559 let conv_mo x
= x
* 4 / 1000000 in
560 Printf.sprintf
"maximal = %d Mo\n" (conv_mo stat.Gc.top_heap_words
) ^
561 Printf.sprintf
"current = %d Mo\n" (conv_mo stat.Gc.heap_words
) ^
562 Printf.sprintf
"lives = %d Mo\n" (conv_mo stat.Gc.live_words
)
563 (* Printf.printf "fragments = %d Mo\n" (conv_mo stat.Gc.fragments); *)
566 "sys:" ^
(string_of_float
(Sys.time
())) ^
" seconds" ^
568 (let tm = Unix.time
() +> Unix.gmtime
in
569 tm.Unix.tm_min
+> string_of_int ^
" min:" ^
570 tm.Unix.tm_sec
+> string_of_int ^
".00 seconds")
578 let count1 () = incr
_count1
579 let count2 () = incr
_count2
580 let count3 () = incr
_count3
581 let count4 () = incr
_count4
582 let count5 () = incr
_count5
584 let profile_diagnostic_basic () =
586 "count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\ncount5 = %d\n"
587 !_count1 !_count2 !_count3 !_count4 !_count5
592 (* let _ = Timing () in *)
594 (* let _ = Timing () in *)
597 (* ---------------------------------------------------------------------- *)
599 type prof
= PALL
| PNONE
| PSOME
of string list
600 let profile = ref PNONE
601 let show_trace_profile = ref false
603 let check_profile category
=
607 | PSOME l
-> List.mem category l
609 let _profile_table = ref (Hashtbl.create
100)
611 let adjust_profile_entry category difftime
=
612 let (xtime
, xcount
) =
613 (try Hashtbl.find
!_profile_table category
615 let xtime = ref 0.0 in
616 let xcount = ref 0 in
617 Hashtbl.add
!_profile_table category
(xtime, xcount);
620 xtime := !xtime +. difftime
;
621 xcount := !xcount + 1;
624 let profile_start category
= failwith
"todo"
625 let profile_end category
= failwith
"todo"
628 (* subtil: don't forget to give all argumens to f, otherwise partial app
629 * and will profile nothing.
631 * todo: try also detect when complexity augment each time, so can
632 * detect the situation for a function gets worse and worse ?
634 let profile_code category f
=
635 if not
(check_profile category
)
638 if !show_trace_profile then pr2 (spf "p: %s" category
);
639 let t = Unix.gettimeofday
() in
642 with Timeout
-> None
, "*"
644 let category = prefix ^
category in (* add a '*' to indicate timeout func *)
645 let t'
= Unix.gettimeofday
() in
647 adjust_profile_entry category (t'
-. t);
650 | None
-> raise Timeout
655 let _is_in_exclusif = ref (None
: string option)
657 let profile_code_exclusif category f
=
658 if not
(check_profile category)
662 match !_is_in_exclusif with
664 failwith
(spf "profile_code_exclusif: %s but already in %s " category s);
666 _is_in_exclusif := (Some
category);
669 profile_code category f
672 _is_in_exclusif := None
677 let profile_code_inside_exclusif_ok category f
=
681 (* todo: also put % ? also add % to see if coherent numbers *)
682 let profile_diagnostic () =
683 if !profile = PNONE
then "" else
685 Hashtbl.fold
(fun k v acc
-> (k
,v
)::acc
) !_profile_table []
686 +> List.sort
(fun (k1
, (t1
,n1
)) (k2
, (t2
,n2
)) -> compare t2 t1
)
688 with_open_stringbuf
(fun (pr,_) ->
689 pr "---------------------";
690 pr "profiling result";
691 pr "---------------------";
692 xs +> List.iter
(fun (k
, (t,n)) ->
693 pr (sprintf
"%-40s : %10.3f sec %10d count" k
!t !n)
699 let report_if_take_time timethreshold
s f
=
700 let t = Unix.gettimeofday
() in
702 let t'
= Unix.gettimeofday
() in
703 if (t'
-. t > float_of_int timethreshold
)
704 then pr2 (sprintf
"NOTE: this code takes more than: %ds %s" timethreshold
s);
707 let profile_code2 category f
=
708 profile_code category (fun () ->
710 then pr2 ("starting: " ^
category);
711 let t = Unix.gettimeofday
() in
713 let t'
= Unix.gettimeofday
() in
715 then pr2 (spf "ending: %s, %fs" category (t'
-. t));
720 (*****************************************************************************)
722 (*****************************************************************************)
723 let example b
= assert b
725 let _ex1 = example (enum 1 4 = [1;2;3;4])
727 let assert_equal a b
=
729 then failwith
("assert_equal: those 2 values are not equal:\n\t" ^
730 (dump a
) ^
"\n\t" ^
(dump b
) ^
"\n")
732 let (example2
: string -> bool -> unit) = fun s b
->
733 try assert b
with x -> failwith
s
735 (*-------------------------------------------------------------------*)
736 let _list_bool = ref []
738 let (example3
: string -> bool -> unit) = fun s b
->
739 _list_bool := (s,b
)::(!_list_bool)
741 (* could introduce a fun () otherwise the calculus is made at compile time
742 * and this can be long. This would require to redefine test_all.
743 * let (example3: string -> (unit -> bool) -> unit) = fun s func ->
744 * _list_bool := (s,func):: (!_list_bool)
746 * I would like to do as a func that take 2 terms, and make an = over it
747 * avoid to add this ugly fun (), but pb of type, cant do that :(
751 let (test_all
: unit -> unit) = fun () ->
752 List.iter
(fun (s, b
) ->
753 Printf.printf
"%s: %s\n" s (if b
then "passed" else "failed")
756 let (test
: string -> unit) = fun s ->
757 Printf.printf
"%s: %s\n" s
758 (if (List.assoc
s (!_list_bool)) then "passed" else "failed")
760 let _ex = example3
"++" ([1;2]++[3;4;5] = [1;2;3;4;5])
762 (*-------------------------------------------------------------------*)
763 (* Regression testing *)
764 (*-------------------------------------------------------------------*)
766 (* cf end of file. It uses too many other common functions so I
767 * have put the code at the end of this file.
772 (* todo? take code from julien signoles in calendar-2.0.2/tests *)
775 (* Generic functions used in the tests. *)
777 val reset
: unit -> unit
778 val nb_ok
: unit -> int
779 val nb_bug
: unit -> int
780 val test
: bool -> string -> unit
781 val test_exn
: 'a
Lazy.t -> string -> unit
785 let ok () = incr
ok_ref
786 let nb_ok () = !ok_ref
789 let bug () = incr
bug_ref
790 let nb_bug () = !bug_ref
797 if x then ok () else begin Printf.printf
"%s\n" s; bug () end;;
801 ignore
(Lazy.force
x);
802 Printf.printf
"%s\n" s;
809 (*****************************************************************************)
810 (* Quickcheck like (sfl) *)
811 (*****************************************************************************)
813 (* Better than quickcheck, cos cant do a test_all_prop in haskell cos
814 * prop were functions, whereas here we have not prop_Unix x = ... but
817 * How to do without overloading ? objet ? can pass a generator as a
818 * parameter, mais lourd, prefer automatic inferring of the
819 * generator? But at the same time quickcheck does not do better cos
820 * we must explictly type the property. So between a
821 * prop_unit:: [Int] -> [Int] -> bool ...
822 * prop_unit x = reverse [x] == [x]
824 * let _ = laws "unit" (fun x -> reverse [x] = [x]) (listg intg)
825 * there is no real differences.
827 * Yes I define typeg generator but quickcheck too, he must define
828 * class instance. I emulate the context Gen a => Gen [a] by making
829 * listg take as a param a type generator. Moreover I have not the pb of
830 * monad. I can do random independently, so my code is more simple
831 * I think than the haskell code of quickcheck.
833 * update: apparently Jane Street have copied some of my code for their
834 * Ounit_util.ml and quichcheck.ml in their Core library :)
837 (*---------------------------------------------------------------------------*)
839 (*---------------------------------------------------------------------------*)
840 type 'a gen
= unit -> 'a
842 let (ig
: int gen
) = fun () ->
844 let (lg
: ('a gen
) -> ('a list
) gen
) = fun gen
() ->
845 foldn
(fun acc i
-> (gen
())::acc
) [] (Random.int 10)
846 let (pg
: ('a gen
) -> ('b gen
) -> ('a
* 'b
) gen
) = fun gen1 gen2
() ->
849 let (ng
: (string gen
)) = fun () ->
850 "a" ^
(string_of_int
(ig
()))
852 let (oneofl
: ('a list
) -> 'a gen
) = fun xs () ->
853 List.nth
xs (Random.int (List.length
xs))
854 (* let oneofl l = oneof (List.map always l) *)
856 let (oneof
: (('a gen
) list
) -> 'a gen
) = fun xs ->
857 List.nth
xs (Random.int (List.length
xs))
859 let (always
: 'a
-> 'a gen
) = fun e
() -> e
861 let (frequency
: ((int * ('a gen
)) list
) -> 'a gen
) = fun xs ->
862 let sums = sum_int (List.map fst
xs) in
863 let i = Random.int sums in
864 let rec freq_aux acc
= function
865 | (x,g
)::xs -> if i < acc
+x then g
else freq_aux (acc
+x) xs
866 | _ -> failwith
"frequency"
869 let frequencyl l
= frequency
(List.map
(fun (i,e
) -> (i,always e
)) l
)
872 let b = oneof [always true; always false] ()
873 let b = frequency [3, always true; 2, always false] ()
877 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneofl [[]; lg gen ()]
879 * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneof [always []; lg gen]
881 * because caml is not as lazy as haskell :( fix the pb by introducing a size
882 * limit. take the bounds/size as parameter. morover this is needed for
885 * how make a bintreeg ?? we need recursion
887 * let rec (bintreeg: ('a gen) -> ('a bintree) gen) = fun gen () ->
889 * if n = 0 then (Leaf (gen ()))
890 * else frequencyl [1, Leaf (gen ()); 4, Branch ((aux (n / 2)), aux (n / 2))]
897 (*---------------------------------------------------------------------------*)
899 (*---------------------------------------------------------------------------*)
901 (* todo: a test_all_laws, better syntax (done already a little with ig in
902 * place of intg. En cas d'erreur, print the arg that not respect
904 * todo: with monitoring, as in haskell, laws = laws2, no need for 2 func,
907 * todo classify, collect, forall
911 (* return None when good, and Just the_problematic_case when bad *)
912 let (laws
: string -> ('a
-> bool) -> ('a gen
) -> 'a
option) = fun s func gen
->
913 let res = foldn
(fun acc
i -> let n = gen
() in (n, func
n)::acc
) [] 1000 in
914 let res = List.filter
(fun (x,b) -> not
b) res in
915 if res = [] then None
else Some
(fst
(List.hd
res))
917 let rec (statistic_number
: ('a list
) -> (int * 'a
) list
) = function
919 | x::xs -> let (splitg
, splitd
) = List.partition
(fun y
-> y
= x) xs in
920 (1+(List.length splitg
), x)::(statistic_number splitd
)
923 let (statistic
: ('a list
) -> (int * 'a
) list
) = fun xs ->
924 let stat_num = statistic_number
xs in
925 let totals = sum_int (List.map fst
stat_num) in
926 List.map
(fun (i, v
) -> ((i * 100) / totals), v
) stat_num
929 string -> ('a
-> (bool * '
b)) -> ('a gen
) ->
930 ('a
option * ((int * '
b) list
))) =
932 let res = foldn
(fun acc
i -> let n = gen
() in (n, func
n)::acc
) [] 1000 in
933 let stat = statistic
(List.map
(fun (x,(b,v
)) -> v
) res) in
934 let res = List.filter
(fun (x,(b,v
)) -> not
b) res in
935 if res = [] then (None
, stat) else (Some
(fst
(List.hd
res)), stat)
939 let b = laws "unit" (fun x -> reverse [x] = [x] )ig
940 let b = laws "app " (fun (xs,ys) -> reverse (xs++ys) = reverse ys++reverse xs)(pg (lg ig)(lg ig))
941 let b = laws "rev " (fun xs -> reverse (reverse xs) = xs )(lg ig)
942 let b = laws "appb" (fun (xs,ys) -> reverse (xs++ys) = reverse xs++reverse ys)(pg (lg ig)(lg ig))
943 let b = laws "max" (fun (x,y) -> x <= y ==> (max x y = y) )(pg ig ig)
945 let b = laws2 "max" (fun (x,y) -> ((x <= y ==> (max x y = y)), x <= y))(pg ig ig)
949 (* todo, do with coarbitrary ?? idea is that given a 'a, generate a 'b
950 * depending of 'a and gen 'b, that is modify gen 'b, what is important is
951 * that each time given the same 'a, we must get the same 'b !!!
955 let (fg: ('a gen) -> ('b gen) -> ('a -> 'b) gen) = fun gen1 gen2 () ->
956 let b = laws "funs" (fun (f,g,h) -> x <= y ==> (max x y = y) )(pg ig ig)
960 let one_of xs = List.nth xs (Random.int (List.length xs))
962 if empty xs then failwith "Take_one: empty list"
964 let i = Random.int (List.length xs) in
965 List.nth xs i, filter_index (fun j _ -> i <> j) xs
968 (*****************************************************************************)
970 (*****************************************************************************)
972 let get_value filename =
973 let chan = open_in
filename in
974 let x = input_value
chan in (* <=> Marshal.from_channel *)
977 let write_value valu
filename =
978 let chan = open_out
filename in
979 (output_value
chan valu
; (* <=> Marshal.to_channel *)
980 (* Marshal.to_channel chan valu [Marshal.Closures]; *)
983 let write_back func
filename =
984 write_value (func
(get_value filename)) filename
987 let read_value f
= get_value f
990 let marshal__to_string2 v flags
=
991 Marshal.to_string v flags
992 let marshal__to_string a
b =
993 profile_code "Marshalling" (fun () -> marshal__to_string2 a
b)
995 let marshal__from_string2 v flags
=
996 Marshal.from_string v flags
997 let marshal__from_string a
b =
998 profile_code "Marshalling" (fun () -> marshal__from_string2 a
b)
1002 (*****************************************************************************)
1004 (*****************************************************************************)
1005 let _counter = ref 0
1006 let counter () = (_counter := !_counter +1; !_counter)
1008 let _counter2 = ref 0
1009 let counter2 () = (_counter2 := !_counter2 +1; !_counter2)
1011 let _counter3 = ref 0
1012 let counter3 () = (_counter3 := !_counter3 +1; !_counter3)
1014 type timestamp
= int
1016 (*****************************************************************************)
1018 (*****************************************************************************)
1019 (* To work with the macro system autogenerated string_of and print_ function
1020 (kind of deriving a la haskell) *)
1022 (* int, bool, char, float, ref ?, string *)
1024 let string_of_string s = "\"" ^
s "\""
1026 let string_of_list f
xs =
1027 "[" ^
(xs +> List.map f
+> String.concat
";" ) ^
"]"
1029 let string_of_unit () = "()"
1031 let string_of_array f
xs =
1032 "[|" ^
(xs +> Array.to_list
+> List.map f
+> String.concat
";") ^
"|]"
1034 let string_of_option f
= function
1036 | Some
x -> "Some " ^
(f
x)
1041 let print_bool x = print_string
(if x then "True" else "False")
1043 let print_option pr = function
1044 | None
-> print_string
"None"
1045 | Some
x -> print_string
"Some ("; pr x; print_string
")"
1047 let print_list pr xs =
1050 List.iter
(fun x -> pr x; print_string
",") xs;
1055 let (string_of_list: char list -> string) =
1056 List.fold_left (fun acc x -> acc^(Char.escaped x)) ""
1060 let rec print_between between fn
= function
1063 | x::xs -> fn
x; between
(); print_between between fn
xs
1068 let adjust_pp_with_indent f
=
1069 Format.open_box
!_tab_level_print;
1070 (*Format.force_newline();*)
1072 Format.close_box
();
1073 Format.print_newline
()
1075 let adjust_pp_with_indent_and_header s f
=
1076 Format.open_box
(!_tab_level_print + String.length
s);
1077 do_n
!_tab_level_print (fun () -> Format.print_string
" ");
1078 Format.print_string
s;
1080 Format.close_box
();
1081 Format.print_newline
()
1085 let pp_do_in_box f
= Format.open_box
1; f
(); Format.close_box
()
1086 let pp_do_in_zero_box f
= Format.open_box
0; f
(); Format.close_box
()
1091 Format.close_box
();
1094 let pp s = Format.print_string
s
1096 let mk_str_func_of_assoc_conv xs =
1097 let swap (x,y
) = (y
,x) in
1100 let xs'
= List.map
swap xs in
1109 (* julia: convert something printed using format to print into a string *)
1110 (* now at bottom of file
1111 let format_to_string f =
1117 (*****************************************************************************)
1119 (*****************************************************************************)
1121 (* put your macro in macro.ml4, and you can test it interactivly as in lisp *)
1122 let macro_expand s =
1123 let c = open_out
"/tmp/ttttt.ml" in
1125 output_string
c s; close_out
c;
1126 command2 ("ocamlc -c -pp 'camlp4o pa_extend.cmo q_MLast.cmo -impl' " ^
1127 "-I +camlp4 -impl macro.ml4");
1128 command2 "camlp4o ./macro.cmo pr_o.cmo /tmp/ttttt.ml";
1129 command2 "rm -f /tmp/ttttt.ml";
1133 let t = macro_expand "{ x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x>2 and y<3}"
1134 let x = { x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x > 2 and y < 3}
1135 let t = macro_expand "{1 .. 10}"
1136 let x = {1 .. 10} +> List.map (fun i -> i)
1137 let t = macro_expand "[1;2] to append to [2;4]"
1138 let t = macro_expand "{x = 2; x = 3}"
1140 let t = macro_expand "type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)"
1145 (*****************************************************************************)
1146 (* Composition/Control *)
1147 (*****************************************************************************)
1149 (* I like the obj.func object notation. In OCaml cant use '.' so I use +>
1151 * update: it seems that F# agrees with me :) but they use |>
1155 * let (+>) o f = f o
1157 let (+!>) refo f
= refo
:= f
!refo
1159 * let ((@): 'a -> ('a -> 'b) -> 'b) = fun a b -> b a
1160 * let o f g x = f (g x)
1163 let ($
) f g
x = g
(f
x)
1164 let compose f g
x = f
(g
x)
1165 (* dont work :( let ( ° ) f g x = f(g(x)) *)
1167 (* trick to have something similar to the 1 `max` 4 haskell infix notation.
1168 by Keisuke Nakano on the caml mailing list.
1169 > let ( /* ) x y = y x
1170 > and ( */ ) x y = x y
1172 let ( <| ) x y = y x
1173 and ( |> ) x y = x y
1175 > Then we can make an infix operator <| f |> for a binary function f.
1178 let flip f
= fun a
b -> f
b a
1180 let curry f
x y
= f
(x,y
)
1181 let uncurry f
(a
,b) = f a
b
1185 let do_nothing () = ()
1187 let rec applyn n f
o = if n = 0 then o else applyn (n-1) f
(f
o)
1195 class ['a
] shared_variable_hook
(x:'a
) =
1197 val mutable data
= x
1198 val mutable registered
= []
1202 pr "refresh registered";
1203 registered
+> List.iter
(fun f
-> f
());
1206 method modify f
= self#set
(f self#get
)
1208 registered
<- f
:: registered
1211 (* src: from aop project. was called ptFix *)
1212 let rec fixpoint trans elem
=
1213 let image = trans elem
in
1215 then elem
(* point fixe *)
1216 else fixpoint trans
image
1218 (* le point fixe pour les objets. was called ptFixForObjetct *)
1219 let rec fixpoint_for_object trans elem
=
1220 let image = trans elem
in
1221 if (image#equal elem
) then elem
(* point fixe *)
1222 else fixpoint_for_object trans
image
1224 let (add_hook
: ('a
-> ('a
-> '
b) -> '
b) ref -> ('a
-> ('a
-> '
b) -> '
b) -> unit) =
1226 let oldvar = !var
in
1227 var
:= fun arg k
-> f arg
(fun x -> oldvar x k
)
1229 let (add_hook_action
: ('a
-> unit) -> ('a
-> unit) list
ref -> unit) =
1233 let (run_hooks_action
: 'a
-> ('a
-> unit) list
ref -> unit) =
1235 !hooks
+> List.iter
(fun f
-> try f obj
with _ -> ())
1238 type 'a mylazy
= (unit -> 'a
)
1241 let save_excursion reference f
=
1242 let old = !reference
in
1247 let save_excursion_and_disable reference f
=
1248 save_excursion reference
(fun () ->
1253 let save_excursion_and_enable reference f
=
1254 save_excursion reference
(fun () ->
1260 let memoized h k f
=
1261 try Hashtbl.find
h k
1269 let cache_in_ref myref f
=
1278 let already = ref false in
1281 then begin already := true; f
x end
1284 (* cache_file, cf below *)
1286 let before_leaving f
x =
1290 (* finalize, cf prelude *)
1294 let rec y f
= fun x -> f
(y f
) x
1296 (*****************************************************************************)
1298 (*****************************************************************************)
1300 (* from http://en.wikipedia.org/wiki/File_locking
1302 * "When using file locks, care must be taken to ensure that operations
1303 * are atomic. When creating the lock, the process must verify that it
1304 * does not exist and then create it, but without allowing another
1305 * process the opportunity to create it in the meantime. Various
1306 * schemes are used to implement this, such as taking advantage of
1307 * system calls designed for this purpose (but such system calls are
1308 * not usually available to shell scripts) or by creating the lock file
1309 * under a temporary name and then attempting to move it into place."
1311 * => can't use 'if(not (file_exist xxx)) then create_file xxx' because
1312 * file_exist/create_file are not in atomic section (classic problem).
1316 * "O_EXCL When used with O_CREAT, if the file already exists it
1317 * is an error and the open() will fail. In this context, a
1318 * symbolic link exists, regardless of where it points to.
1319 * O_EXCL is broken on NFS file systems; programs which
1320 * rely on it for performing locking tasks will contain a
1321 * race condition. The solution for performing atomic file
1322 * locking using a lockfile is to create a unique file on
1323 * the same file system (e.g., incorporating host- name and
1324 * pid), use link(2) to make a link to the lockfile. If
1325 * link(2) returns 0, the lock is successful. Otherwise,
1326 * use stat(2) on the unique file to check if its link
1327 * count has increased to 2, in which case the lock is also
1332 exception FileAlreadyLocked
1334 (* Racy if lock file on NFS!!! But still racy with recent Linux ? *)
1335 let acquire_file_lock filename =
1336 pr2 ("Locking file: " ^
filename);
1338 let _fd = Unix.openfile
filename [Unix.O_CREAT
;Unix.O_EXCL
] 0o777
in
1340 with Unix.Unix_error
(e, fm
, argm
) ->
1341 pr2 (spf "exn Unix_error: %s %s %s\n" (Unix.error_message
e) fm argm
);
1342 raise FileAlreadyLocked
1345 let release_file_lock filename =
1346 pr2 ("Releasing file: " ^
filename);
1347 Unix.unlink
filename;
1352 (*****************************************************************************)
1353 (* Error managment *)
1354 (*****************************************************************************)
1357 exception Impossible
1361 exception Multi_found
(* to be consistent with Not_found *)
1363 exception WrongFormat
of string
1365 (* old: let _TODO () = failwith "TODO", now via fix_caml with raise Todo *)
1367 let internal_error s = failwith
("internal error: "^
s)
1368 let error_cant_have x = internal_error ("cant have this case" ^
(dump x))
1369 let myassert cond
= if cond
then () else failwith
"assert error"
1373 (* before warning I was forced to do stuff like this:
1375 * let (fixed_int_to_posmap: fixed_int -> posmap) = fun fixed ->
1376 * let v = ((fix_to_i fixed) / (power 2 16)) in
1377 * let _ = Printf.printf "coord xy = %d\n" v in
1380 * The need for printf make me force to name stuff :(
1381 * How avoid ? use 'it' special keyword ?
1382 * In fact dont have to name it, use +> (fun v -> ...) so when want
1383 * erase debug just have to erase one line.
1385 let warning s v = (pr2 ("Warning: " ^
s ^
"; value = " ^
(dump v)); v)
1391 Printexc.to_string exn
1394 let string_of_exn exn
= exn_to_s exn
1397 (* want or of merd, but cant cos cant put die ... in b (strict call) *)
1398 let (|||) a
b = try a
with _ -> b
1400 (* emacs/lisp inspiration, (vouillon does that too in unison I think) *)
1403 * let unwind_protect f cleanup = ...
1404 * let finalize f cleanup = ...
1407 type error
= Error
of string
1409 (* sometimes to get help from ocaml compiler to tell me places where
1410 * I should update, we sometimes need to change some type from pair
1411 * to triple, hence this kind of fake type.
1416 (*****************************************************************************)
1418 (*****************************************************************************)
1420 let check_stack = ref true
1421 let check_stack_size limit
=
1422 if !check_stack then begin
1423 pr2 "checking stack size (do ulimit -s 50000 if problem)";
1427 else 1 + aux (i + 1)
1429 assert(aux 0 = limit
);
1433 let test_check_stack_size limit
=
1434 (* bytecode: 100000000 *)
1435 (* native: 10000000 *)
1436 check_stack_size (int_of_string limit
)
1439 (* only relevant in bytecode, in native the stacklimit is the os stacklimit
1440 * (adjustable by ulimit -s)
1442 let _init_gc_stack =
1443 Gc.set
{(Gc.get
()) with Gc.stack_limit
= 100 * 1024 * 1024}
1448 (* if process a big set of files then dont want get overflow in the middle
1449 * so for this we are ready to spend some extra time at the beginning that
1450 * could save far more later.
1452 let check_stack_nbfiles nbfiles
=
1454 then check_stack_size 10000000
1456 (*****************************************************************************)
1457 (* Arguments/options and command line (cocci and acomment) *)
1458 (*****************************************************************************)
1461 * Why define wrappers ? Arg not good enough ? Well the Arg.Rest is not that
1462 * good and I need a way sometimes to get a list of argument.
1464 * I could define maybe a new Arg.spec such as
1465 * | String_list of (string list -> unit), but the action may require
1466 * some flags to be set, so better to process this after all flags have
1467 * been set by parse_options. So have to split. Otherwise it would impose
1468 * an order of the options such as
1469 * -verbose_parsing -parse_c file1 file2. and I really like to use bash
1470 * history and add just at the end of my command a -profile for instance.
1473 * Why want a -action arg1 arg2 arg3 ? (which in turn requires this
1474 * convulated scheme ...) Why not use Arg.String action such as
1475 * "-parse_c", Arg.String (fun file -> ...) ?
1476 * I want something that looks like ocaml function but at the UNIX
1477 * command line level. So natural to have this scheme instead of
1478 * -taxo_file arg2 -sample_file arg3 -parse_c arg1.
1481 * Why not use the toplevel ?
1482 * - because to debug, ocamldebug is far superior to the toplevel
1483 * (can go back, can go directly to a specific point, etc).
1484 * I want a kind of testing at cmdline level.
1485 * - Also I don't have file completion when in the ocaml toplevel.
1486 * I have to type "/path/to/xxx" without help.
1489 * Why having variable flags ? Why use 'if !verbose_parsing then ...' ?
1490 * why not use strings and do stuff like the following
1491 * 'if (get_config "verbose_parsing") then ...'
1492 * Because I want to make the interface for flags easier for the code
1493 * that use it. The programmer should not be bothered wether this
1494 * flag is set via args cmd line or a config file, so I want to make it
1495 * as simple as possible, just use a global plain caml ref variable.
1497 * Same spirit a little for the action. Instead of having function such as
1498 * test_parsing_c, I could do it only via string. But I still prefer
1499 * to have plain caml test functions. Also it makes it easier to call
1500 * those functions from a toplevel for people who prefer the toplevel.
1503 * So have flag_spec and action_spec. And in flag have debug_xxx flags,
1504 * verbose_xxx flags and other flags.
1506 * I would like to not have to separate the -xxx actions spec from the
1507 * corresponding actions, but those actions may need more than one argument
1508 * and so have to wait for parse_options, which in turn need the options
1511 * Also I dont want to mix code with data structures, so it's better that the
1512 * options variable contain just a few stuff and have no side effects except
1513 * setting global variables.
1515 * Why not have a global variable such as Common.actions that
1516 * other modules modify ? No, I prefer to do less stuff behind programmer's
1517 * back so better to let the user merge the different options at call
1518 * site, but at least make it easier by providing shortcut for set of options.
1523 * todo? isn't unison or scott-mcpeak-lib-in-cil handles that kind of
1524 * stuff better ? That is the need to localize command line argument
1525 * while still being able to gathering them. Same for logging.
1526 * Similiar to the type prof = PALL | PNONE | PSOME of string list.
1527 * Same spirit of fine grain config in log4j ?
1529 * todo? how mercurial/cvs/git manage command line options ? because they
1530 * all have a kind of DSL around arguments with some common options,
1531 * specific options, conventions, etc.
1534 * todo? generate the corresponding noxxx options ?
1535 * todo? generate list of options and show their value ?
1537 * todo? make it possible to set this value via a config file ?
1542 type arg_spec_full
= Arg.key
* Arg.spec
* Arg.doc
1543 type cmdline_options
= arg_spec_full list
1545 (* the format is a list of triples:
1546 * (title of section * (optional) explanation of sections * options)
1548 type options_with_title
= string * string * arg_spec_full list
1549 type cmdline_sections
= options_with_title list
1552 (* ---------------------------------------------------------------------- *)
1554 (* now I use argv as I like at the call sites to show that
1555 * this function internally use argv.
1557 let parse_options options usage_msg argv
=
1558 let args = ref [] in
1560 Arg.parse_argv argv options
(fun file
-> args := file
::!args) usage_msg
;
1561 args := List.rev
!args;
1564 | Arg.Bad msg
-> eprintf
"%s" msg
; exit
2
1565 | Arg.Help msg
-> printf
"%s" msg
; exit
0
1571 let usage usage_msg options
=
1572 Arg.usage (Arg.align options
) usage_msg
1575 (* for coccinelle *)
1577 (* If you don't want the -help and --help that are appended by Arg.align *)
1579 Arg.align
xs +> List.rev
+> drop 2 +> List.rev
1582 let short_usage usage_msg ~short_opt
=
1583 usage usage_msg short_opt
1585 let long_usage usage_msg ~short_opt ~long_opt
=
1588 let all_options_with_title =
1589 (("main options", "", short_opt
)::long_opt
) in
1590 all_options_with_title +> List.iter
1591 (fun (title
, explanations
, xs) ->
1593 pr_xxxxxxxxxxxxxxxxx();
1594 if explanations
<> ""
1595 then begin pr explanations
; pr "" end;
1596 arg_align2 xs +> List.iter
(fun (key
,action
,s) ->
1604 (* copy paste of Arg.parse. Don't want the default -help msg *)
1605 let arg_parse2 l msg short_usage_fun
=
1606 let args = ref [] in
1607 let f = (fun file
-> args := file
::!args) in
1608 let l = Arg.align
l in
1610 Arg.parse_argv
Sys.argv
l f msg
;
1611 args := List.rev
!args;
1615 | Arg.Bad msg
-> (* eprintf "%s" msg; exit 2; *)
1616 let xs = lines msg
in
1617 (* take only head, it's where the error msg is *)
1620 raise
(UnixExit
(2))
1621 | Arg.Help msg
-> (* printf "%s" msg; exit 0; *)
1622 raise Impossible
(* -help is specified in speclist *)
1626 (* ---------------------------------------------------------------------- *)
1627 (* kind of unit testing framework, or toplevel like functionnality
1628 * at shell command line. I realize than in fact It follows a current trend
1629 * to have a main cmdline program where can then select different actions,
1630 * as in cvs/hg/git where do hg <action> <arguments>, and the shell even
1631 * use a curried syntax :)
1634 * Not-perfect-but-basic-feels-right: an action
1635 * spec looks like this:
1637 * let actions () = [
1638 * "-parse_taxo", " <file>",
1639 * Common.mk_action_1_arg test_parse_taxo;
1643 * Not-perfect-but-basic-feels-right because for such functionality we
1644 * need a way to transform a string into a caml function and pass arguments
1645 * and the preceding design does exactly that, even if then the
1646 * functions that use this design are not so convenient to use (there
1647 * are 2 places where we need to pass those data, in the options and in the
1650 * Also it's not too much intrusive. Still have an
1651 * action ref variable in the main.ml and can still use the previous
1652 * simpler way to do where the match args with in main.ml do the
1655 * Use like this at option place:
1656 * (Common.options_of_actions actionref (Test_parsing_c.actions())) ++
1657 * Use like this at dispatch action place:
1658 * | xs when List.mem !action (Common.action_list all_actions) ->
1659 * Common.do_action !action xs all_actions
1663 type flag_spec
= Arg.key
* Arg.spec
* Arg.doc
1664 type action_spec
= Arg.key
* Arg.doc
* action_func
1665 and action_func
= (string list
-> unit)
1667 type cmdline_actions
= action_spec list
1668 exception WrongNumberOfArguments
1670 let options_of_actions action_ref
actions =
1671 actions +> List.map
(fun (key
, doc
, _func
) ->
1672 (key
, (Arg.Unit
(fun () -> action_ref
:= key
)), doc
)
1675 let (action_list
: cmdline_actions
-> Arg.key list
) = fun xs ->
1676 List.map
(fun (a
,b,c) -> a
) xs
1678 let (do_action
: Arg.key
-> string list
(* args *) -> cmdline_actions
-> unit) =
1680 let assoc = xs +> List.map
(fun (a
,b,c) -> (a
,c)) in
1681 let action_func = List.assoc key
assoc in
1685 (* todo? if have a function with default argument ? would like a
1686 * mk_action_0_or_1_arg ?
1689 let mk_action_0_arg f =
1692 | _ -> raise WrongNumberOfArguments
1695 let mk_action_1_arg f =
1698 | _ -> raise WrongNumberOfArguments
1701 let mk_action_2_arg f =
1703 | [file1
;file2
] -> f file1 file2
1704 | _ -> raise WrongNumberOfArguments
1707 let mk_action_3_arg f =
1709 | [file1
;file2
;file3
] -> f file1 file2 file3
1710 | _ -> raise WrongNumberOfArguments
1713 let mk_action_n_arg f = f
1716 (*****************************************************************************)
1718 (*****************************************************************************)
1720 (* Using the generic (=) is tempting, but it backfires, so better avoid it *)
1722 (* To infer all the code that use an equal, and that should be
1723 * transformed, is not that easy, because (=) is used by many
1724 * functions, such as List.find, List.mem, and so on. So the strategy
1725 * is to turn what you were previously using into a function, because
1726 * (=) return an exception when applied to a function. Then you simply
1727 * use ocamldebug to infer where the code has to be transformed.
1730 (* src: caml mailing list ? *)
1731 let (=|=) : int -> int -> bool = (=)
1732 let (=<=) : char
-> char
-> bool = (=)
1733 let (=$
=) : string -> string -> bool = (=)
1734 let (=:=) : bool -> bool -> bool = (=)
1736 (* the evil generic (=). I define another symbol to more easily detect
1737 * it, cos the '=' sign is syntaxically overloaded in caml. It is also
1738 * used to define function.
1742 (* if really want to forbid to use '='
1745 let (=) () () = false
1754 (*###########################################################################*)
1755 (* And now basic types *)
1756 (*###########################################################################*)
1760 (*****************************************************************************)
1762 (*****************************************************************************)
1763 let (==>) b1 b2
= if b1
then b2
else true (* could use too => *)
1765 (* superseded by another <=> below
1766 let (<=>) a b = if a =*= b then 0 else if a < b then -1 else 1
1769 let xor a
b = not
(a
=*= b)
1772 (*****************************************************************************)
1774 (*****************************************************************************)
1776 let string_of_char c = String.make
1 c
1778 let is_single = String.contains
",;()[]{}_`"
1779 let is_symbol = String.contains
"!@#$%&*+./<=>?\\^|:-~"
1780 let is_space = String.contains
"\n\t "
1781 let cbetween min max
c =
1782 (int_of_char
c) <= (int_of_char max
) &&
1783 (int_of_char
c) >= (int_of_char min
)
1784 let is_upper = cbetween 'A' 'Z'
1785 let is_lower = cbetween 'a' 'z'
1786 let is_alpha c = is_upper c || is_lower c
1787 let is_digit = cbetween '
0' '
9'
1789 let string_of_chars cs
= cs
+> List.map
(String.make
1) +> String.concat
""
1793 (*****************************************************************************)
1795 (*****************************************************************************)
1797 (* since 3.08, div by 0 raise Div_by_rezo, and not anymore a hardware trap :)*)
1798 let (/!) x y = if y =|= 0 then (log "common.ml: div by 0"; 0) else x / y
1801 * let rec (do_n: int -> (unit -> unit) -> unit) = fun i f ->
1802 * if i = 0 then () else (f(); do_n (i-1) f)
1806 * let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i ->
1807 * if i = 0 then acc else foldn f (f acc i) (i-1)
1810 let sum_float = List.fold_left
(+.) 0.0
1811 let sum_int = List.fold_left
(+) 0
1813 let pi = 3.14159265358979323846
1818 let (deg_to_rad
: float -> float) = fun deg
->
1819 (deg
*. pi) /. 180.0
1821 let clampf = function
1822 | n when n < 0.0 -> 0.0
1823 | n when n > 1.0 -> 1.0
1826 let square x = x *. x
1828 let rec power x n = if n =|= 0 then 1 else x * power x (n-1)
1830 let between i min max
= i > min
&& i < max
1832 let (between_strict
: int -> int -> int -> bool) = fun a
b c ->
1836 let bitrange x p
= let v = power 2 p
in between x (-v) v
1839 let (prime1
: int -> int option) = fun x ->
1840 let rec prime1_aux n =
1841 if n =|= 1 then None
1843 if (x / n) * n =|= x then Some
n else prime1_aux (n-1)
1844 in if x =|= 1 then None
else if x < 0 then failwith
"negative" else prime1_aux (x-1)
1846 (* montant, better *)
1847 let (prime
: int -> int option) = fun x ->
1848 let rec prime_aux n =
1849 if n =|= x then None
1851 if (x / n) * n =|= x then Some
n else prime_aux (n+1)
1852 in if x =|= 1 then None
else if x < 0 then failwith
"negative" else prime_aux 2
1854 let sum xs = List.fold_left
(+) 0 xs
1855 let product = List.fold_left
( * ) 1
1859 let rec decompose x =
1864 | Some
n -> n::decompose (x / n)
1866 in assert (product (decompose x) =|= x); decompose x
1868 let mysquare x = x * x
1872 type compare
= Equal
| Inf
| Sup
1873 let (<=>) a
b = if a
=*= b then Equal
else if a
< b then Inf
else Sup
1874 let (<==>) a
b = if a
=*= b then 0 else if a
< b then -1 else 1
1879 let int_of_stringchar s =
1880 fold_left_with_index (fun acc
e i -> acc
+ (Char.code
e*(power 8 i))) 0 (List.rev
(list_of_string
s))
1882 let int_of_base s base
=
1883 fold_left_with_index (fun acc
e i ->
1884 let j = Char.code
e - Char.code '
0'
in
1885 if j >= base
then failwith
"not in good base"
1886 else acc
+ (j*(power base
i))
1888 0 (List.rev
(list_of_string
s))
1890 let int_of_stringbits s = int_of_base s 2
1891 let _ = example (int_of_stringbits "1011" =|= 1*8 + 1*2 + 1*1)
1893 let int_of_octal s = int_of_base s 8
1894 let _ = example (int_of_octal "017" =|= 15)
1896 (* let int_of_hex s = int_of_base s 16, NONONONO cos 'A' - '0' does not give 10 !! *)
1899 if String.length
s >= 2 && (String.get
s 0 =<= '
0'
) && is_digit (String.get
s 1)
1900 then int_of_octal s else int_of_string
s
1903 let (+=) ref v = ref := !ref + v
1904 let (-=) ref v = ref := !ref - v
1906 let pourcent x total
=
1908 let pourcent_float x total
=
1909 ((float_of_int
x) *. 100.0) /. (float_of_int total
)
1911 let pourcent_float_of_floats x total
=
1912 (x *. 100.0) /. total
1915 let pourcent_good_bad good bad
=
1916 (good
* 100) / (good
+ bad
)
1918 let pourcent_good_bad_float good bad
=
1919 (float_of_int good
*. 100.0) /. (float_of_int good
+. float_of_int bad
)
1921 type 'a max_with_elem
= int ref * 'a
ref
1922 let update_max_with_elem (aref
, aelem
) ~is_better
(newv
, newelem
) =
1923 if is_better newv aref
1929 (*****************************************************************************)
1930 (* Numeric/overloading *)
1931 (*****************************************************************************)
1934 NumDict
of (('a
-> 'a
-> 'a
) *
1939 let add (NumDict
(a
, m
, d
, n)) = a
;;
1940 let mul (NumDict
(a
, m
, d
, n)) = m
;;
1941 let div (NumDict
(a
, m
, d
, n)) = d
;;
1942 let neg (NumDict
(a
, m
, d
, n)) = n;;
1944 let numd_int = NumDict
(( + ),( * ),( / ),( ~
- ));;
1945 let numd_float = NumDict
(( +. ),( *. ), ( /. ),( ~
-. ));;
1947 let ( * ) x y = mul dict
x y in
1948 let ( / ) x y = div dict
x y in
1949 let ( + ) x y = add dict
x y in
1950 (* Now you can define all sorts of things in terms of *, /, + *)
1951 let f num
= (num
* num
) / (num
+ num
) in
1956 module ArithFloatInfix
= struct
1968 let (+=) ref v = ref := !ref + v
1969 let (-=) ref v = ref := !ref - v
1975 (*****************************************************************************)
1977 (*****************************************************************************)
1979 type 'a pair
= 'a
* 'a
1980 type 'a triple
= 'a
* 'a
* 'a
1982 let fst3 (x,_,_) = x
1983 let snd3 (_,y,_) = y
1984 let thd3 (_,_,z
) = z
1986 let sndthd (a
,b,c) = (b,c)
1988 let map_fst f (x, y) = f x, y
1989 let map_snd f (x, y) = x, f y
1991 let pair f (x,y) = (f x, f y)
1993 (* for my ocamlbeautify script *)
1998 let swap (x,y) = (y,x)
2001 let tuple_of_list1 = function [a
] -> a
| _ -> failwith
"tuple_of_list1"
2002 let tuple_of_list2 = function [a
;b] -> a
,b | _ -> failwith
"tuple_of_list2"
2003 let tuple_of_list3 = function [a
;b;c] -> a
,b,c | _ -> failwith
"tuple_of_list3"
2004 let tuple_of_list4 = function [a
;b;c;d
] -> a
,b,c,d
| _ -> failwith
"tuple_of_list4"
2005 let tuple_of_list5 = function [a
;b;c;d
;e] -> a
,b,c,d
,e | _ -> failwith
"tuple_of_list5"
2006 let tuple_of_list6 = function [a
;b;c;d
;e;f] -> a
,b,c,d
,e,f | _ -> failwith
"tuple_of_list6"
2009 (*****************************************************************************)
2011 (*****************************************************************************)
2013 (* type 'a maybe = Just of 'a | None *)
2015 type ('a
,'
b) either
= Left
of 'a
| Right
of '
b
2017 type ('a
, '
b, '
c) either3
= Left3
of 'a
| Middle3
of '
b | Right3
of '
c
2022 | _ -> failwith
"just: pb"
2027 let fmap f = function
2029 | Some
x -> Some
(f x)
2030 let map_option = fmap
2032 let do_option f = function
2037 try Some
(f ()) with Not_found
-> None
2042 let some_or = function
2044 | Some
e -> fun _ -> e
2047 let partition_either f l =
2048 let rec part_either left right
= function
2049 | [] -> (List.rev left
, List.rev right
)
2052 | Left
e -> part_either (e :: left
) right
l
2053 | Right
e -> part_either left
(e :: right
) l) in
2058 let rec filter_some = function
2060 | None
:: l -> filter_some l
2061 | Some
e :: l -> e :: filter_some l
2063 let map_filter f xs = xs +> List.map
f +> filter_some
2065 let rec find_some p
= function
2066 | [] -> raise Not_found
2070 | None
-> find_some p
l
2074 xs +> List.map f +> List.find (function Some x -> true | None -> false)
2075 +> (function Some x -> x | None -> raise Impossible)
2079 let list_to_single_or_exn xs =
2081 | [] -> raise Not_found
2082 | x::y::zs
-> raise Multi_found
2085 (*****************************************************************************)
2087 (*****************************************************************************)
2089 type bool3
= True3
| False3
| TrueFalsePb3
of string
2093 (*****************************************************************************)
2094 (* Regexp, can also use PCRE *)
2095 (*****************************************************************************)
2097 (* Note: OCaml Str regexps are different from Perl regexp:
2098 * - The OCaml regexp must match the entire way.
2099 * So "testBee" =~ "Bee" is wrong
2100 * but "testBee" =~ ".*Bee" is right
2101 * Can have the perl behavior if use Str.search_forward instead of
2103 * - Must add some additional \ in front of some special char. So use
2104 * \\( \\| and also \\b
2105 * - It does not always handle newlines very well.
2106 * - \\b does consider _ but not numbers in indentifiers.
2108 * Note: PCRE regexps are then different from Str regexps ...
2109 * - just use '(' ')' for grouping, not '\\)'
2110 * - still need \\b for word boundary, but this time it works ...
2111 * so can match some word that have some digits in them.
2115 (* put before String section because String section use some =~ *)
2117 (* let gsubst = global_replace *)
2120 let (==~
) s re
= Str.string_match re
s 0
2122 let _memo_compiled_regexp = Hashtbl.create
101
2123 let candidate_match_func s re
=
2124 (* old: Str.string_match (Str.regexp re) s 0 *)
2126 memoized _memo_compiled_regexp re
(fun () -> Str.regexp re
)
2128 Str.string_match
compile_re s 0
2130 let match_func s re
=
2131 profile_code "Common.=~" (fun () -> candidate_match_func s re
)
2140 let string_match_substring re
s =
2141 try let _i = Str.search_forward re
s 0 in true
2142 with Not_found
-> false
2145 example(string_match_substring (Str.regexp
"foo") "a foo b")
2147 example(string_match_substring (Str.regexp
"\\bfoo\\b") "a foo b")
2149 example(string_match_substring (Str.regexp
"\\bfoo\\b") "a\n\nfoo b")
2151 example(string_match_substring (Str.regexp
"\\bfoo_bar\\b") "a\n\nfoo_bar b")
2154 example(string_match_substring (Str.regexp "\\bfoo_bar2\\b") "a\n\nfoo_bar2 b")
2159 let (regexp_match
: string -> string -> string) = fun s re
->
2161 Str.matched_group
1 s
2163 (* beurk, side effect code, but hey, it is convenient *)
2165 * let (matched: int -> string -> string) = fun i s ->
2166 * Str.matched_group i s
2168 * let matched1 = fun s -> matched 1 s
2169 * let matched2 = fun s -> (matched 1 s, matched 2 s)
2170 * let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s)
2171 * let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s)
2172 * let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s)
2173 * let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s)
2178 let split sep
s = Str.split (Str.regexp sep
) s
2179 let _ = example (split "/" "" =*= [])
2180 let join sep
xs = String.concat sep
xs
2181 let _ = example (join "/" ["toto"; "titi"; "tata"] =$
= "toto/titi/tata")
2183 let rec join str = function
2186 | x::xs -> x ^ str ^ (join str xs)
2190 let (split_list_regexp
: string -> string list
-> (string * string list
) list
) =
2192 let rec split_lr_aux (heading
, accu
) = function
2193 | [] -> [(heading
, List.rev accu
)]
2196 then (heading
, List.rev accu
)::split_lr_aux (x, []) xs
2197 else split_lr_aux (heading
, x::accu
) xs
2199 split_lr_aux ("__noheading__", []) xs
2200 +> (fun xs -> if (List.hd
xs) =*= ("__noheading__",[]) then List.tl
xs else xs)
2204 let regexp_alpha = Str.regexp
2205 "^[a-zA-Z_][A-Za-z_0-9]*$"
2208 let all_match re
s =
2209 let regexp = Str.regexp re
in
2211 let _ = Str.global_substitute
regexp (fun _s
->
2212 let substr = Str.matched_string
s in
2213 assert(substr ==~
regexp); (* @Effect: also use it's side effect *)
2214 let paren_matched = matched1 substr in
2215 push2 paren_matched res;
2220 let _ = example (all_match "\\(@[A-Za-z]+\\)" "ca va @Et toi @Comment"
2221 =*= ["@Et";"@Comment"])
2224 let global_replace_regexp re f_on_substr
s =
2225 let regexp = Str.regexp re
in
2226 Str.global_substitute
regexp (fun _wholestr
->
2228 let substr = Str.matched_string
s in
2233 let regexp_word_str =
2234 "\\([a-zA-Z_][A-Za-z_0-9]*\\)"
2235 let regexp_word = Str.regexp regexp_word_str
2237 let regular_words s =
2238 all_match regexp_word_str s
2240 let contain_regular_word s =
2241 let xs = regular_words s in
2246 (*****************************************************************************)
2248 (*****************************************************************************)
2250 let slength = String.length
2251 let concat = String.concat
2254 let i_to_s = string_of_int
2255 let s_to_i = int_of_string
2258 (* strings take space in memory. Better when can share the space used by
2260 let _shareds = Hashtbl.create
100
2261 let (shared_string
: string -> string) = fun s ->
2262 try Hashtbl.find
_shareds s
2263 with Not_found
-> (Hashtbl.add _shareds s s; s)
2267 | s -> String.sub
s 0 (String.length
s - 1)
2270 let chop_dirsymbol = function
2271 | s when s =~
"\\(.*\\)/$" -> matched1 s
2275 let (<!!>) s (i,j) =
2276 String.sub
s i (if j < 0 then String.length
s - i + j + 1 else j - i)
2277 (* let _ = example ( "tototati"<!!>(3,-2) = "otat" ) *)
2279 let (<!>) s i = String.get
s i
2282 let rec split_on_char c s =
2284 let sp = String.index
s c in
2285 String.sub
s 0 sp ::
2286 split_on_char c (String.sub
s (sp+1) (String.length
s - sp - 1))
2287 with Not_found
-> [s]
2290 let lowercase = String.lowercase
2292 let quote s = "\"" ^
s ^
"\""
2294 (* easier to have this to be passed as hof, because ocaml dont have
2295 * haskell "section" operators
2300 let is_blank_string s =
2301 s =~
"^\\([ \t]\\)*$"
2303 (* src: lablgtk2/examples/entrycompletion.ml *)
2304 let is_string_prefix s1 s2
=
2305 (String.length s1
<= String.length s2
) &&
2306 (String.sub s2
0 (String.length s1
) =$
= s1
)
2310 then Printf.sprintf
"%d %s" i s
2311 else Printf.sprintf
"%d %ss" i s
2313 let showCodeHex xs = List.iter
(fun i -> printf
"%02x" i) xs
2315 let take_string n s =
2316 String.sub
s 0 (n-1)
2318 let take_string_safe n s =
2319 if n > String.length
s
2321 else take_string n s
2327 let ko = (i / 1024) mod 1024 in
2328 let mo = (i / 1024) / 1024 in
2330 then sprintf
"%dMo%dKo" mo ko
2331 else sprintf
"%dKo" ko
2335 let ko = i / 1024 in
2343 (* done in summer 2007 for julia
2344 * Reference: P216 of gusfeld book
2345 * For two strings S1 and S2, D(i,j) is defined to be the edit distance of S1[1..i] to S2[1..j]
2346 * So edit distance of S1 (of length n) and S2 (of length m) is D(n,m)
2348 * Dynamic programming technique
2350 * 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]
2351 * D(0,j) = j for all j (cos j characters must be inserted)
2353 * D(i,j) = min([D(i-1, j)+1, D(i, j - 1 + 1), D(i-1, j-1) + t(i,j)])
2354 * where t(i,j) is equal to 1 if S1(i) != S2(j) and 0 if equal
2355 * intuition = there is 4 possible action = deletion, insertion, substitution, or match
2358 * D(i,j) must be one of the three
2366 let matrix_distance s1 s2
=
2367 let n = (String.length s1
) in
2368 let m = (String.length s2
) in
2369 let mat = Array.make_matrix
(n+1) (m+1) 0 in
2371 if String.get s1
(i-1) =<= String.get s2
(j-1)
2375 let min3 a
b c = min
(min a
b) c in
2387 min3 (mat.(i).(j-1) + 1) (mat.(i-1).(j) + 1) (mat.(i-1).(j-1) + t i j)
2392 let edit_distance s1 s2
=
2393 (matrix_distance s1 s2
).(String.length s1
).(String.length s2
)
2396 let test = edit_distance "vintner" "writers"
2397 let _ = assert (edit_distance "winter" "winter" =|= 0)
2398 let _ = assert (edit_distance "vintner" "writers" =|= 5)
2401 (*****************************************************************************)
2403 (*****************************************************************************)
2405 let dirname = Filename.dirname
2406 let basename = Filename.basename
2408 type filename = string (* TODO could check that exist :) type sux *)
2410 type dirname = string (* TODO could check that exist :) type sux *)
2413 module BasicType
= struct
2414 type filename = string
2418 let (filesuffix
: filename -> string) = fun s ->
2419 (try regexp_match
s ".+\\.\\([a-zA-Z0-9_]+\\)$" with _ -> "NOEXT")
2420 let (fileprefix
: filename -> string) = fun s ->
2421 (try regexp_match
s "\\(.+\\)\\.\\([a-zA-Z0-9_]+\\)?$" with _ -> s)
2423 let _ = example (filesuffix
"toto.c" =$
= "c")
2424 let _ = example (fileprefix
"toto.c" =$
= "toto")
2427 assert (s = fileprefix s ^ filesuffix s)
2429 let withoutExtension s = global_replace (regexp "\\..*$") "" s
2430 let () = example "without"
2431 (withoutExtension "toto.s.toto" = "toto")
2434 let adjust_ext_if_needed filename ext
=
2435 if String.get ext
0 <> '
.'
2436 then failwith
"I need an extension such as .c not just c";
2438 if not
(filename =~
(".*\\" ^ ext
))
2444 let db_of_filename file
=
2445 dirname file
, basename file
2447 let filename_of_db (basedir
, file
) =
2448 Filename.concat basedir file
2452 let dbe_of_filename file
=
2453 (* raise Invalid_argument if no ext, so safe to use later the unsafe
2454 * fileprefix and filesuffix functions.
2456 ignore
(Filename.chop_extension file
);
2457 Filename.dirname file
,
2458 Filename.basename file
+> fileprefix
,
2459 Filename.basename file
+> filesuffix
2461 let filename_of_dbe (dir
, base
, ext
) =
2462 Filename.concat dir
(base ^
"." ^ ext
)
2465 let dbe_of_filename_safe file
=
2466 try Left
(dbe_of_filename file
)
2467 with Invalid_argument
_ ->
2468 Right
(Filename.dirname file
, Filename.basename file
)
2471 let dbe_of_filename_nodot file
=
2472 let (d
,b,e) = dbe_of_filename file
in
2473 let d = if d =$
= "." then "" else d in
2480 let replace_ext file oldext newext
=
2481 let (d,b,e) = dbe_of_filename file
in
2482 assert(e =$
= oldext
);
2483 filename_of_dbe (d,b,newext
)
2486 let normalize_path file
=
2487 let (dir
, filename) = Filename.dirname file
, Filename.basename file
in
2488 let xs = split "/" dir
in
2489 let rec aux acc
= function
2490 | [] -> List.rev acc
2494 | ".." -> aux (List.tl acc
) xs
2495 | x -> aux (x::acc
) xs
2498 let xs'
= aux [] xs in
2499 Filename.concat (join "/" xs'
) filename
2504 let relative_to_absolute s =
2505 if Filename.is_relative s
2508 let old = Sys.getcwd () in
2510 let current = Sys.getcwd () in
2517 let relative_to_absolute s =
2518 if Filename.is_relative
s
2519 then Sys.getcwd
() ^
"/" ^
s
2522 let is_relative s = Filename.is_relative s
2523 let is_absolute s = not
(is_relative s)
2526 (* @Pre: prj_path must not contain regexp symbol *)
2527 let filename_without_leading_path prj_path
s =
2528 let prj_path = chop_dirsymbol prj_path in
2529 if s =~
("^" ^
prj_path ^
"/\\(.*\\)$")
2533 (spf "cant find filename_without_project_path: %s %s" prj_path s)
2536 (*****************************************************************************)
2538 (*****************************************************************************)
2547 (*****************************************************************************)
2549 (*****************************************************************************)
2551 (* maybe I should use ocamlcalendar, but I don't like all those functors ... *)
2554 | Jan
| Feb
| Mar
| Apr
| May
| Jun
2555 | Jul
| Aug
| Sep
| Oct
| Nov
| Dec
2556 type year
= Year
of int
2557 type day
= Day
of int
2558 type wday
= Sunday
| Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
2560 type date_dmy
= DMY
of day
* month
* year
2562 type hour
= Hour
of int
2563 type minute
= Min
of int
2564 type second
= Sec
of int
2566 type time_hms
= HMS
of hour
* minute
* second
2568 type full_date
= date_dmy
* time_hms
2572 type days
= Days
of int
2574 type time_dmy
= TimeDMY
of day
* month
* year
2577 type float_time
= float
2581 let check_date_dmy (DMY
(day
, month
, year
)) =
2584 let check_time_dmy (TimeDMY
(day
, month
, year
)) =
2587 let check_time_hms (HMS
(x,y,a
)) =
2592 (* ---------------------------------------------------------------------- *)
2595 let int_to_month i =
2596 assert (i <= 12 && i >= 1);
2625 | _ -> raise Impossible
2629 1 , Jan
, "Jan", "January", 31;
2630 2 , Feb
, "Feb", "February", 28;
2631 3 , Mar
, "Mar", "March", 31;
2632 4 , Apr
, "Apr", "April", 30;
2633 5 , May
, "May", "May", 31;
2634 6 , Jun
, "Jun", "June", 30;
2635 7 , Jul
, "Jul", "July", 31;
2636 8 , Aug
, "Aug", "August", 31;
2637 9 , Sep
, "Sep", "September", 30;
2638 10 , Oct
, "Oct", "October", 31;
2639 11 , Nov
, "Nov", "November", 30;
2640 12 , Dec
, "Dec", "December", 31;
2643 let week_day_info = [
2644 0 , Sunday
, "Sun" , "Dim" , "Sunday";
2645 1 , Monday
, "Mon" , "Lun" , "Monday";
2646 2 , Tuesday
, "Tue" , "Mar" , "Tuesday";
2647 3 , Wednesday
, "Wed" , "Mer" , "Wednesday";
2648 4 , Thursday
, "Thu" ,"Jeu" ,"Thursday";
2649 5 , Friday
, "Fri" , "Ven" , "Friday";
2650 6 , Saturday
, "Sat" ,"Sam" , "Saturday";
2654 month_info +> List.map
(fun (i,month
,monthstr
,mlong
,days
) -> i, month
)
2656 month_info +> List.map
(fun (i,month
,monthstr
,mlong
,days
) -> monthstr
, month
)
2657 let slong_to_month_h =
2658 month_info +> List.map
(fun (i,month
,monthstr
,mlong
,days
) -> mlong
, month
)
2660 month_info +> List.map
(fun (i,month
,monthstr
,mlong
,days
) -> month
, monthstr
)
2662 month_info +> List.map
(fun (i,month
,monthstr
,mlong
,days
) -> month
, i)
2665 week_day_info +> List.map
(fun (i,day
,dayen
,dayfr
,daylong
) -> i, day
)
2667 week_day_info +> List.map
(fun (i,day
,dayen
,dayfr
,daylong
) -> day
, dayen
)
2669 week_day_info +> List.map
(fun (i,day
,dayen
,dayfr
,daylong
) -> day
, dayfr
)
2671 let month_of_string s =
2672 List.assoc s s_to_month_h
2674 let month_of_string_long s =
2675 List.assoc s slong_to_month_h
2677 let string_of_month s =
2678 List.assoc s month_to_s_h
2680 let month_of_int i =
2681 List.assoc i i_to_month_h
2683 let int_of_month m =
2684 List.assoc m month_to_i_h
2688 List.assoc i i_to_wday_h
2690 let string_en_of_wday wday
=
2691 List.assoc wday
wday_to_en_h
2692 let string_fr_of_wday wday
=
2693 List.assoc wday
wday_to_fr_h
2695 (* ---------------------------------------------------------------------- *)
2697 let wday_str_of_int ~langage
i =
2698 let wday = wday_of_int i in
2700 | English
-> string_en_of_wday wday
2701 | Francais
-> string_fr_of_wday wday
2702 | Deutsch
-> raise Todo
2706 let string_of_date_dmy (DMY
(Day
n, month
, Year
y)) =
2707 (spf "%02d-%s-%d" n (string_of_month month
) y)
2710 let string_of_unix_time ?
(langage
=English
) tm =
2711 let y = tm.Unix.tm_year
+ 1900 in
2712 let mon = string_of_month (month_of_int (tm.Unix.tm_mon
+ 1)) in
2713 let d = tm.Unix.tm_mday
in
2714 let h = tm.Unix.tm_hour
in
2715 let min = tm.Unix.tm_min
in
2716 let s = tm.Unix.tm_sec
in
2718 let wday = wday_str_of_int ~langage
tm.Unix.tm_wday
in
2720 spf "%02d/%03s/%04d (%s) %02d:%02d:%02d" d mon y wday h min s
2722 (* ex: 21/Jul/2008 (Lun) 21:25:12 *)
2723 let unix_time_of_string s =
2725 ("\\([0-9][0-9]\\)/\\(...\\)/\\([0-9][0-9][0-9][0-9]\\) " ^
2726 "\\(.*\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)")
2728 let (sday
, smonth
, syear
, _sday
, shour
, smin
, ssec
) = matched7 s in
2730 let y = s_to_i syear
- 1900 in
2732 smonth
+> month_of_string +> int_of_month +> (fun i -> i -1)
2735 let tm = Unix.localtime
(Unix.time
()) in
2739 Unix.tm_mday
= s_to_i sday
;
2740 Unix.tm_hour
= s_to_i shour
;
2741 Unix.tm_min
= s_to_i smin
;
2742 Unix.tm_sec
= s_to_i ssec
;
2744 else failwith
("unix_time_of_string: " ^
s)
2748 let short_string_of_unix_time ?
(langage
=English
) tm =
2749 let y = tm.Unix.tm_year
+ 1900 in
2750 let mon = string_of_month (month_of_int (tm.Unix.tm_mon
+ 1)) in
2751 let d = tm.Unix.tm_mday
in
2752 let _h = tm.Unix.tm_hour
in
2753 let _min = tm.Unix.tm_min
in
2754 let _s = tm.Unix.tm_sec
in
2756 let wday = wday_str_of_int ~langage
tm.Unix.tm_wday
in
2758 spf "%02d/%03s/%04d (%s)" d mon y wday
2761 let string_of_unix_time_lfs time
=
2764 (int_to_month (time
.Unix.tm_mon
+ 1))
2765 (time
.Unix.tm_year
+ 1900)
2768 (* ---------------------------------------------------------------------- *)
2769 let string_of_floattime ?langage
i =
2770 let tm = Unix.localtime
i in
2771 string_of_unix_time ?langage
tm
2773 let short_string_of_floattime ?langage
i =
2774 let tm = Unix.localtime
i in
2775 short_string_of_unix_time ?langage
tm
2777 let floattime_of_string s =
2778 let tm = unix_time_of_string s in
2779 let (sec
,_tm
) = Unix.mktime
tm in
2783 (* ---------------------------------------------------------------------- *)
2784 let days_in_week_of_day day
=
2785 let tm = Unix.localtime day
in
2787 let wday = tm.Unix.tm_wday
in
2788 let wday = if wday =|= 0 then 6 else wday -1 in
2790 let mday = tm.Unix.tm_mday
in
2792 let start_d = mday - wday in
2793 let end_d = mday + (6 - wday) in
2795 enum start_d end_d +> List.map
(fun mday ->
2796 Unix.mktime
{tm with Unix.tm_mday
= mday} +> fst
2799 let first_day_in_week_of_day day
=
2800 List.hd
(days_in_week_of_day day
)
2802 let last_day_in_week_of_day day
=
2803 last (days_in_week_of_day day
)
2806 (* ---------------------------------------------------------------------- *)
2808 (* (modified) copy paste from ocamlcalendar/src/date.ml *)
2810 [| 0; 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334(*; 365*) |]
2813 let rough_days_since_jesus (DMY
(Day nday
, month
, Year year
)) =
2816 (days_month.(int_of_month month
-1)) +
2823 let is_more_recent d1 d2
=
2824 let (Days n1
) = rough_days_since_jesus d1
in
2825 let (Days n2
) = rough_days_since_jesus d2
in
2830 if is_more_recent d1 d2
2835 if is_more_recent d1 d2
2840 let maximum_dmy ds
=
2843 let minimum_dmy ds
=
2848 let rough_days_between_dates d1 d2
=
2849 let (Days n1
) = rough_days_since_jesus d1
in
2850 let (Days n2
) = rough_days_since_jesus d2
in
2854 (rough_days_between_dates
2855 (DMY
(Day
7, Jan
, Year
1977))
2856 (DMY
(Day
13, Jan
, Year
1977)) =*= Days
6)
2858 (* because of rough days, it is a bit buggy, here it should return 1 *)
2860 let _ = assert_equal
2861 (rough_days_between_dates
2862 (DMY (Day 29, Feb, Year 1977))
2863 (DMY (Day 1, Mar , Year 1977)))
2868 (* from julia, in gitsort.ml *)
2872 [(1,31);(2,28);(3,31);(4,30);(5,31); (6,6);(7,7);(8,31);(9,30);(10,31);
2873 (11,30);(12,31);(0,31)]
2875 let normalize (year,month,day,hour,minute,second) =
2878 let (day,hour) = (day - 1,hour + 24) in
2881 let month = month - 1 in
2882 let day = List.assoc month antimonths in
2884 if month = 2 && year / 4 * 4 = year && not (year / 100 * 100 = year)
2888 then (year-1,12,day,hour,minute,second)
2889 else (year,month,day,hour,minute,second)
2890 else (year,month,day,hour,minute,second)
2891 else (year,month,day,hour,minute,second)
2896 let mk_date_dmy day month year
=
2897 let date = DMY
(Day
day, month_of_int month, Year year
) in
2898 (* check_date_dmy date *)
2902 (* ---------------------------------------------------------------------- *)
2903 (* conversion to unix.tm *)
2905 let dmy_to_unixtime (DMY
(Day
n, month, Year year
)) =
2907 Unix.tm_sec
= 0; (** Seconds 0..60 *)
2908 tm_min
= 0; (** Minutes 0..59 *)
2909 tm_hour
= 12; (** Hours 0..23 *)
2910 tm_mday
= n; (** Day of month 1..31 *)
2911 tm_mon
= (int_of_month month -1); (** Month of year 0..11 *)
2912 tm_year
= year
- 1900; (** Year - 1900 *)
2913 tm_wday
= 0; (** Day of week (Sunday is 0) *)
2914 tm_yday
= 0; (** Day of year 0..365 *)
2915 tm_isdst
= false; (** Daylight time savings in effect *)
2919 let unixtime_to_dmy tm =
2920 let n = tm.Unix.tm_mday
in
2921 let month = month_of_int (tm.Unix.tm_mon
+ 1) in
2922 let year = tm.Unix.tm_year
+ 1900 in
2924 DMY
(Day
n, month, Year
year)
2927 let unixtime_to_floattime tm =
2928 Unix.mktime
tm +> fst
2930 let floattime_to_unixtime sec
=
2934 let sec_to_days sec
=
2935 let minfactor = 60 in
2936 let hourfactor = 60 * 60 in
2937 let dayfactor = 60 * 60 * 24 in
2939 let days = sec
/ dayfactor in
2940 let hours = (sec
mod dayfactor) / hourfactor in
2941 let mins = (sec
mod hourfactor) / minfactor in
2942 let sec = (sec mod 60) in
2943 (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *)
2944 (if days > 0 then plural days "day" ^
" " else "") ^
2945 (if hours > 0 then plural hours "hour" ^
" " else "") ^
2946 (if mins > 0 then plural mins "min" ^
" " else "") ^
2949 let sec_to_hours sec =
2950 let minfactor = 60 in
2951 let hourfactor = 60 * 60 in
2953 let hours = sec / hourfactor in
2954 let mins = (sec mod hourfactor) / minfactor in
2955 let sec = (sec mod 60) in
2956 (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *)
2957 (if hours > 0 then plural hours "hour" ^
" " else "") ^
2958 (if mins > 0 then plural mins "min" ^
" " else "") ^
2963 let test_date_1 () =
2964 let date = DMY
(Day
17, Sep
, Year
1991) in
2965 let float, tm = dmy_to_unixtime date in
2966 pr2 (spf "date: %.0f" float);
2970 (* src: ferre in logfun/.../date.ml *)
2972 let day_secs : float = 86400.
2974 let today : unit -> float = fun () -> (Unix.time
() )
2975 let yesterday : unit -> float = fun () -> (Unix.time
() -. day_secs)
2976 let tomorrow : unit -> float = fun () -> (Unix.time
() +. day_secs)
2978 let lastweek : unit -> float = fun () -> (Unix.time
() -. (7.0 *. day_secs))
2979 let lastmonth : unit -> float = fun () -> (Unix.time
() -. (30.0 *. day_secs))
2982 let week_before : float_time
-> float_time
= fun d ->
2983 (d -. (7.0 *. day_secs))
2984 let month_before : float_time
-> float_time
= fun d ->
2985 (d -. (30.0 *. day_secs))
2987 let week_after : float_time
-> float_time
= fun d ->
2988 (d +. (7.0 *. day_secs))
2992 (*****************************************************************************)
2993 (* Lines/words/strings *)
2994 (*****************************************************************************)
2997 * let (list_of_string: string -> char list) = fun s ->
2998 * (enum 0 ((String.length s) - 1) +> List.map (String.get s))
3001 let _ = example (list_of_string
"abcd" =*= ['a'
;'
b'
;'
c'
;'
d'
])
3004 let rec (list_of_stream: ('a Stream.t) -> 'a list) =
3006 | [< 'c ; stream >] -> c :: list_of_stream stream
3009 let (list_of_string: string -> char list) =
3010 Stream.of_string $ list_of_stream
3014 * let (lines: string -> string list) = fun s -> ...
3017 let (lines_with_nl
: string -> string list
) = fun s ->
3018 let rec lines_aux = function
3020 | [x] -> if x =$
= "" then [] else [x ^
"\n"] (* old: [x] *)
3025 (time_func (fun () -> Str.split_delim
(Str.regexp "\n") s)) +> lines_aux
3027 (* in fact better make it return always complete lines, simplify *)
3028 (* Str.split, but lines "\n1\n2\n" dont return the \n and forget the first \n => split_delim better than split *)
3029 (* +> List.map (fun s -> s ^ "\n") but add an \n even at the end => lines_aux *)
3031 let chars = list_of_string s in
3032 chars +> List.fold_left (fun (acc, lines) char ->
3033 let newacc = acc ^ (String.make 1 char) in
3035 then ("", newacc::lines)
3036 else (newacc, lines)
3038 +> (fun (s, lines) -> List.rev (s::lines))
3041 (* CHECK: unlines (lines x) = x *)
3042 let (unlines
: string list
-> string) = fun s ->
3043 (String.concat "\n" s) ^
"\n"
3044 let (words
: string -> string list
) = fun s ->
3045 Str.split (Str.regexp "[ \t()\";]+") s
3046 let (unwords
: string list
-> string) = fun s ->
3049 let (split_space
: string -> string list
) = fun s ->
3050 Str.split (Str.regexp "[ \t\n]+") s
3055 lines
s +> List.length
3056 let _ = example (nblines "" =|= 0)
3057 let _ = example (nblines "toto" =|= 1)
3058 let _ = example (nblines "toto\n" =|= 1)
3059 let _ = example (nblines "toto\ntata" =|= 2)
3060 let _ = example (nblines "toto\ntata\n" =|= 2)
3062 (*****************************************************************************)
3064 (*****************************************************************************)
3066 let chan = open_in file
in
3067 let rec cat_orig_aux () =
3069 (* cant do input_line chan::aux() cos ocaml eval from right to left ! *)
3070 let l = input_line
chan in
3071 l :: cat_orig_aux ()
3072 with End_of_file
-> [] in
3075 (* tail recursive efficient version *)
3077 let chan = open_in file
in
3078 let rec cat_aux acc
() =
3079 (* cant do input_line chan::aux() cos ocaml eval from right to left ! *)
3080 let (b, l) = try (true, input_line
chan) with End_of_file
-> (false, "") in
3082 then cat_aux (l::acc
) ()
3085 cat_aux [] () +> List.rev
+> (fun x -> close_in
chan; x)
3087 let cat_array file
=
3088 (""::cat file
) +> Array.of_list
3091 let interpolate str
=
3093 command2 ("printf \"%s\\n\" " ^ str ^
">/tmp/caml");
3097 (* could do a print_string but printf dont like print_string *)
3098 let echo s = printf
"%s" s; flush stdout
; s
3100 let usleep s = for i = 1 to s do () done
3102 let sleep_little () =
3105 (*ignore(Sys.command ("usleep " ^ !_sleep_time))*)
3109 * let command2 s = ignore(Sys.command s)
3113 let pid = Unix.fork
() in
3117 (* Unix.setsid(); *)
3118 Sys.set_signal
Sys.sigint
(Sys.Signal_handle
(fun _ ->
3120 Unix.kill
0 Sys.sigkill
;
3128 let process_output_to_list2 = fun command
->
3129 let chan = Unix.open_process_in command
in
3130 let res = ref ([] : string list
) in
3131 let rec process_otl_aux () =
3132 let e = input_line
chan in
3134 process_otl_aux() in
3135 try process_otl_aux ()
3137 let stat = Unix.close_process_in
chan in (List.rev
!res,stat)
3138 let cmd_to_list command
=
3139 let (l,_) = process_output_to_list2 command
in l
3140 let process_output_to_list = cmd_to_list
3141 let cmd_to_list_and_status = process_output_to_list2
3144 * let command2 s = ignore(Sys.command s)
3148 let _batch_mode = ref false
3149 let command2_y_or_no cmd
=
3150 if !_batch_mode then begin command2 cmd
; true end
3153 pr2 (cmd ^
" [y/n] ?");
3154 match read_line
() with
3155 | "y" | "yes" | "Y" -> command2 cmd
; true
3156 | "n" | "no" | "N" -> false
3157 | _ -> failwith
"answer by yes or no"
3160 let command2_y_or_no_exit_if_no cmd
=
3161 let res = command2_y_or_no cmd
in
3164 else raise
(UnixExit
(1))
3169 let mkdir ?
(mode
=0o770
) file
=
3170 Unix.mkdir file mode
3172 let read_file_orig file
= cat file
+> unlines
3173 let read_file file
=
3174 let ic = open_in file
in
3175 let size = in_channel_length
ic in
3176 let buf = String.create
size in
3177 really_input
ic buf 0 size;
3182 let write_file ~file
s =
3183 let chan = open_out file
in
3184 (output_string
chan s; close_out
chan)
3187 (Unix.stat file
).Unix.st_size
3189 let filemtime file
=
3190 (Unix.stat file
).Unix.st_mtime
3192 (* opti? use wc -l ? *)
3193 let nblines_file file
=
3194 cat file
+> List.length
3196 let lfile_exists filename =
3198 (match (Unix.lstat
filename).Unix.st_kind
with
3199 | (Unix.S_REG
| Unix.S_LNK
) -> true
3202 with Unix.Unix_error
(Unix.ENOENT
, _, _) -> false
3204 let is_directory file
=
3205 (Unix.stat file
).Unix.st_kind
=*= Unix.S_DIR
3208 (* src: from chailloux et al book *)
3209 let capsule_unix f args =
3211 with Unix.Unix_error
(e, fm
, argm
) ->
3212 log (Printf.sprintf
"exn Unix_error: %s %s %s\n" (Unix.error_message
e) fm argm
)
3215 let (readdir_to_kind_list
: string -> Unix.file_kind
-> string list
) =
3219 +> List.filter
(fun s ->
3221 let stat = Unix.lstat
(path ^
"/" ^
s) in
3222 stat.Unix.st_kind
=*= kind
3224 pr2 ("EXN pb stating file: " ^
s);
3228 let (readdir_to_dir_list
: string -> string list
) = fun path
->
3229 readdir_to_kind_list path
Unix.S_DIR
3231 let (readdir_to_file_list
: string -> string list
) = fun path
->
3232 readdir_to_kind_list path
Unix.S_REG
3234 let (readdir_to_link_list
: string -> string list
) = fun path
->
3235 readdir_to_kind_list path
Unix.S_LNK
3238 let (readdir_to_dir_size_list
: string -> (string * int) list
) = fun path
->
3241 +> map_filter (fun s ->
3242 let stat = Unix.lstat
(path ^
"/" ^
s) in
3243 if stat.Unix.st_kind
=*= Unix.S_DIR
3244 then Some
(s, stat.Unix.st_size
)
3248 (* could be in control section too *)
3250 (* Why a use_cache argument ? because sometimes want disable it but dont
3251 * want put the cache_computation funcall in comment, so just easier to
3252 * pass this extra option.
3254 let cache_computation2 ?
(verbose
=false) ?
(use_cache
=true) file ext_cache
f =
3258 if not
(Sys.file_exists file
)
3259 then failwith
("can't find: " ^ file
);
3260 let file_cache = (file ^ ext_cache
) in
3261 if Sys.file_exists
file_cache &&
3262 filemtime file_cache >= filemtime file
3264 if verbose
then pr2 ("using cache: " ^
file_cache);
3265 get_value file_cache
3269 write_value res file_cache;
3273 let cache_computation ?verbose ?use_cache a
b c =
3274 profile_code "Common.cache_computation" (fun () ->
3275 cache_computation2 ?verbose ?use_cache a
b c)
3278 let cache_computation_robust2
3280 (need_no_changed_files
, need_no_changed_variables
) ext_depend
3282 if not
(Sys.file_exists file
)
3283 then failwith
("can't find: " ^ file
);
3285 let file_cache = (file ^ ext_cache
) in
3286 let dependencies_cache = (file ^ ext_depend
) in
3289 (* could do md5sum too *)
3290 ((file
::need_no_changed_files
) +> List.map
(fun f -> f, filemtime f),
3291 need_no_changed_variables
)
3294 if Sys.file_exists
dependencies_cache &&
3295 get_value dependencies_cache =*= dependencies
3296 then get_value file_cache
3298 pr2 ("cache computation recompute " ^ file
);
3300 write_value dependencies dependencies_cache;
3301 write_value res file_cache;
3305 let cache_computation_robust a
b c d e =
3306 profile_code "Common.cache_computation_robust" (fun () ->
3307 cache_computation_robust2 a
b c d e)
3312 (* dont forget that cmd_to_list call bash and so pattern may contain
3313 * '*' symbols that will be expanded, so can do glob "*.c"
3316 cmd_to_list ("ls -1 " ^ pattern
)
3319 (* update: have added the -type f, so normally need less the sanity_check_xxx
3321 let files_of_dir_or_files ext
xs =
3322 xs +> List.map
(fun x ->
3324 then cmd_to_list ("find " ^
x ^
" -noleaf -type f -name \"*." ^ext^
"\"")
3329 let files_of_dir_or_files_no_vcs ext
xs =
3330 xs +> List.map
(fun x ->
3334 ("find " ^
x ^
" -noleaf -type f -name \"*." ^ext^
"\"" ^
3335 "| grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/ |grep -v /_darcs/"
3341 let files_of_dir_or_files_no_vcs_post_filter regex
xs =
3342 xs +> List.map
(fun x ->
3347 " -noleaf -type f | grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/ |grep -v /_darcs/"
3349 +> List.filter
(fun s -> s =~ regex
)
3354 let sanity_check_files_and_adjust ext files
=
3355 let files = files +> List.filter
(fun file
->
3356 if not
(file
=~
(".*\\."^ext
))
3358 pr2 ("warning: seems not a ."^ext^
" file");
3362 if is_directory file
3364 pr2 (spf "warning: %s is a directory" file
);
3374 (* taken from mlfuse, the predecessor of ocamlfuse *)
3375 type rwx
= [`R
|`W
|`X
] list
3376 let file_perm_of : u
:rwx
-> g
:rwx
-> o:rwx
-> Unix.file_perm
=
3379 List.fold_left
(fun acc p
-> acc
lor ((function `R
-> 4 | `W
-> 2 | `X
-> 1) p
)) 0 l in
3381 ((to_oct u
) lsl 6) lor
3382 ((to_oct g
) lsl 3) lor
3391 let _ = Sys.getenv var
in true
3392 with Not_found
-> false
3394 (* emacs/lisp inspiration (eric cooper and yaron minsky use that too) *)
3395 let (with_open_outfile
: filename -> (((string -> unit) * out_channel
) -> 'a
) -> 'a
) =
3397 let chan = open_out file
in
3398 let pr s = output_string
chan s in
3399 unwind_protect (fun () ->
3400 let res = f (pr, chan) in
3403 (fun e -> close_out
chan)
3405 let (with_open_infile
: filename -> ((in_channel
) -> 'a
) -> 'a
) = fun file
f ->
3406 let chan = open_in file
in
3407 unwind_protect (fun () ->
3411 (fun e -> close_in
chan)
3414 let (with_open_outfile_append
: filename -> (((string -> unit) * out_channel
) -> 'a
) -> 'a
) =
3416 let chan = open_out_gen
[Open_creat
;Open_append
] 0o666 file
in
3417 let pr s = output_string
chan s in
3418 unwind_protect (fun () ->
3419 let res = f (pr, chan) in
3422 (fun e -> close_out
chan)
3429 (* it seems that the toplevel block such signals, even with this explicit
3431 * let _ = Unix.sigprocmask Unix.SIG_UNBLOCK [Sys.sigalrm]
3434 (* could be in Control section *)
3436 (* subtil: have to make sure that timeout is not intercepted before here, so
3437 * avoid exn handle such as try (...) with _ -> cos timeout will not bubble up
3438 * enough. In such case, add a case before such as
3439 * with Timeout -> raise Timeout | _ -> ...
3441 * question: can we have a signal and so exn when in a exn handler ?
3443 let timeout_function timeoutval
= fun f ->
3446 Sys.set_signal
Sys.sigalrm
(Sys.Signal_handle
(fun _ -> raise Timeout
));
3447 ignore
(Unix.alarm timeoutval
);
3449 ignore
(Unix.alarm
0);
3454 log "timeout (we abort)";
3458 (* subtil: important to disable the alarm before relaunching the exn,
3459 * otherwise the alarm is still running.
3461 * robust?: and if alarm launched after the log (...) ?
3462 * Maybe signals are disabled when process an exception handler ?
3465 ignore
(Unix.alarm
0);
3466 (* log ("exn while in transaction (we abort too, even if ...) = " ^
3467 Printexc.to_string e);
3469 log "exn while in timeout_function";
3473 let timeout_function_opt timeoutvalopt
f =
3474 match timeoutvalopt
with
3476 | Some
x -> timeout_function x f
3480 (* creation of tmp files, a la gcc *)
3482 let _temp_files_created = ref []
3484 (* ex: new_temp_file "cocci" ".c" will give "/tmp/cocci-3252-434465.c" *)
3485 let new_temp_file prefix suffix
=
3486 let processid = i_to_s (Unix.getpid
()) in
3487 let tmp_file = Filename.temp_file
(prefix ^
"-" ^
processid ^
"-") suffix
in
3488 push2 tmp_file _temp_files_created;
3492 let save_tmp_files = ref false
3493 let erase_temp_files () =
3494 if not
!save_tmp_files then begin
3495 !_temp_files_created +> List.iter
(fun s ->
3496 (* pr2 ("erasing: " ^ s); *)
3497 command2 ("rm -f " ^
s)
3499 _temp_files_created := []
3502 (* now in prelude: exception UnixExit of int *)
3503 let exn_to_real_unixexit f =
3505 with UnixExit
x -> exit
x
3511 with_open_outfile file
(fun (pr,_chan) ->
3512 xs +> List.iter
(fun s -> pr s; pr "\n");
3521 (*****************************************************************************)
3523 (*****************************************************************************)
3526 let uncons l = (List.hd
l, List.tl
l)
3529 let safe_tl l = try List.tl
l with _ -> []
3537 | ([],_) -> failwith
"zip: not same length"
3538 | (_,[]) -> failwith
"zip: not same length"
3539 | (x::xs,y::ys
) -> (x,y)::zip xs ys
3541 let rec zip_safe xs ys
=
3545 | (x::xs,y::ys
) -> (x,y)::zip_safe xs ys
3548 List.fold_right
(fun e (xs, ys
) ->
3549 (fst e::xs), (snd e::ys
)) zs
([],[])
3552 let map_withkeep f xs =
3553 xs +> List.map
(fun x -> f x, x)
3556 * let rec take n xs =
3559 * | (_,[]) -> failwith "take: not enough"
3560 * | (n,x::xs) -> x::take (n-1) xs
3563 let rec take_safe n xs =
3567 | (n,x::xs) -> x::take_safe (n-1) xs
3569 let rec take_until p
= function
3571 | x::xs -> if p
x then [] else x::(take_until p
xs)
3573 let take_while p
= take_until (p $ not
)
3576 (* now in prelude: let rec drop n xs = ... *)
3577 let _ = example (drop 3 [1;2;3;4] =*= [4])
3579 let rec drop_while p
= function
3581 | x::xs -> if p
x then drop_while p
xs else x::xs
3584 let rec drop_until p
xs =
3585 drop_while (fun x -> not
(p
x)) xs
3586 let _ = example (drop_until (fun x -> x =|= 3) [1;2;3;4;5] =*= [3;4;5])
3589 let span p
xs = (take_while p
xs, drop_while p
xs)
3592 let rec (span: ('a
-> bool) -> 'a list
-> 'a list
* 'a list
) =
3597 let (l1
, l2
) = span p
xs in
3600 let _ = example ((span (fun x -> x <= 3) [1;2;3;4;1;2] =*= ([1;2;3],[4;1;2])))
3602 let rec groupBy eq
l =
3606 let (xs1
,xs2
) = List.partition
(fun x'
-> eq
x x'
) xs in
3607 (x::xs1
)::(groupBy eq xs2
)
3609 let rec group_by_mapped_key fkey
l =
3614 let (xs1
,xs2
) = List.partition
(fun x'
-> let k2 = fkey
x'
in k=*=k2) xs
3616 (k, (x::xs1
))::(group_by_mapped_key fkey xs2
)
3621 let (exclude_but_keep_attached
: ('a
-> bool) -> 'a list
-> ('a
* 'a list
) list
)=
3623 let rec aux_filter acc
= function
3624 | [] -> [] (* drop what was accumulated because nothing to attach to *)
3627 then aux_filter (x::acc
) xs
3628 else (x, List.rev acc
)::aux_filter [] xs
3632 (exclude_but_keep_attached
(fun x -> x =|= 3) [3;3;1;3;2;3;3;3] =*=
3633 [(1,[3;3]);(2,[3])])
3635 let (group_by_post
: ('a
-> bool) -> 'a list
-> ('a list
* 'a
) list
* 'a list
)=
3637 let rec aux_filter grouped_acc acc
= function
3639 List.rev grouped_acc
, List.rev acc
3643 aux_filter ((List.rev acc
,x)::grouped_acc
) [] xs
3645 aux_filter grouped_acc
(x::acc
) xs
3650 (group_by_post
(fun x -> x =|= 3) [1;1;3;2;3;4;5;3;6;6;6] =*=
3651 ([([1;1],3);([2],3);[4;5],3], [6;6;6]))
3653 let (group_by_pre
: ('a
-> bool) -> 'a list
-> 'a list
* ('a
* 'a list
) list
)=
3655 let xs'
= List.rev
xs in
3656 let (ys
, unclassified
) = group_by_post
f xs'
in
3657 List.rev unclassified
,
3658 ys
+> List.rev
+> List.map
(fun (xs, x) -> x, List.rev
xs )
3661 (group_by_pre
(fun x -> x =|= 3) [1;1;3;2;3;4;5;3;6;6;6] =*=
3662 ([1;1], [(3,[2]); (3,[4;5]); (3,[6;6;6])]))
3665 let rec (split_when
: ('a
-> bool) -> 'a list
-> 'a list
* 'a
* 'a list
) =
3667 | [] -> raise Not_found
3672 let (l1
, a
, l2
) = split_when p
xs in
3674 let _ = example (split_when
(fun x -> x =|= 3)
3675 [1;2;3;4;1;2] =*= ([1;2],3,[4;1;2]))
3678 (* not so easy to come up with ... used in aComment for split_paragraph *)
3679 let rec split_gen_when_aux f acc
xs =
3686 (match f (x::xs) with
3688 split_gen_when_aux f (x::acc
) xs
3690 let before = List.rev acc
in
3692 then split_gen_when_aux f [] rest
3693 else before::split_gen_when_aux f [] rest
3695 (* could avoid introduce extra aux function by using ?(acc = []) *)
3696 let split_gen_when f xs =
3697 split_gen_when_aux f [] xs
3701 (* generate exception (Failure "tl") if there is no element satisfying p *)
3702 let rec (skip_until
: ('a list
-> bool) -> 'a list
-> 'a list
) = fun p
xs ->
3703 if p
xs then xs else skip_until p
(List.tl
xs)
3705 (skip_until
(function 1::2::xs -> true | _ -> false)
3706 [1;3;4;1;2;4;5] =*= [1;2;4;5])
3708 let rec skipfirst e = function
3710 | e'
::l when e =*= e'
-> skipfirst e l
3715 * let rec enum x n = ...
3720 if null xs then [] (* enum 0 (-1) generate an exception *)
3721 else zip xs (enum 0 ((List.length
xs) -1))
3723 let index_list_and_total xs =
3724 let total = List.length
xs in
3725 if null xs then [] (* enum 0 (-1) generate an exception *)
3726 else zip xs (enum 0 ((List.length
xs) -1))
3727 +> List.map
(fun (a
,b) -> (a
,b,total))
3729 let index_list_1 xs =
3730 xs +> index_list +> List.map
(fun (x,i) -> x, i+1)
3732 let or_list = List.fold_left
(||) false
3733 let and_list = List.fold_left
(&&) true
3736 let sum = sum_int xs in
3737 (float_of_int
sum) /. (float_of_int
(List.length
xs))
3739 let snoc x xs = xs @ [x]
3740 let cons x xs = x::xs
3742 let head_middle_tail xs =
3746 let reversed = List.rev
(y::xs) in
3747 let tail = List.hd
reversed in
3748 let middle = List.rev
(List.tl
reversed) in
3750 | _ -> failwith
"head_middle_tail, too small list"
3752 let _ = assert_equal (head_middle_tail [1;2;3]) (1, [2], 3)
3753 let _ = assert_equal (head_middle_tail [1;3]) (1, [], 3)
3759 (* let (++) = (@), could do that, but if load many times the common, then pb *)
3760 (* let (++) l1 l2 = List.fold_right (fun x acc -> x::acc) l1 l2 *)
3763 let newxs = List.filter
(fun y -> y <> x) xs in
3764 assert (List.length
newxs =|= List.length
xs - 1);
3769 List.filter
(fun x -> not
(p
x)) xs
3774 let fold_k f lastk acc
xs =
3775 let rec fold_k_aux acc
= function
3778 f acc
x (fun acc
-> fold_k_aux acc
xs)
3783 let rec list_init = function
3784 | [] -> raise Not_found
3786 | x::y::xs -> x::(list_init (y::xs))
3788 let rec list_last = function
3789 | [] -> raise Not_found
3791 | x::y::xs -> list_last (y::xs)
3795 * let last_n n l = List.rev (take n (List.rev l))
3796 * let last l = List.hd (last_n 1 l)
3799 let rec join_gen a
= function
3802 | x::xs -> x::a
::(join_gen a
xs)
3805 (* todo: foldl, foldr (a more consistent foldr) *)
3808 let iter_index f l =
3809 let rec iter_ n = function
3811 | e::l -> f e n ; iter_ (n+1) l
3815 let rec map_ n = function
3817 | e::l -> f e n :: map_ (n+1) l
3822 let filter_index f l =
3823 let rec filt i = function
3825 | e::l -> if f i e then e :: filt (i+1) l else filt (i+1) l
3830 let do_withenv doit
f env
l =
3831 let r_env = ref env
in
3832 let l'
= doit
(fun e ->
3833 let e'
, env'
= f !r_env e in
3839 * let fold_left_with_index f acc = ...
3842 let map_withenv f env
e = do_withenv List.map
f env
e
3844 let rec collect_accu f accu
= function
3846 | e::l -> collect_accu f (List.rev_append
(f e) accu
) l
3848 let collect f l = List.rev
(collect_accu f [] l)
3850 (* cf also List.partition *)
3852 let rec fpartition p
l =
3853 let rec part yes no
= function
3854 | [] -> (List.rev yes
, List.rev no
)
3857 | None
-> part yes
(x :: no
) l
3858 | Some
v -> part (v :: yes
) no
l) in
3863 let rec removelast = function
3864 | [] -> failwith
"removelast"
3866 | e::l -> e :: removelast l
3868 let remove x = List.filter
(fun y -> y != x)
3869 let empty list
= null list
3872 let rec inits = function
3874 | e::l -> [] :: List.map
(fun l -> e::l) (inits l)
3876 let rec tails = function
3878 | (_::xs) as xxs
-> xxs
:: tails xs
3881 let reverse = List.rev
3885 let fold_left = List.fold_left
3886 let rev_map = List.rev_map
3889 let rec fold_right1 f = function
3890 | [] -> failwith
"fold_right1"
3892 | e::l -> f e (fold_right1 f l)
3894 let maximum l = foldl1 max
l
3895 let minimum l = foldl1 min l
3897 (* do a map tail recursive, and result is reversed, it is a tail recursive map => efficient *)
3898 let map_eff_rev = fun f l ->
3899 let rec map_eff_aux acc
=
3902 | x::xs -> map_eff_aux ((f x)::acc
) xs
3907 let rec loop acc
= function
3909 | x::xs -> loop ((f x)::acc
) xs in
3913 let rec (generate
: int -> 'a
-> 'a list
) = fun i el
->
3915 else el
::(generate
(i-1) el
)
3917 let rec uniq = function
3919 | e::l -> if List.mem
e l then uniq l else e :: uniq l
3921 let has_no_duplicate xs =
3922 List.length
xs =|= List.length
(uniq xs)
3923 let is_set_as_list = has_no_duplicate
3926 let rec get_duplicates xs =
3931 then x::get_duplicates xs (* todo? could x from xs to avoid double dups?*)
3932 else get_duplicates xs
3934 let rec all_assoc e = function
3936 | (e'
,v) :: l when e=*=e'
-> v :: all_assoc e l
3937 | _ :: l -> all_assoc e l
3939 let prepare_want_all_assoc l =
3940 List.map
(fun n -> n, uniq (all_assoc n l)) (uniq (List.map
fst l))
3942 let rotate list
= List.tl list
++ [(List.hd list
)]
3944 let or_list = List.fold_left (||) false
3945 let and_list = List.fold_left (&&) true
3947 let rec (return_when
: ('a
-> '
b option) -> 'a list
-> '
b) = fun p
-> function
3948 | [] -> raise Not_found
3949 | x::xs -> (match p
x with None
-> return_when p
xs | Some
b -> b)
3951 let rec splitAt n xs =
3952 if n =|= 0 then ([],xs)
3956 | (x::xs) -> let (a
,b) = splitAt (n-1) xs in (x::a
, b)
3960 let rec pack_aux l i = function
3961 | [] -> failwith
"not on a boundary"
3962 | [x] -> if i =|= n then [l++[x]] else failwith
"not on a boundary"
3965 then (l++[x])::(pack_aux [] 1 xs)
3966 else pack_aux (l++[x]) (i+1) xs
3970 let min_with f = function
3971 | [] -> raise Not_found
3973 let rec min_with_ min_val min_elt
= function
3978 then min_with_ val_ e l
3979 else min_with_ min_val min_elt
l
3980 in min_with_ (f e) e l
3982 let two_mins_with f = function
3984 let rec min_with_ min_val min_elt min_val2 min_elt2
= function
3985 | [] -> min_elt
, min_elt2
3991 then min_with_ val_ e min_val min_elt
l
3992 else min_with_ min_val min_elt
val_ e l
3993 else min_with_ min_val min_elt min_val2 min_elt2
l
3997 if v1 < v2 then min_with_ v1 e1
v2 e2
l else min_with_ v2 e2
v1 e1
l
3998 | _ -> raise Not_found
4000 let grep_with_previous f = function
4003 let rec grep_with_previous_ previous
= function
4005 | e::l -> if f previous
e then e :: grep_with_previous_ e l else grep_with_previous_ previous
l
4006 in e :: grep_with_previous_ e l
4008 let iter_with_previous f = function
4011 let rec iter_with_previous_ previous
= function
4013 | e::l -> f previous
e ; iter_with_previous_ e l
4014 in iter_with_previous_ e l
4017 let iter_with_before_after f xs =
4018 let rec aux before_rev after
=
4023 aux (x::before_rev
) xs
4029 (* kind of cartesian product of x*x *)
4030 let rec (get_pair
: ('a list
) -> (('a
* 'a
) list
)) = function
4032 | x::xs -> (List.map
(fun y -> (x,y)) xs) ++ (get_pair
xs)
4035 (* retourne le rang dans une liste d'un element *)
4036 let rang elem liste
=
4037 let rec rang_rec elem accu
= function
4038 | [] -> raise Not_found
4039 | a
::l -> if a
=*= elem
then accu
4040 else rang_rec elem
(accu
+1) l in
4041 rang_rec elem
1 liste
4043 (* retourne vrai si une liste contient des doubles *)
4044 let rec doublon = function
4046 | a
::l -> if List.mem a
l then true
4049 let rec (insert_in
: 'a
-> 'a list
-> 'a list list
) = fun x -> function
4051 | y::ys
-> (x::y::ys
) :: (List.map
(fun xs -> y::xs) (insert_in
x ys
))
4052 (* insert_in 3 [1;2] = [[3; 1; 2]; [1; 3; 2]; [1; 2; 3]] *)
4054 let rec (permutation
: 'a list
-> 'a list list
) = function
4057 | x::xs -> List.flatten
(List.map
(insert_in
x) (permutation
xs))
4058 (* permutation [1;2;3] =
4059 * [[1; 2; 3]; [2; 1; 3]; [2; 3; 1]; [1; 3; 2]; [3; 1; 2]; [3; 2; 1]]
4063 let rec remove_elem_pos pos
xs =
4064 match (pos
, xs) with
4065 | _, [] -> failwith
"remove_elem_pos"
4067 | n, x::xs -> x::(remove_elem_pos (n-1) xs)
4069 let rec insert_elem_pos (e, pos
) xs =
4070 match (pos
, xs) with
4072 | n, x::xs -> x::(insert_elem_pos (e, (n-1)) xs)
4073 | n, [] -> failwith
"insert_elem_pos"
4075 let rec uncons_permut xs =
4076 let indexed = index_list xs in
4077 indexed +> List.map
(fun (x, pos
) -> (x, pos
), remove_elem_pos pos
xs)
4080 (uncons_permut ['a'
;'
b'
;'
c'
] =*=
4081 [('a'
, 0), ['
b'
;'
c'
];
4082 ('
b'
, 1), ['a'
;'
c'
];
4086 let rec uncons_permut_lazy xs =
4087 let indexed = index_list xs in
4088 indexed +> List.map
(fun (x, pos
) ->
4090 lazy (remove_elem_pos pos
xs)
4097 let rec map_flatten f l =
4098 let rec map_flatten_aux accu
= function
4100 | e :: l -> map_flatten_aux (List.rev (f e) ++ accu
) l
4101 in List.rev (map_flatten_aux [] l)
4104 let rec repeat e n =
4105 let rec repeat_aux acc
= function
4107 | n when n < 0 -> failwith
"repeat"
4108 | n -> repeat_aux (e::acc
) (n-1) in
4111 let rec map2 f = function
4113 | x::xs -> let r = f x in r::map2 f xs
4116 let rec map3_aux acc
= function
4118 | x::xs -> map3_aux (f x::acc
) xs in
4122 let tails2 xs = map rev (inits (rev xs))
4123 let res = tails2 [1;2;3;4]
4124 let res = tails [1;2;3;4]
4128 let pack_sorted same
xs =
4129 let rec pack_s_aux acc
xs =
4131 | ((cur
,rest
),[]) -> cur
::rest
4132 | ((cur
,rest
), y::ys
) ->
4133 if same
(List.hd cur
) y then pack_s_aux (y::cur
, rest
) ys
4134 else pack_s_aux ([y], cur
::rest
) ys
4135 in pack_s_aux ([List.hd
xs],[]) (List.tl
xs) +> List.rev
4136 let test = pack_sorted (=*=) [1;1;1;2;2;3;4]
4139 let rec keep_best f =
4140 let rec partition e = function
4144 | None
-> let (e''
, l'
) = partition e l in e''
, e'
:: l'
4145 | Some
e''
-> partition e''
l
4149 let (e'
, l'
) = partition e l in
4150 e'
:: keep_best f l'
4152 let rec sorted_keep_best f = function
4157 | None
-> a
:: sorted_keep_best f (b :: l)
4158 | Some
e -> sorted_keep_best f (e :: l)
4162 let (cartesian_product
: 'a list
-> '
b list
-> ('a
* '
b) list
) = fun xs ys
->
4163 xs +> List.map
(fun x -> ys
+> List.map
(fun y -> (x,y)))
4166 let _ = assert_equal
4167 (cartesian_product
[1;2] ["3";"4";"5"])
4168 [1,"3";1,"4";1,"5"; 2,"3";2,"4";2,"5"]
4171 profile_code "Common.sort_by_xxx" (fun () -> List.sort a
b)
4173 let sort_by_val_highfirst xs =
4174 sort_prof (fun (k1
,v1) (k2,v2) -> compare
v2 v1) xs
4175 let sort_by_val_lowfirst xs =
4176 sort_prof (fun (k1
,v1) (k2,v2) -> compare
v1 v2) xs
4178 let sort_by_key_highfirst xs =
4179 sort_prof (fun (k1
,v1) (k2,v2) -> compare
k2 k1
) xs
4180 let sort_by_key_lowfirst xs =
4181 sort_prof (fun (k1
,v1) (k2,v2) -> compare k1
k2) xs
4183 let _ = example (sort_by_key_lowfirst [4, (); 7,()] =*= [4,(); 7,()])
4184 let _ = example (sort_by_key_highfirst [4,(); 7,()] =*= [7,(); 4,()])
4187 let sortgen_by_key_highfirst xs =
4188 sort_prof (fun (k1
,v1) (k2,v2) -> compare
k2 k1
) xs
4189 let sortgen_by_key_lowfirst xs =
4190 sort_prof (fun (k1
,v1) (k2,v2) -> compare k1
k2) xs
4192 (*----------------------------------*)
4194 (* sur surEnsemble [p1;p2] [[p1;p2;p3] [p1;p2] ....] -> [[p1;p2;p3] ... *)
4195 (* mais pas p2;p3 *)
4197 let surEnsemble liste_el liste_liste_el
=
4199 (function liste_elbis
->
4200 List.for_all
(function el
-> List.mem el liste_elbis
) liste_el
4205 (*----------------------------------*)
4206 (* combinaison/product/.... (aop) *)
4207 (* 123 -> 123 12 13 23 1 2 3 *)
4208 let rec realCombinaison = function
4212 let res = realCombinaison l in
4213 let res2 = List.map
(function x -> a
::x) res in
4214 res2 ++ res ++ [[a
]]
4216 (* genere toutes les combinaisons possible de paire *)
4217 (* par exemple combinaison [1;2;4] -> [1, 2; 1, 4; 2, 4] *)
4218 let rec combinaison = function
4222 | a
::b::l -> (List.map
(function elem
-> (a
, elem
)) (b::l)) ++
4223 (combinaison (b::l))
4225 (*----------------------------------*)
4227 (* list of list(aop) *)
4228 (* insere elem dans la liste de liste (si elem est deja present dans une de *)
4229 (* ces listes, on ne fait rien *)
4230 let rec insere elem
= function
4233 if (List.mem elem a
) then a
::l
4234 else a
::(insere elem
l)
4236 let rec insereListeContenant lis el
= function
4239 if List.mem el a
then
4240 (List.append lis a
)::l
4241 else a
::(insereListeContenant lis el
l)
4243 (* fusionne les listes contenant et1 et et2 dans la liste de liste*)
4244 let rec fusionneListeContenant (et1
, et2
) = function
4245 | [] -> [[et1
; et2
]]
4247 (* si les deux sont deja dedans alors rien faire *)
4248 if List.mem et1 a
then
4249 if List.mem et2 a
then a
::l
4251 insereListeContenant a et2
l
4252 else if List.mem et2 a
then
4253 insereListeContenant a et1
l
4254 else a
::(fusionneListeContenant (et1
, et2
) l)
4256 (*****************************************************************************)
4258 (*****************************************************************************)
4260 (* do bound checking ? *)
4261 let array_find_index f a
=
4262 let rec array_find_index_ i =
4263 if f i then i else array_find_index_ (i+1)
4265 try array_find_index_ 0 with _ -> raise Not_found
4267 let array_find_index_via_elem f a
=
4268 let rec array_find_index_ i =
4269 if f a
.(i) then i else array_find_index_ (i+1)
4271 try array_find_index_ 0 with _ -> raise Not_found
4275 type idx
= Idx
of int
4276 let next_idx (Idx
i) = (Idx
(i+1))
4277 let int_of_idx (Idx
i) = i
4279 let array_find_index_typed f a
=
4280 let rec array_find_index_ i =
4281 if f i then i else array_find_index_ (next_idx i)
4283 try array_find_index_ (Idx
0) with _ -> raise Not_found
4287 (*****************************************************************************)
4289 (*****************************************************************************)
4291 type 'a matrix
= 'a array array
4293 let map_matrix f mat =
4294 mat +> Array.map
(fun arr
-> arr
+> Array.map
f)
4296 let (make_matrix_init
:
4297 nrow
:int -> ncolumn
:int -> (int -> int -> 'a
) -> 'a matrix
) =
4298 fun ~nrow ~ncolumn
f ->
4299 Array.init nrow
(fun i ->
4300 Array.init ncolumn
(fun j ->
4305 let iter_matrix f m =
4306 Array.iteri
(fun i e ->
4307 Array.iteri
(fun j x ->
4312 let nb_rows_matrix m =
4315 let nb_columns_matrix m =
4316 assert(Array.length
m > 0);
4319 (* check all nested arrays have the same size *)
4320 let invariant_matrix m =
4323 let (rows_of_matrix
: 'a matrix
-> 'a list list
) = fun m ->
4324 Array.to_list
m +> List.map
Array.to_list
4326 let (columns_of_matrix
: 'a matrix
-> 'a list list
) = fun m ->
4327 let nbcols = nb_columns_matrix m in
4328 let nbrows = nb_rows_matrix m in
4329 (enum 0 (nbcols -1)) +> List.map
(fun j ->
4330 (enum 0 (nbrows -1)) +> List.map
(fun i ->
4335 let all_elems_matrix_by_row m =
4336 rows_of_matrix
m +> List.flatten
4357 let _ = example (rows_of_matrix
ex_matrix1 =*= ex_rows1)
4358 let _ = example (columns_of_matrix
ex_matrix1 =*= ex_columns1)
4361 (*****************************************************************************)
4363 (*****************************************************************************)
4365 module B_Array = Bigarray.Array2
4374 (* for the string_of auto generation of camlp4
4375 val b_array_string_of_t : 'a -> 'b -> string
4376 val bigarray_string_of_int16_unsigned_elt : 'a -> string
4377 val bigarray_string_of_c_layout : 'a -> string
4378 let b_array_string_of_t f a = "<>"
4379 let bigarray_string_of_int16_unsigned_elt a = "<>"
4380 let bigarray_string_of_c_layout a = "<>"
4385 (*****************************************************************************)
4386 (* Set. Have a look too at set*.mli *)
4387 (*****************************************************************************)
4388 type 'a set
= 'a list
4391 let (empty_set
: 'a set
) = []
4392 let (insert_set
: 'a
-> 'a set
-> 'a set
) = fun x xs ->
4394 then (* let _ = print_string "warning insert: already exist" in *)
4401 let (single_set
: 'a
-> 'a set
) = fun x -> insert_set
x empty_set
4402 let (set
: 'a list
-> 'a set
) = fun xs ->
4403 xs +> List.fold_left (flip insert_set
) empty_set
4405 let (exists_set
: ('a
-> bool) -> 'a set
-> bool) = List.exists
4406 let (forall_set
: ('a
-> bool) -> 'a set
-> bool) = List.for_all
4407 let (filter_set
: ('a
-> bool) -> 'a set
-> 'a set
) = List.filter
4408 let (fold_set
: ('a
-> '
b -> 'a
) -> 'a
-> '
b set
-> 'a
) = List.fold_left
4409 let (map_set
: ('a
-> '
b) -> 'a set
-> '
b set
) = List.map
4410 let (member_set
: 'a
-> 'a set
-> bool) = List.mem
4412 let find_set = List.find
4413 let sort_set = List.sort
4414 let iter_set = List.iter
4416 let (top_set
: 'a set
-> 'a
) = List.hd
4418 let (inter_set
: 'a set
-> 'a set
-> 'a set
) = fun s1 s2
->
4419 s1
+> fold_set
(fun acc
x -> if member_set
x s2
then insert_set
x acc
else acc
) empty_set
4420 let (union_set
: 'a set
-> 'a set
-> 'a set
) = fun s1 s2
->
4421 s2
+> fold_set
(fun acc
x -> if member_set
x s1
then acc
else insert_set
x acc
) s1
4422 let (minus_set
: 'a set
-> 'a set
-> 'a set
) = fun s1 s2
->
4423 s1
+> filter_set
(fun x -> not
(member_set
x s2
))
4426 let union_all l = List.fold_left union_set
[] l
4428 let big_union_set f xs = xs +> map_set
f +> fold_set union_set empty_set
4430 let (card_set
: 'a set
-> int) = List.length
4432 let (include_set
: 'a set
-> 'a set
-> bool) = fun s1 s2
->
4433 (s1
+> forall_set
(fun p
-> member_set p s2
))
4435 let equal_set s1 s2
= include_set s1 s2
&& include_set s2 s1
4437 let (include_set_strict
: 'a set
-> 'a set
-> bool) = fun s1 s2
->
4438 (card_set s1
< card_set s2
) && (include_set s1 s2
)
4440 let ($
*$
) = inter_set
4441 let ($
+$
) = union_set
4442 let ($
-$
) = minus_set
4443 let ($?$
) a
b = profile_code "$?$" (fun () -> member_set a
b)
4444 let ($
<$
) = include_set_strict
4445 let ($
<=$
) = include_set
4446 let ($
=$
) = equal_set
4448 (* as $+$ but do not check for memberness, allow to have set of func *)
4449 let ($
@$
) = fun a
b -> a
@ b
4451 let rec nub = function
4453 | x::xs -> if List.mem
x xs then nub xs else x::(nub xs)
4455 (*****************************************************************************)
4456 (* Set as normal list *)
4457 (*****************************************************************************)
4459 let (union: 'a list -> 'a list -> 'a list) = fun l1 l2 ->
4460 List.fold_left (fun acc x -> if List.mem x l1 then acc else x::acc) l1 l2
4462 let insert_normal x xs = union xs [x]
4464 (* retourne lis1 - lis2 *)
4465 let minus l1 l2
= List.filter
(fun x -> not
(List.mem
x l2
)) l1
4467 let inter l1 l2
= List.fold_left (fun acc
x -> if List.mem
x l2
then x::acc
else acc
) [] l1
4469 let union_list = List.fold_left union
[]
4472 List.fold_left (function acc
-> function el
-> union
[el
] acc
) [] lis
4475 let rec non_uniq = function
4477 | e::l -> if mem
e l then e :: non_uniq l else non_uniq l
4479 let rec inclu lis1 lis2
=
4480 List.for_all
(function el
-> List.mem el lis2
) lis1
4482 let equivalent lis1 lis2
=
4483 (inclu lis1 lis2
) && (inclu lis2 lis1
)
4488 (*****************************************************************************)
4489 (* Set as sorted list *)
4490 (*****************************************************************************)
4491 (* liste trie, cos we need to do intersection, and insertion (it is a set
4492 cos when introduce has, if we create a new has => must do a recurse_rep
4493 and another categ can have to this has => must do an union
4496 let rec insert x = function
4500 else (if x < y then x::y::ys else y::(insert x ys))
4502 (* same, suppose sorted list *)
4503 let rec intersect x y =
4508 if x = y then x::(intersect xs ys
)
4510 (if x < y then intersect xs (y::ys
)
4511 else intersect (x::xs) ys
4513 (* intersect [1;3;7] [2;3;4;7;8];; *)
4516 (*****************************************************************************)
4518 (*****************************************************************************)
4519 type ('a
,'
b) assoc = ('a
* '
b) list
4523 let (assoc_to_function
: ('a
, '
b) assoc -> ('a
-> '
b)) = fun xs ->
4524 xs +> List.fold_left (fun acc
(k, v) ->
4526 if k =*= k'
then v else acc
k'
4527 )) (fun k -> failwith
"no key in this assoc")
4529 let (assoc_to_function: ('a, 'b) assoc -> ('a -> 'b)) = fun xs ->
4530 fun k -> List.assoc k xs
4533 let (empty_assoc
: ('a
, '
b) assoc) = []
4534 let fold_assoc = List.fold_left
4535 let insert_assoc = fun x xs -> x::xs
4536 let map_assoc = List.map
4537 let filter_assoc = List.filter
4539 let assoc = List.assoc
4540 let keys xs = List.map
fst xs
4544 (* assert unique key ?*)
4545 let del_assoc key
xs = xs +> List.filter
(fun (k,v) -> k <> key
)
4546 let replace_assoc (key
, v) xs = insert_assoc (key
, v) (del_assoc key
xs)
4548 let apply_assoc key
f xs =
4549 let old = assoc key
xs in
4550 replace_assoc (key
, f old) xs
4552 let big_union_assoc f xs = xs +> map_assoc f +> fold_assoc union_set empty_set
4554 (* todo: pb normally can suppr fun l -> .... l but if do that, then strange type _a
4555 => assoc_map is strange too => equal dont work
4557 let (assoc_reverse
: (('a
* '
b) list
) -> (('
b * 'a
) list
)) = fun l ->
4558 List.map
(fun(x,y) -> (y,x)) l
4560 let (assoc_map
: (('a
* '
b) list
) -> (('a
* '
b) list
) -> (('a
* 'a
) list
)) =
4562 let (l1bis
, l2bis
) = (assoc_reverse l1
, assoc_reverse l2
) in
4563 List.map
(fun (x,y) -> (y, List.assoc x l2bis
)) l1bis
4565 let rec (lookup_list
: 'a
-> ('a
, '
b) assoc list
-> '
b) = fun el
-> function
4566 | [] -> raise Not_found
4567 | (xs::xxs
) -> try List.assoc el
xs with Not_found
-> lookup_list el xxs
4569 let (lookup_list2
: 'a
-> ('a
, '
b) assoc list
-> ('
b * int)) = fun el xxs
->
4570 let rec lookup_l_aux i = function
4571 | [] -> raise Not_found
4573 try let res = List.assoc el
xs in (res,i)
4574 with Not_found
-> lookup_l_aux (i+1) xxs
4575 in lookup_l_aux 0 xxs
4578 (lookup_list2
"c" [["a",1;"b",2];["a",1;"b",3];["a",1;"c",7]] =*= (7,2))
4581 let assoc_option k l =
4582 optionise (fun () -> List.assoc k l)
4584 let assoc_with_err_msg k l =
4587 pr2 (spf "pb assoc_with_err_msg: %s" (dump k));
4590 (*****************************************************************************)
4591 (* Assoc int -> xxx with binary tree. Have a look too at Mapb.mli *)
4592 (*****************************************************************************)
4594 (* ex: type robot_list = robot_info IntMap.t *)
4595 module IntMap
= Map.Make
4598 let compare = compare
4600 let intmap_to_list m = IntMap.fold
(fun id v acc
-> (id, v) :: acc
) m []
4601 let intmap_string_of_t f a
= "<Not Yet>"
4603 module IntIntMap
= Map.Make
4606 let compare = compare
4609 let intintmap_to_list m = IntIntMap.fold
(fun id v acc
-> (id, v) :: acc
) m []
4610 let intintmap_string_of_t f a
= "<Not Yet>"
4613 (*****************************************************************************)
4615 (*****************************************************************************)
4617 (* il parait que better when choose a prime *)
4618 let hcreate () = Hashtbl.create
401
4619 let hadd (k,v) h = Hashtbl.add h k v
4620 let hmem k h = Hashtbl.mem
h k
4621 let hfind k h = Hashtbl.find
h k
4622 let hreplace (k,v) h = Hashtbl.replace
h k v
4623 let hiter = Hashtbl.iter
4624 let hfold = Hashtbl.fold
4625 let hremove k h = Hashtbl.remove h k
4628 let hash_to_list h =
4629 Hashtbl.fold
(fun k v acc
-> (k,v)::acc
) h []
4630 +> List.sort
compare
4632 let hash_to_list_unsorted h =
4633 Hashtbl.fold
(fun k v acc
-> (k,v)::acc
) h []
4635 let hash_of_list xs =
4636 let h = Hashtbl.create
101 in
4638 xs +> List.iter
(fun (k, v) -> Hashtbl.add h k v);
4643 let h = Hashtbl.create
101 in
4644 Hashtbl.add h "toto" 1;
4645 Hashtbl.add h "toto" 1;
4646 assert(hash_to_list h =*= ["toto",1; "toto",1])
4649 let hfind_default key value_if_not_found
h =
4650 try Hashtbl.find
h key
4652 (Hashtbl.add h key
(value_if_not_found
()); Hashtbl.find
h key
)
4654 (* not as easy as Perl $h->{key}++; but still possible *)
4655 let hupdate_default key op value_if_not_found
h =
4656 let old = hfind_default key value_if_not_found
h in
4657 Hashtbl.replace
h key
(op
old)
4660 let hfind_option key
h =
4661 optionise (fun () -> Hashtbl.find
h key
)
4664 (* see below: let hkeys h = ... *)
4667 (*****************************************************************************)
4669 (*****************************************************************************)
4671 type 'a hashset
= ('a
, bool) Hashtbl.t
4675 let hash_hashset_add k e h =
4676 match optionise (fun () -> Hashtbl.find
h k) with
4677 | Some hset
-> Hashtbl.replace hset
e true
4679 let hset = Hashtbl.create
11 in
4681 Hashtbl.add h k hset;
4682 Hashtbl.replace
hset e true;
4685 let hashset_to_set baseset
h =
4686 h +> hash_to_list +> List.map
fst +> (fun xs -> baseset#fromlist
xs)
4688 let hashset_to_list h = hash_to_list h +> List.map
fst
4690 let hashset_of_list xs =
4691 xs +> List.map
(fun x -> x, true) +> hash_of_list
4696 let hkey = Hashtbl.create
101 in
4697 h +> Hashtbl.iter
(fun k v -> Hashtbl.replace
hkey k true);
4698 hashset_to_list hkey
4702 let group_assoc_bykey_eff2 xs =
4703 let h = Hashtbl.create
101 in
4704 xs +> List.iter
(fun (k, v) -> Hashtbl.add h k v);
4705 let keys = hkeys h in
4706 keys +> List.map
(fun k -> k, Hashtbl.find_all
h k)
4708 let group_assoc_bykey_eff xs =
4709 profile_code2 "Common.group_assoc_bykey_eff" (fun () ->
4710 group_assoc_bykey_eff2 xs)
4713 let test_group_assoc () =
4714 let xs = enum 0 10000 +> List.map
(fun i -> i_to_s i, i) in
4715 let xs = ("0", 2)::xs in
4716 (* let _ys = xs +> Common.groupBy (fun (a,resa) (b,resb) -> a =$= b) *)
4717 let ys = xs +> group_assoc_bykey_eff
4723 let h = Hashtbl.create
101 in
4724 xs +> List.iter
(fun k ->
4725 Hashtbl.add h k true
4731 let diff_two_say_set_eff xs1 xs2
=
4732 let h1 = hashset_of_list xs1
in
4733 let h2 = hashset_of_list xs2
in
4735 let hcommon = Hashtbl.create
101 in
4736 let honly_in_h1 = Hashtbl.create
101 in
4737 let honly_in_h2 = Hashtbl.create
101 in
4739 h1 +> Hashtbl.iter
(fun k _ ->
4741 then Hashtbl.replace
hcommon k true
4742 else Hashtbl.add honly_in_h1 k true
4744 h2 +> Hashtbl.iter
(fun k _ ->
4746 then Hashtbl.replace
hcommon k true
4747 else Hashtbl.add honly_in_h2 k true
4749 hashset_to_list hcommon,
4750 hashset_to_list honly_in_h1,
4751 hashset_to_list honly_in_h2
4754 (*****************************************************************************)
4756 (*****************************************************************************)
4757 type 'a stack
= 'a list
4760 let (empty_stack
: 'a stack
) = []
4761 let (push: 'a
-> 'a stack
-> 'a stack
) = fun x xs -> x::xs
4762 let (top
: 'a stack
-> 'a
) = List.hd
4763 let (pop
: 'a stack
-> 'a stack
) = List.tl
4765 let top_option = function
4773 * let push2 v l = l := v :: !l
4777 let v = List.hd
!l in
4784 (*****************************************************************************)
4785 (* Undoable Stack *)
4786 (*****************************************************************************)
4788 (* Okasaki use such structure also for having efficient data structure
4789 * supporting fast append.
4792 type 'a undo_stack
= 'a list
* 'a list
(* redo *)
4794 let (empty_undo_stack
: 'a undo_stack
) =
4797 (* push erase the possible redo *)
4798 let (push_undo
: 'a
-> 'a undo_stack
-> 'a undo_stack
) = fun x (undo
,redo
) ->
4801 let (top_undo
: 'a undo_stack
-> 'a
) = fun (undo
, redo
) ->
4804 let (pop_undo
: 'a undo_stack
-> 'a undo_stack
) = fun (undo
, redo
) ->
4806 | [] -> failwith
"empty undo stack"
4810 let (undo_pop
: 'a undo_stack
-> 'a undo_stack
) = fun (undo
, redo
) ->
4812 | [] -> failwith
"empty redo, nothing to redo"
4816 let redo_undo x = undo_pop
x
4819 let top_undo_option = fun (undo
, redo
) ->
4824 (*****************************************************************************)
4826 (*****************************************************************************)
4827 type 'a bintree
= Leaf
of 'a
| Branch
of ('a bintree
* 'a bintree
)
4830 (*****************************************************************************)
4832 (*****************************************************************************)
4834 (* no empty tree, must have one root at list *)
4835 type 'a tree
= Tree
of 'a
* ('a tree
) list
4837 let rec (tree_iter
: ('a
-> unit) -> 'a tree
-> unit) = fun f tree
->
4839 | Tree
(node
, xs) ->
4841 xs +> List.iter
(tree_iter
f)
4844 (*****************************************************************************)
4845 (* N-ary tree with updatable childrens *)
4846 (*****************************************************************************)
4848 (* no empty tree, must have one root at list *)
4851 | NodeRef
of 'a
* 'a treeref list
ref
4853 let treeref_children_ref tree
=
4855 | NodeRef
(n, x) -> x
4859 let rec (treeref_node_iter
:
4860 (* (('a * ('a, 'b) treeref list ref) -> unit) ->
4861 ('a, 'b) treeref -> unit
4866 (* | LeafRef _ -> ()*)
4867 | NodeRef
(n, xs) ->
4869 !xs +> List.iter
(treeref_node_iter
f)
4872 let find_treeref f tree
=
4875 tree
+> treeref_node_iter
(fun (n, xs) ->
4877 then push2 (n, xs) res;
4880 | [n,xs] -> NodeRef
(n, xs)
4881 | [] -> raise Not_found
4882 | x::y::zs
-> raise Multi_found
4884 let rec (treeref_node_iter_with_parents
:
4885 (* (('a * ('a, 'b) treeref list ref) -> ('a list) -> unit) ->
4886 ('a, 'b) treeref -> unit)
4890 let rec aux acc tree
=
4892 (* | LeafRef _ -> ()*)
4893 | NodeRef
(n, xs) ->
4895 !xs +> List.iter
(aux (n::acc
))
4900 (* ---------------------------------------------------------------------- *)
4901 (* Leaf can seem redundant, but sometimes want to directly see if
4902 * a children is a leaf without looking if the list is empty.
4904 type ('a
, '
b) treeref2
=
4905 | NodeRef2
of 'a
* ('a
, '
b) treeref2 list
ref
4909 let treeref2_children_ref tree
=
4911 | LeafRef2
_ -> failwith
"treeref_tail: leaf"
4912 | NodeRef2
(n, x) -> x
4916 let rec (treeref_node_iter2
:
4917 (('a
* ('a
, '
b) treeref2 list
ref) -> unit) ->
4918 ('a
, '
b) treeref2
-> unit) =
4922 | NodeRef2
(n, xs) ->
4924 !xs +> List.iter
(treeref_node_iter2
f)
4927 let find_treeref2 f tree
=
4930 tree
+> treeref_node_iter2
(fun (n, xs) ->
4932 then push2 (n, xs) res;
4935 | [n,xs] -> NodeRef2
(n, xs)
4936 | [] -> raise Not_found
4937 | x::y::zs
-> raise Multi_found
4942 let rec (treeref_node_iter_with_parents2
:
4943 (('a
* ('a
, '
b) treeref2 list
ref) -> ('a list
) -> unit) ->
4944 ('a
, '
b) treeref2
-> unit) =
4946 let rec aux acc tree
=
4949 | NodeRef2
(n, xs) ->
4951 !xs +> List.iter
(aux (n::acc
))
4967 let find_treeref_with_parents_some f tree
=
4970 tree
+> treeref_node_iter_with_parents
(fun (n, xs) parents
->
4971 match f (n,xs) parents
with
4972 | Some
v -> push2 v res;
4977 | [] -> raise Not_found
4978 | x::y::zs
-> raise Multi_found
4980 let find_multi_treeref_with_parents_some f tree
=
4983 tree
+> treeref_node_iter_with_parents
(fun (n, xs) parents
->
4984 match f (n,xs) parents
with
4985 | Some
v -> push2 v res;
4990 | [] -> raise Not_found
4994 (*****************************************************************************)
4995 (* Graph. Have a look too at Ograph_*.mli *)
4996 (*****************************************************************************)
4997 (* todo: generalise to put in common (need 'edge (and 'c ?),
4998 * and take in param a display func, cos caml sux, no overloading of show :(
4999 * Simple impelemntation. Can do also matrix, or adjacent list, or pointer(ref)
5000 * todo: do some check (dont exist already, ...)
5003 type 'node graph
= ('node set
) * (('node
* 'node
) set
)
5005 let (add_node
: 'a
-> 'a graph
-> 'a graph
) = fun node
(nodes
, arcs
) ->
5008 let (del_node
: 'a
-> 'a graph
-> 'a graph
) = fun node
(nodes
, arcs
) ->
5009 (nodes $
-$ set
[node
], arcs
)
5010 (* could do more job:
5011 let _ = assert (successors node (nodes, arcs) = empty) in
5012 +> List.filter (fun (src, dst) -> dst != node))
5014 let (add_arc
: ('a
* 'a
) -> 'a graph
-> 'a graph
) = fun arc
(nodes
, arcs
) ->
5015 (nodes
, set
[arc
] $
+$ arcs
)
5017 let (del_arc
: ('a
* 'a
) -> 'a graph
-> 'a graph
) = fun arc
(nodes
, arcs
) ->
5018 (nodes
, arcs
+> List.filter
(fun a
-> not
(arc
=*= a
)))
5020 let (successors
: 'a
-> 'a graph
-> 'a set
) = fun x (nodes
, arcs
) ->
5021 arcs
+> List.filter
(fun (src
, dst
) -> src
=*= x) +> List.map
snd
5023 let (predecessors
: 'a
-> 'a graph
-> 'a set
) = fun x (nodes
, arcs
) ->
5024 arcs
+> List.filter
(fun (src
, dst
) -> dst
=*= x) +> List.map
fst
5026 let (nodes
: 'a graph
-> 'a set
) = fun (nodes
, arcs
) -> nodes
5029 let rec (fold_upward
: ('
b -> 'a
-> '
b) -> 'a set
-> '
b -> 'a graph
-> '
b) =
5030 fun f xs acc graph
->
5033 | x::xs -> (f acc
x)
5034 +> (fun newacc -> fold_upward
f (graph
+> predecessors
x) newacc graph
)
5035 +> (fun newacc -> fold_upward
f xs newacc graph
)
5036 (* TODO avoid already visited *)
5038 let empty_graph = ([], [])
5043 let (add_arcs_toward: int -> (int list) -> 'a graph -> 'a graph) = fun i xs ->
5045 (nodes, arcs) -> (nodes, (List.map (fun j -> (j,i) ) xs)++arcs)
5046 let (del_arcs_toward: int -> (int list) -> 'a graph -> 'a graph)= fun i xs g ->
5047 List.fold_left (fun acc el -> del_arc (el, i) acc) g xs
5048 let (add_arcs_from: int -> (int list) -> 'a graph -> 'a graph) = fun i xs ->
5050 (nodes, arcs) -> (nodes, (List.map (fun j -> (i,j) ) xs)++arcs)
5053 let (del_node: (int * 'node) -> 'node graph -> 'node graph) = fun node ->
5054 function (nodes, arcs) ->
5055 let newnodes = List.filter (fun a -> not (node = a)) nodes in
5056 if newnodes = nodes then (raise Not_found) else (newnodes, arcs)
5057 let (replace_node: int -> 'node -> 'node graph -> 'node graph) = fun i n ->
5058 function (nodes, arcs) ->
5059 let newnodes = List.filter (fun (j,_) -> not (i = j)) nodes in
5060 ((i,n)::newnodes, arcs)
5061 let (get_node: int -> 'node graph -> 'node) = fun i -> function
5062 (nodes, arcs) -> List.assoc i nodes
5064 let (get_free: 'a graph -> int) = function
5065 (nodes, arcs) -> (maximum (List.map fst nodes))+1
5066 (* require no cycle !!
5067 TODO if cycle check that we have already visited a node *)
5068 let rec (succ_all
: int -> 'a graph
-> (int list
)) = fun i -> function
5069 (nodes
, arcs
) as g
->
5070 let direct = succ
i g
in
5071 union
direct (union_list (List.map
(fun i -> succ_all
i g
) direct))
5072 let rec (pred_all
: int -> 'a graph
-> (int list
)) = fun i -> function
5073 (nodes
, arcs
) as g
->
5074 let direct = pred
i g
in
5075 union
direct (union_list (List.map
(fun i -> pred_all
i g
) direct))
5076 (* require that the nodes are different !! *)
5077 let rec (equal
: 'a graph
-> 'a graph
-> bool) = fun g1 g2
->
5078 let ((nodes1
, arcs1
),(nodes2
, arcs2
)) = (g1
,g2
) in
5080 (* do 2 things, check same length and to assoc *)
5081 let conv = assoc_map nodes1 nodes2
in
5082 List.for_all
(fun (i1
,i2
) ->
5083 List.mem
(List.assoc i1
conv, List.assoc i2
conv) arcs2
)
5085 && (List.length arcs1
= List.length arcs2
)
5086 (* could think that only forall is needed, but need check same lenth too*)
5089 let (display
: 'a graph
-> ('a
-> unit) -> unit) = fun g display_func
->
5090 let rec aux depth
i =
5092 print_int
i; print_string
"->"; display_func
(get_node
i g
);
5094 List.iter
(aux (depth
+2)) (succ
i g
)
5097 let (display_dot
: 'a graph
-> ('a
-> string) -> unit)= fun (nodes
,arcs
) func
->
5098 let file = open_out
"test.dot" in
5099 output_string
file "digraph misc {\n" ;
5100 List.iter
(fun (n, node
) ->
5101 output_int
file n; output_string
file " [label=\"";
5102 output_string
file (func node
); output_string
file " \"];\n"; ) nodes
;
5103 List.iter
(fun (i1
,i2
) -> output_int
file i1
; output_string
file " -> " ;
5104 output_int
file i2
; output_string
file " ;\n"; ) arcs
;
5105 output_string
file "}\n" ;
5107 let status = Unix.system
"viewdot test.dot" in
5109 (* todo: faire = graphe (int can change !!! => cant make simply =)
5110 reassign number first !!
5113 (* todo: mettre diff(modulo = !!) en rouge *)
5114 let (display_dot2
: 'a graph
-> 'a graph
-> ('a
-> string) -> unit) =
5115 fun (nodes1
, arcs1
) (nodes2
, arcs2
) func
->
5116 let file = open_out
"test.dot" in
5117 output_string
file "digraph misc {\n" ;
5118 output_string
file "rotate = 90;\n";
5119 List.iter
(fun (n, node
) ->
5120 output_string
file "100"; output_int
file n;
5121 output_string
file " [label=\"";
5122 output_string
file (func node
); output_string
file " \"];\n"; ) nodes1
;
5123 List.iter
(fun (n, node
) ->
5124 output_string
file "200"; output_int
file n;
5125 output_string
file " [label=\"";
5126 output_string
file (func node
); output_string
file " \"];\n"; ) nodes2
;
5127 List.iter
(fun (i1
,i2
) ->
5128 output_string
file "100"; output_int
file i1
; output_string
file " -> " ;
5129 output_string
file "100"; output_int
file i2
; output_string
file " ;\n";
5132 List.iter
(fun (i1
,i2
) ->
5133 output_string
file "200"; output_int
file i1
; output_string
file " -> " ;
5134 output_string
file "200"; output_int
file i2
; output_string
file " ;\n"; )
5136 (* output_string file "500 -> 1001; 500 -> 2001}\n" ; *)
5137 output_string
file "}\n" ;
5139 let status = Unix.system
"viewdot test.dot" in
5144 (*****************************************************************************)
5146 (*****************************************************************************)
5149 let map = List.map (* note: really really slow, use rev_map if possible *)
5150 let filter = List.filter
5151 let fold = List.fold_left
5152 let member = List.mem
5153 let iter = List.iter
5154 let find = List.find
5155 let exists = List.exists
5156 let forall = List.for_all
5157 let big_union f xs = xs +> map f +> fold union_set empty_set
5158 (* let empty = [] *)
5160 let sort = List.sort
5161 let length = List.length
5162 (* in prelude now: let null xs = match xs with [] -> true | _ -> false *)
5165 let is_singleton = fun xs -> List.length xs =|= 1
5167 (*****************************************************************************)
5168 (* Geometry (raytracer) *)
5169 (*****************************************************************************)
5171 type vector
= (float * float * float)
5173 type color
= vector
(* color(0-1) *)
5175 (* todo: factorise *)
5176 let (dotproduct
: vector
* vector
-> float) =
5177 fun ((x1
,y1
,z1
),(x2
,y2
,z2
)) -> (x1
*.x2
+. y1
*.y2
+. z1
*.z2
)
5178 let (vector_length
: vector
-> float) =
5179 fun (x,y,z
) -> sqrt
(square x +. square y +. square z
)
5180 let (minus_point
: point
* point
-> vector
) =
5181 fun ((x1
,y1
,z1
),(x2
,y2
,z2
)) -> ((x1
-. x2
),(y1
-. y2
),(z1
-. z2
))
5182 let (distance
: point
* point
-> float) =
5183 fun (x1
, x2
) -> vector_length
(minus_point
(x2
,x1
))
5184 let (normalise
: vector
-> vector
) =
5186 let len = vector_length
(x,y,z
) in (x /. len, y /. len, z
/. len)
5187 let (mult_coeff
: vector
-> float -> vector
) =
5188 fun (x,y,z
) c -> (x *. c, y *. c, z
*. c)
5189 let (add_vector
: vector
-> vector
-> vector
) =
5190 fun v1 v2 -> let ((x1
,y1
,z1
),(x2
,y2
,z2
)) = (v1,v2) in
5191 (x1
+.x2
, y1
+.y2
, z1
+.z2
)
5192 let (mult_vector
: vector
-> vector
-> vector
) =
5193 fun v1 v2 -> let ((x1
,y1
,z1
),(x2
,y2
,z2
)) = (v1,v2) in
5194 (x1
*.x2
, y1
*.y2
, z1
*.z2
)
5195 let sum_vector = List.fold_left add_vector
(0.0,0.0,0.0)
5197 (*****************************************************************************)
5198 (* Pics (raytracer) *)
5199 (*****************************************************************************)
5201 type pixel
= (int * int * int) (* RGB *)
5203 (* required pixel list in row major order, line after line *)
5204 let (write_ppm
: int -> int -> (pixel list
) -> string -> unit) = fun
5205 width height
xs filename ->
5206 let chan = open_out
filename in
5208 output_string
chan "P6\n";
5209 output_string
chan ((string_of_int width
) ^
"\n");
5210 output_string
chan ((string_of_int height
) ^
"\n");
5211 output_string
chan "255\n";
5212 List.iter (fun (r,g
,b) ->
5213 List.iter (fun byt
-> output_byte
chan byt
) [r;g
;b]
5218 let test_ppm1 () = write_ppm
100 100
5219 ((generate
(50*100) (1,45,100)) ++ (generate
(50*100) (1,1,100)))
5222 (*****************************************************************************)
5224 (*****************************************************************************)
5225 type diff
= Match
| BnotinA
| AnotinB
5227 let (diff
: (int -> int -> diff
-> unit)-> (string list
* string list
) -> unit)=
5229 let file1 = "/tmp/diff1-" ^
(string_of_int
(Unix.getuid
())) in
5230 let file2 = "/tmp/diff2-" ^
(string_of_int
(Unix.getuid
())) in
5231 let fileresult = "/tmp/diffresult-" ^
(string_of_int
(Unix.getuid
())) in
5232 write_file file1 (unwords
xs);
5233 write_file file2 (unwords
ys);
5235 ("diff --side-by-side -W 1 " ^
file1 ^
" " ^
file2 ^
" > " ^
fileresult);
5236 let res = cat fileresult in
5239 res +> List.iter (fun s ->
5241 | ("" | " ") -> f !a !b Match
; incr
a; incr
b;
5242 | ">" -> f !a !b BnotinA
; incr
b;
5243 | ("|" | "/" | "\\" ) ->
5244 f !a !b BnotinA
; f !a !b AnotinB
; incr
a; incr
b;
5245 | "<" -> f !a !b AnotinB
; incr
a;
5246 | _ -> raise Impossible
5251 ["0";"a";"b";"c";"d"; "f";"g";"h";"j";"q"; "z"]
5252 [ "a";"b";"c";"d";"e";"f";"g";"i";"j";"k";"r";"x";"y";"z"]
5253 (fun x y -> pr "match")
5254 (fun x y -> pr "a_not_in_b")
5255 (fun x y -> pr "b_not_in_a")
5258 let (diff2
: (int -> int -> diff
-> unit) -> (string * string) -> unit) =
5259 fun f (xstr
,ystr
) ->
5260 write_file "/tmp/diff1" xstr
;
5261 write_file "/tmp/diff2" ystr
;
5263 ("diff --side-by-side --left-column -W 1 " ^
5264 "/tmp/diff1 /tmp/diff2 > /tmp/diffresult");
5265 let res = cat "/tmp/diffresult" in
5268 res +> List.iter (fun s ->
5270 | "(" -> f !a !b Match
; incr
a; incr
b;
5271 | ">" -> f !a !b BnotinA
; incr
b;
5272 | "|" -> f !a !b BnotinA
; f !a !b AnotinB
; incr
a; incr
b;
5273 | "<" -> f !a !b AnotinB
; incr
a;
5274 | _ -> raise Impossible
5278 (*****************************************************************************)
5279 (* Parsers (aop-colcombet) *)
5280 (*****************************************************************************)
5282 let parserCommon lexbuf parserer lexer
=
5284 let result = parserer lexer lexbuf
in
5286 with Parsing.Parse_error
->
5287 print_string
"buf: "; print_string lexbuf
.Lexing.lex_buffer
;
5289 print_string
"current: "; print_int lexbuf
.Lexing.lex_curr_pos
;
5291 raise
Parsing.Parse_error
5294 (* marche pas ca neuneu *)
5296 let getDoubleParser parserer lexer string =
5297 let lexbuf1 = Lexing.from_string string in
5298 let chan = open_in string in
5299 let lexbuf2 = Lexing.from_channel chan in
5300 (parserCommon lexbuf1 parserer lexer , parserCommon lexbuf2 parserer lexer )
5303 let getDoubleParser parserer lexer
=
5306 let lexbuf1 = Lexing.from_string
string in
5307 parserCommon lexbuf1 parserer lexer
5310 let chan = open_in
string in
5311 let lexbuf2 = Lexing.from_channel
chan in
5312 parserCommon lexbuf2 parserer lexer
5316 (*****************************************************************************)
5317 (* parser combinators *)
5318 (*****************************************************************************)
5320 (* cf parser_combinators.ml
5322 * Could also use ocaml stream. but not backtrack and forced to do LL,
5323 * so combinators are better.
5328 (*****************************************************************************)
5329 (* Parser related (cocci) *)
5330 (*****************************************************************************)
5342 let fake_parse_info = {
5343 charpos
= -1; str
= "";
5344 line
= -1; column
= -1; file = "";
5347 let string_of_parse_info x =
5348 spf "%s at %s:%d:%d" x.str
x.file x.line
x.column
5349 let string_of_parse_info_bis x =
5350 spf "%s:%d:%d" x.file x.line
x.column
5352 let (info_from_charpos2
: int -> filename -> (int * int * string)) =
5353 fun charpos
filename ->
5355 (* Currently lexing.ml does not handle the line number position.
5356 * Even if there is some fields in the lexing structure, they are not
5357 * maintained by the lexing engine :( So the following code does not work:
5358 * let pos = Lexing.lexeme_end_p lexbuf in
5359 * sprintf "at file %s, line %d, char %d" pos.pos_fname pos.pos_lnum
5360 * (pos.pos_cnum - pos.pos_bol) in
5361 * Hence this function to overcome the previous limitation.
5363 let chan = open_in
filename in
5364 let linen = ref 0 in
5366 let rec charpos_to_pos_aux last_valid
=
5368 try Some
(input_line
chan)
5369 with End_of_file
when charpos
=|= last_valid
-> None
in
5374 if (!posl + slength s > charpos
)
5377 (!linen, charpos
- !posl, s)
5380 posl := !posl + slength s;
5381 charpos_to_pos_aux !posl;
5383 | None
-> (!linen, charpos
- !posl, "\n")
5385 let res = charpos_to_pos_aux 0 in
5389 let info_from_charpos a b =
5390 profile_code "Common.info_from_charpos" (fun () -> info_from_charpos2
a b)
5394 let full_charpos_to_pos2 = fun filename ->
5396 let size = (filesize filename + 2) in
5398 let arr = Array.create
size (0,0) in
5400 let chan = open_in
filename in
5402 let charpos = ref 0 in
5405 let rec full_charpos_to_pos_aux () =
5407 let s = (input_line
chan) in
5410 (* '... +1 do' cos input_line dont return the trailing \n *)
5411 for i = 0 to (slength s - 1) + 1 do
5412 arr.(!charpos + i) <- (!line, i);
5414 charpos := !charpos + slength s + 1;
5415 full_charpos_to_pos_aux();
5418 for i = !charpos to Array.length arr - 1 do
5419 arr.(i) <- (!line, 0);
5424 full_charpos_to_pos_aux ();
5428 let full_charpos_to_pos a =
5429 profile_code "Common.full_charpos_to_pos" (fun () -> full_charpos_to_pos2 a)
5431 let test_charpos file =
5432 full_charpos_to_pos file +> dump +> pr2
5436 let complete_parse_info filename table
x =
5439 line = fst (table
.(x.charpos));
5440 column
= snd (table
.(x.charpos));
5445 let full_charpos_to_pos_large2 = fun filename ->
5447 let size = (filesize filename + 2) in
5449 (* old: let arr = Array.create size (0,0) in *)
5450 let arr1 = Bigarray.Array1.create
5451 Bigarray.int Bigarray.c_layout
size in
5452 let arr2 = Bigarray.Array1.create
5453 Bigarray.int Bigarray.c_layout
size in
5454 Bigarray.Array1.fill
arr1 0;
5455 Bigarray.Array1.fill
arr2 0;
5457 let chan = open_in
filename in
5459 let charpos = ref 0 in
5462 let rec full_charpos_to_pos_aux () =
5464 let s = (input_line
chan) in
5467 (* '... +1 do' cos input_line dont return the trailing \n *)
5468 for i = 0 to (slength s - 1) + 1 do
5469 (* old: arr.(!charpos + i) <- (!line, i); *)
5470 arr1.{!charpos + i} <- (!line);
5471 arr2.{!charpos + i} <- i;
5473 charpos := !charpos + slength s + 1;
5474 full_charpos_to_pos_aux();
5477 for i = !charpos to (* old: Array.length arr *)
5478 Bigarray.Array1.dim
arr1 - 1 do
5479 (* old: arr.(i) <- (!line, 0); *)
5486 full_charpos_to_pos_aux ();
5488 (fun i -> arr1.{i}, arr2.{i})
5490 let full_charpos_to_pos_large a =
5491 profile_code "Common.full_charpos_to_pos_large"
5492 (fun () -> full_charpos_to_pos_large2 a)
5495 let complete_parse_info_large filename table
x =
5498 line = fst (table
(x.charpos));
5499 column
= snd (table
(x.charpos));
5502 (*---------------------------------------------------------------------------*)
5503 (* Decalage is here to handle stuff such as cpp which include file and who
5506 let (error_messagebis
: filename -> (string * int) -> int -> string)=
5507 fun filename (lexeme
, lexstart
) decalage
->
5509 let charpos = lexstart
+ decalage
in
5511 let (line, pos, linecontent
) = info_from_charpos charpos filename in
5512 sprintf
"File \"%s\", line %d, column %d, charpos = %d
5513 around = '%s', whole content = %s"
5514 filename line pos charpos tok (chop linecontent
)
5516 let error_message = fun filename (lexeme
, lexstart
) ->
5517 try error_messagebis
filename (lexeme
, lexstart
) 0
5520 ("PB in Common.error_message, position " ^
i_to_s lexstart ^
5521 " given out of file:" ^
filename)
5525 let error_message_short = fun filename (lexeme
, lexstart
) ->
5527 let charpos = lexstart
in
5528 let (line, pos, linecontent
) = info_from_charpos charpos filename in
5529 sprintf
"File \"%s\", line %d" filename line
5533 ("PB in Common.error_message, position " ^
i_to_s lexstart ^
5534 " given out of file:" ^
filename);
5539 (*****************************************************************************)
5540 (* Regression testing bis (cocci) *)
5541 (*****************************************************************************)
5543 (* todo: keep also size of file, compute md5sum ? cos maybe the file
5546 * todo: could also compute the date, or some version info of the program,
5547 * can record the first date when was found a OK, the last date where
5548 * was ok, and then first date when found fail. So the
5549 * Common.Ok would have more information that would be passed
5550 * to the Common.Pb of date * date * date * string peut etre.
5552 * todo? maybe use plain text file instead of marshalling.
5555 type score_result
= Ok
| Pb
of string
5557 type score
= (string (* usually a filename *), score_result
) Hashtbl.t
5559 type score_list
= (string (* usually a filename *) * score_result
) list
5562 let empty_score () = (Hashtbl.create
101 : score
)
5566 let regression_testing_vs newscore bestscore
=
5568 let newbestscore = empty_score () in
5571 (hash_to_list newscore
+> List.map fst)
5573 (hash_to_list bestscore
+> List.map fst)
5576 allres +> List.iter (fun res ->
5578 optionise (fun () -> Hashtbl.find newscore
res),
5579 optionise (fun () -> Hashtbl.find bestscore
res)
5581 | None
, None
-> raise Impossible
5583 Printf.printf
"new test file appeared: %s\n" res;
5584 Hashtbl.add newbestscore res x;
5586 Printf.printf
"old test file disappeared: %s\n" res;
5587 | Some newone
, Some bestone
->
5588 (match newone
, bestone
with
5590 Hashtbl.add newbestscore res Ok
5593 "PBBBBBBBB: a test file does not work anymore!!! : %s\n" res;
5594 Printf.printf
"Error : %s\n" x;
5595 Hashtbl.add newbestscore res Ok
5597 Printf.printf
"Great: a test file now works: %s\n" res;
5598 Hashtbl.add newbestscore res Ok
5600 Hashtbl.add newbestscore res (Pb
x);
5604 "Semipb: still error but not same error : %s\n" res;
5605 Printf.printf
"%s\n" (chop ("Old error: " ^
y));
5606 Printf.printf
"New error: %s\n" x;
5610 flush stdout
; flush stderr
;
5614 let regression_testing newscore best_score_file
=
5616 pr2 ("regression file: "^ best_score_file
);
5617 let (bestscore
: score
) =
5618 if not
(Sys.file_exists best_score_file
)
5619 then write_value (empty_score()) best_score_file
;
5620 get_value best_score_file
5622 let newbestscore = regression_testing_vs newscore bestscore
in
5623 write_value newbestscore (best_score_file ^
".old");
5624 write_value newbestscore best_score_file
;
5630 let string_of_score_result v =
5633 | Pb
s -> "Pb: " ^
s
5635 let total_scores score
=
5636 let total = hash_to_list score
+> List.length in
5637 let good = hash_to_list score
+> List.filter
5638 (fun (s, v) -> v =*= Ok
) +> List.length in
5642 let print_total_score score
=
5643 pr2 "--------------------------------";
5645 pr2 "--------------------------------";
5646 let (good, total) = total_scores score
in
5647 pr2 (sprintf
"good = %d/%d" good total)
5649 let print_score score
=
5650 score
+> hash_to_list +> List.iter (fun (k, v) ->
5651 pr2 (sprintf
"% s --> %s" k (string_of_score_result v))
5653 print_total_score score
;
5657 (*****************************************************************************)
5658 (* Scope managment (cocci) *)
5659 (*****************************************************************************)
5661 (* could also make a function Common.make_scope_functions that return
5662 * the new_scope, del_scope, do_in_scope, add_env. Kind of functor :)
5665 type ('
a, '
b) scoped_env
= ('
a, '
b) assoc list
5668 let rec lookup_env f env =
5670 | [] -> raise Not_found
5671 | []::zs -> lookup_env f zs
5674 | None -> lookup_env f (xs::zs)
5677 let member_env_key k env =
5679 let _ = lookup_env (fun (k',v) -> if k = k' then Some v else None) env in
5681 with Not_found -> false
5685 let rec lookup_env k env
=
5687 | [] -> raise Not_found
5688 | []::zs
-> lookup_env k zs
5689 | ((k'
,v)::xs)::zs
->
5692 else lookup_env k (xs::zs
)
5694 let member_env_key k env
=
5695 match optionise (fun () -> lookup_env k env
) with
5700 let new_scope scoped_env
= scoped_env
:= []::!scoped_env
5701 let del_scope scoped_env
= scoped_env
:= List.tl
!scoped_env
5703 let do_in_new_scope scoped_env
f =
5705 new_scope scoped_env
;
5707 del_scope scoped_env
;
5711 let add_in_scope scoped_env def
=
5712 let (current, older
) = uncons !scoped_env
in
5713 scoped_env
:= (def
::current)::older
5719 (* note that ocaml hashtbl store also old value of a binding when add
5720 * add a newbinding; that's why del_scope works
5723 type ('
a, '
b) scoped_h_env
= {
5724 scoped_h
: ('
a, '
b) Hashtbl.t;
5725 scoped_list
: ('
a, '
b) assoc list
;
5728 let empty_scoped_h_env () = {
5729 scoped_h
= Hashtbl.create
101;
5732 let clone_scoped_h_env x =
5733 { scoped_h
= Hashtbl.copy
x.scoped_h
;
5734 scoped_list
= x.scoped_list
;
5737 let rec lookup_h_env k env
=
5738 Hashtbl.find env
.scoped_h
k
5740 let member_h_env_key k env
=
5741 match optionise (fun () -> lookup_h_env k env
) with
5746 let new_scope_h scoped_env
=
5747 scoped_env
:= {!scoped_env
with scoped_list
= []::!scoped_env
.scoped_list
}
5748 let del_scope_h scoped_env
=
5750 List.hd
!scoped_env
.scoped_list
+> List.iter (fun (k, v) ->
5751 Hashtbl.remove !scoped_env
.scoped_h
k
5753 scoped_env
:= {!scoped_env
with scoped_list
=
5754 List.tl
!scoped_env
.scoped_list
5758 let do_in_new_scope_h scoped_env
f =
5760 new_scope_h scoped_env
;
5762 del_scope_h scoped_env
;
5767 let add_in_scope scoped_env def =
5768 let (current, older) = uncons !scoped_env in
5769 scoped_env := (def::current)::older
5772 let add_in_scope_h x (k,v) =
5774 Hashtbl.add !x.scoped_h
k v;
5775 x := { !x with scoped_list
=
5776 ((k,v)::(List.hd
!x.scoped_list
))::(List.tl
!x.scoped_list
);
5780 (*****************************************************************************)
5782 (*****************************************************************************)
5784 (* let ansi_terminal = ref true *)
5786 let (_execute_and_show_progress_func
: (int (* length *) -> ((unit -> unit) -> unit) -> unit) ref)
5789 failwith
"no execute yet, have you included common_extra.cmo?"
5794 let execute_and_show_progress len f =
5795 !_execute_and_show_progress_func
len f
5798 (* now in common_extra.ml:
5799 * let execute_and_show_progress len f = ...
5802 (*****************************************************************************)
5804 (*****************************************************************************)
5806 let _init_random = Random.self_init
()
5808 let random_insert i l =
5809 let p = Random.int (length l +1)
5810 in let rec insert i p l =
5811 if (p = 0) then i::l else (hd l)::insert i (p-1) (tl l)
5814 let rec randomize_list = function
5816 | a::l -> random_insert a (randomize_list l)
5818 let random_list xs =
5819 List.nth xs (Random.int (length xs))
5821 (* todo_opti: use fisher/yates algorithm.
5822 * ref: http://en.wikipedia.org/wiki/Knuth_shuffle
5824 * public static void shuffle (int[] array)
5826 * Random rng = new Random ();
5827 * int n = array.length;
5830 * int k = rng.nextInt(n + 1); // 0 <= k <= n (!)
5831 * int temp = array[n];
5832 * array[n] = array[k];
5838 let randomize_list xs =
5839 let permut = permutation
xs in
5844 let random_subset_of_list num
xs =
5845 let array = Array.of_list
xs in
5846 let len = Array.length array in
5848 let h = Hashtbl.create
101 in
5849 let cnt = ref num
in
5851 let x = Random.int len in
5852 if not
(Hashtbl.mem
h (array.(x))) (* bugfix2: not just x :) *)
5854 Hashtbl.add h (array.(x)) true; (* bugfix1: not just x :) *)
5858 let objs = hash_to_list h +> List.map fst in
5863 (*****************************************************************************)
5864 (* Flags and actions *)
5865 (*****************************************************************************)
5867 (* I put it inside a func as it can help to give a chance to
5868 * change the globals before getting the options as some
5869 * options sometimes may want to show the default value.
5871 let cmdline_flags_devel () =
5873 "-debugger", Arg.Set
debugger ,
5874 " option to set if launched inside ocamldebug";
5875 "-profile", Arg.Unit
(fun () -> profile := PALL
),
5876 " gather timing information about important functions";
5878 let cmdline_flags_verbose () =
5880 "-verbose_level", Arg.Set_int
verbose_level,
5881 " <int> guess what";
5882 "-disable_pr2_once", Arg.Set
disable_pr2_once,
5883 " to print more messages";
5884 "-show_trace_profile", Arg.Set
show_trace_profile,
5888 let cmdline_flags_other () =
5890 "-nocheck_stack", Arg.Clear
check_stack,
5892 "-batch_mode", Arg.Set
_batch_mode,
5896 (* potentially other common options but not yet integrated:
5898 "-timeout", Arg.Set_int timeout,
5899 " <sec> interrupt LFS or buggy external plugins";
5901 (* can't be factorized because of the $ cvs stuff, we want the date
5902 * of the main.ml file, not common.ml
5904 "-version", Arg.Unit
(fun () ->
5905 pr2 "version: _dollar_Date: 2008/06/14 00:54:22 _dollar_";
5906 raise
(Common.UnixExit
0)
5910 "-shorthelp", Arg.Unit
(fun () ->
5911 !short_usage_func
();
5912 raise
(Common.UnixExit
0)
5914 " see short list of options";
5915 "-longhelp", Arg.Unit
(fun () ->
5917 raise
(Common.UnixExit
0)
5919 "-help", Arg.Unit
(fun () ->
5921 raise
(Common.UnixExit
0)
5924 "--help", Arg.Unit
(fun () ->
5926 raise
(Common.UnixExit
0)
5932 let cmdline_actions () =
5934 "-test_check_stack", " <limit>",
5935 mk_action_1_arg test_check_stack_size;
5939 (*****************************************************************************)
5941 (*****************************************************************************)
5942 (* stuff put here cos of of forward definition limitation of ocaml *)
5945 (* Infix trick, seen in jane street lib and harrop's code, and maybe in GMP *)
5946 module Infix
= struct
5953 let main_boilerplate f =
5954 if not
(!Sys.interactive
) then
5955 exn_to_real_unixexit (fun () ->
5957 Sys.set_signal
Sys.sigint
(Sys.Signal_handle
(fun _ ->
5958 pr2 "C-c intercepted, will do some cleaning before exiting";
5959 (* But if do some try ... with e -> and if do not reraise the exn,
5960 * the bubble never goes at top and so I cant really C-c.
5962 * A solution would be to not raise, but do the erase_temp_file in the
5963 * syshandler, here, and then exit.
5964 * The current solution is to not do some wild try ... with e
5965 * by having in the exn handler a case: UnixExit x -> raise ... | e ->
5967 Sys.set_signal
Sys.sigint
Sys.Signal_default
;
5968 raise
(UnixExit
(-1))
5971 (* The finalize below makes it tedious to go back to exn when use
5972 * 'back' in the debugger. Hence this special case. But the
5973 * Common.debugger will be set in main(), so too late, so
5974 * have to be quicker
5976 if Sys.argv
+> Array.to_list
+> List.exists (fun x -> x =$
= "-debugger")
5977 then debugger := true;
5980 pp_do_in_zero_box (fun () ->
5981 f(); (* <---- here it is *)
5984 if !profile <> PNONE
5985 then pr2 (profile_diagnostic ());
5986 erase_temp_files ();
5989 (* let _ = if not !Sys.interactive then (main ()) *)
5992 (* based on code found in cameleon from maxence guesdon *)
5993 let md5sum_of_string s =
5994 let com = spf "echo %s | md5sum | cut -d\" \" -f 1"
5997 match cmd_to_list com with
6001 | _ -> failwith
"md5sum_of_string wrong output"
6005 let with_pr2_to_string f =
6006 let file = new_temp_file "pr2" "out" in
6007 redirect_stdout_stderr file f;
6010 (* julia: convert something printed using format to print into a string *)
6011 let format_to_string f =
6012 let (nm
,o) = Filename.open_temp_file
"format_to_s" ".out" in
6013 Format.set_formatter_out_channel
o;
6015 Format.print_newline
();
6016 Format.print_flush
();
6017 Format.set_formatter_out_channel stdout
;
6019 let i = open_in nm
in
6020 let lines = ref [] in
6022 let cur = input_line
i in
6023 lines := cur :: !lines;
6025 (try loop() with End_of_file
-> ());
6027 command2 ("rm -f " ^ nm
);
6028 String.concat "\n" (List.rev !lines)
6032 (*****************************************************************************)
6034 (*****************************************************************************)
6036 let (generic_print
: '
a -> string -> string) = fun v typ
->
6037 write_value v "/tmp/generic_print";
6039 ("printf 'let (v:" ^ typ ^
")= Common.get_value \"/tmp/generic_print\" " ^
6041 " | calc.top > /tmp/result_generic_print");
6042 cat "/tmp/result_generic_print"
6043 +> drop_while (fun e -> not
(e =~
"^#.*")) +> tail
6046 if (s =~
".*= \\(.+\\)")
6048 else "error in generic_print, not good format:" ^
s)
6050 (* let main () = pr (generic_print [1;2;3;4] "int list") *)
6052 class ['
a] olist
(ys: '
a list
) =
6056 (* method fold f a = List.fold_left f a xs *)
6057 method fold : '
b. ('
b -> '
a -> '
b) -> '
b -> '
b =
6058 fun f accu
-> List.fold_left f accu
xs
6062 (* let _ = write_value ((new setb[])#add 1) "/tmp/test" *)
6063 let typing_sux_test () =
6064 let x = Obj.magic
[1;2;3] in
6065 let f1 xs = List.iter print_int
xs in
6066 let f2 xs = List.iter print_string
xs in
6069 (* let (test: 'a osetb -> 'a ocollection) = fun o -> (o :> 'a ocollection) *)
6070 (* let _ = test (new osetb (Setb.empty)) *)