package rdbg

  1. Overview
  2. Docs

Source file rdbgMain.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
(* Time-stamp: <modified the 07/05/2021 (at 18:49) by Erwan Jahier> *)
(* Opium/morphine like debugger *)
 
open RdbgArg
open RdbgEvent
open Mypervasives

(* a few shortcuts *)
let info_string () =
    let msg =  "The current session parameters are:
     sut: "^ (String.concat "," (List.map reactive_program_to_string args.suts)) ^ "
     env: "^ (String.concat "," (List.map reactive_program_to_string args.envs)) ^ "
     oracle: "^ (String.concat "," (List.map reactive_program_to_string args.oracles)) ^ "
     test length: " ^  (string_of_int args.step_nb) ^ "
     precision: " ^ (string_of_int args.precision) ^ "
     verbosity level: " ^ (string_of_int (args.verbose)) ^ "
     rif file name: " ^ args.output ^ "
     overwrite rif file? "
      ^ (if args.overwrite_output then "yes" else "no") ^ "
     coverage file name: " ^ args.cov_file ^ "
     do we stop  when an oracle returns false? " 
      ^ (if args.stop_on_oracle_error then "yes" else "no") ^ "
     display local var? " ^ (if (args.display_local_var) then "yes" else "no") ^ "

"
    in
    msg

let info () =
  output_string args.ocr (info_string ());
  flush args.ocr


let i = info

let run () = RdbgRun.start ()
let _next e = e.next
let _data e = e.data
let _terminate e = e.terminate
let off () = RdbgArg.args.RdbgArg.rdbg <- false
let _on () = RdbgArg.args.RdbgArg.rdbg <- true

let _ = 
  RdbgArg.args.RdbgArg.rdbg <- true


(* XXX rm? *)
let (get_val_event : RdbgEvent.t -> unit) =
  fun e -> 
    let nl,vl = List.split e.data in
    let nl = List.map (fun n -> String.uncapitalize_ascii n) nl in
    let vstrl = List.map (Data.val_to_string (string_of_float)) vl in
    let str =
      "let " ^ (String.concat "," nl) ^ 
        " = " ^ (String.concat "," vstrl) ^ ";;\n"
    in
    print_string (str)

(* (Ugly?) hack to be able to display online help

   I suppose that "rdbg.mli" is formatted like this:

(** cmd help message *)
val cmd : <cmd profile>

where 
   - val begins a line,
   - the cmd profile fits on a line
   - the space before the ":" matters
   
*)

let rdbg_lib_dir = 
  try
    let path = Mypervasives.run ("ocamlfind query rdbg") (fun s -> Some s) in
    let path = List.hd path in
    path 
  with _  -> (* try something else *)
    try
      let path = Mypervasives.run ("ocamlc -where") (fun s -> Some s) in
      let path = List.hd path in
      let sep = "/" in
      let l = Str.split (Str.regexp sep) path in
      let l = "rdbg-plugin"::(List.rev (List.tl l)) in
      let l = List.rev l in
      String.concat sep l
    with _ ->  (* try something else *)
      try
        let path = Mypervasives.run ("locate rdbg") (fun s -> Some s) in
        let path = List.hd path in
        path 
      with _ -> "" 
                
let rdbg_mli = 
  try readfile (Filename.concat rdbg_lib_dir "rdbgMain.mli"),"rdbgMain.ml"
  with _ -> "",""
let rdbg_utils_mli = 
  try readfile (Filename.concat rdbg_lib_dir "rdbgStdLib.mli"),"rdbgStdLib.ml"
  with _ -> "",""
let callgraph_mli = 
  try readfile (Filename.concat rdbg_lib_dir "callgraph.mli"),"callgraph.ml"
  with _ -> "",""



(* name, (profile,msg,category,file)  *)
type docu = string * (string * string * string * string)

(* parse the mli to get documentation *)
let (get_cmd_list: string * string -> docu list) =
  fun (mli, file) -> 
  let rec aux acc i0 = 
    try
      let i3 = Str.search_forward (Str.regexp ("^val ")) mli i0 in
      let i1 = Str.search_backward (Str.regexp ("^(\\*\\*")) mli i3 in
      let i1bis = (Str.search_forward (Str.regexp (":")) mli i1) - 1 in
      let i2 = Str.search_forward (Str.regexp ("\\*)")) mli i1 in
      let i4 = (Str.search_forward (Str.regexp ":") mli i3) - 1 in
      let i5 = Str.search_forward (Str.regexp "\n") mli i4 in
      if i1bis = i4 then ( (* no category => don't appear in the online doc *)
        if args.debug_rdbg then
          Printf.eprintf "No category for %s\n%!" (String.sub mli (i3+4) (i4-i3-4));
        aux acc i5
      )
      else if i1 < i0 then (
        if args.debug_rdbg then
          Printf.eprintf "No  help msg for for %s\n%!" (String.sub mli (i3+4) (i4-i3-4));
        aux acc i5
      ) else 
      (try 
         let help,cat =
           String.sub mli (i1bis+2) (i2-i1bis-2),
           String.sub mli (i1+4) (i1bis-i1-3)
         in
         let cmd = String.sub mli (i3+4) (i4-i3-4) in
         let profile = String.sub mli (i4+3) (i5-i4-3) in
         if args.debug_rdbg then (
           Printf.eprintf 
             "===> %si: i0=%i i1=%i i1bis=%i i2=%i i3=%i i4=%i i5=%i \n%!" 
             file i0 i1 i1bis i2 i3 i4 i5; 
           Printf.eprintf 
             "\tcmd=%s\n\tprofile=%s\n\thelp=%s\n\tcat=%s\n\tfile=%s\n%!"
             cmd profile help cat file; 
           flush stderr
         ); 
         aux ((cmd,(profile,help,cat,file))::acc) i5
       with Invalid_argument _ ->
         if args.debug_rdbg then Printf.eprintf
             "Bad format in comment in %si: i0=%i i1=%i i1bis=%i i2=%i i3=%i i4=%i i5=%i \n%!"
           file i0 i1 i1bis i2 i3 i4 i5;
         aux acc i5)
    with Not_found -> acc

  in
  List.rev(aux [] 0)

let (cmd_list: docu list) = 
  get_cmd_list rdbg_mli

let cmd_list_utils = get_cmd_list rdbg_utils_mli
let cmd_callgraph = get_cmd_list callgraph_mli
let all_cmds = ref (cmd_list @ cmd_list_utils @ cmd_callgraph)
let get_doc c  = try List.assoc c !all_cmds with Not_found -> "","","",""
let doc_prof c = (fun (x,_,_,_) -> x) (get_doc c)
let doc_msg c  = (fun (_, x,_,_) -> x) (get_doc c)
let doc_label c = (fun (_, _, x,_) -> x) (get_doc c)
let doc_file c = (fun (_, _, _, x) -> x) (get_doc c)
let add_doc_entry cmd profile msg cat file =
  if List.mem_assoc cmd !all_cmds then (
    Printf.printf
        "Warning: RdbgMain.add_doc_entry: the '%s' command already exist, and is overwritten\n
%!" cmd ;
    all_cmds := List.remove_assoc cmd !all_cmds
  );
  all_cmds := (cmd,(profile,msg,cat,file))::!all_cmds


let _get_profile str =
  try 
    let i = Str.search_forward (Str.regexp_string ("val "^str)) (fst rdbg_mli) 0 in
    let j = Str.search_forward (Str.regexp_string "\n")  (fst rdbg_mli) i in
      String.sub (fst rdbg_mli) (i+4) (j-i+4)
  with Not_found -> ""


let _print_cmd_list = 
  List.iter 
    (fun (cmd, (profile,_msg, _cat)) -> Printf.printf "\t%12s : %s\n" cmd profile)
    
let print_cmd_list2_string l = 
  List.fold_left  
    (fun acc (cmd, (_profile,msg, _cat, file)) ->
       let msg = try (* let's only keep the first line *)
           let i = Str.search_forward (Str.regexp "\n") msg 0 in
           (String.sub msg 0 i) 
         with Not_found -> msg
       in
       let s = String.length msg in
       let msg = if (s) < 45 then msg else
           (String.sub msg 0 42) ^ "..." 
       in
       let blank = String.make (max 0 (45-s)) ' ' in
       Printf.sprintf "%s\n%16s : %s%s (%s)" acc cmd msg blank file)
    ""
    l
    
let print_cmd_list2 l =
  Printf.printf "%s\n%!" (print_cmd_list2_string l)

let (apropos : string -> unit) =
  fun str -> 
    let l = List.filter 
        (fun (cmd,(_prof,msg,cat,file)) ->
           Str.string_match (Str.regexp (".*"^str^".*")) cmd 0 ||
           Str.string_match (Str.regexp (".*"^str^".*")) msg 0 ||
           Str.string_match (Str.regexp (".*"^str^".*")) cat 0||
           Str.string_match (Str.regexp (".*"^str^".*")) file 0
        ) !all_cmds 
    in
      print_cmd_list2 l
  


let (sort_cmd_by_categories: unit -> (string * docu list) list) =
  fun () ->
  let t = Hashtbl.create 5 in
  List.iter
    (fun (cmd, (p,m,cat,file)) ->
       match Hashtbl.find_opt t cat with
       | None -> Hashtbl.add t cat [(cmd,(p,m,cat,file))]
       | Some l -> Hashtbl.replace t cat ((cmd,(p,m,cat,file))::l)
    )
    !all_cmds;
  Hashtbl.fold (fun cat l acc -> (cat,l)::acc) t []
  

let (help_string:string -> string) =
  fun cmd ->
    if cmd="base" then (
      ("Type 
help \"function\";; 
  to obtain more help on the following functions: \n"^
      print_cmd_list2_string cmd_list)
    ) 
    else if cmd="utils" then (
      print_cmd_list2_string cmd_list_utils
    )
    else if cmd="cat" then (
      let docl = sort_cmd_by_categories () in
      let cat = fst (List.split docl) in
      Printf.sprintf "Available categories are: \n\t - %s " (String.concat "\n\t - " cat)
    )
    else if List.mem_assoc cmd !all_cmds then (
      let prof,help,cat,file = List.assoc cmd !all_cmds in
        Printf.sprintf "%s : %s [%s] (%s)\n%s\n" cmd prof cat file help 
    )
    else
      let docl = sort_cmd_by_categories () in
       match List.assoc_opt cmd docl with
       | None ->
         Printf.sprintf  "Unknown function '%s'. Available functions are: %s" cmd
        (String.concat "," (fst (List.split !all_cmds)))
       | Some cmds -> 
         print_cmd_list2_string (List.rev cmds)
      
let (help:string -> unit) = fun str -> 
  Printf.printf "%s\n%!" (help_string str)
    

let q () = print_string "bye!\n";flush stdout;exit 0
let quit () = q ()


let h = help
let a = apropos

let (man:unit -> unit) =
  fun () -> 
    output_string stdout " rdbg is a Reactive program DeBuGger. 
 - web doc:  http://www-verimag.imag.fr/DIST-TOOLS/SYNCHRONE/rdbg
 - tutorials:http://www-verimag.imag.fr/DIST-TOOLS/vtt/rdbg
 - online doc:
   + help cat     (* List commands categories *)
   + help <a cat> (* List commands related to a given category *)
   + help <a command>   (* Print the documentation of a command/function *)
   + apropos <a string> (* List functions related a string *)
   + apropos            (* List all functions *)
   + h (* Shortcut for help    *)
   + a (* Shortcut for apropos *)
   + l (* List rdbg commands *)
";
  flush stdout
 
let prompt = "(rdbg) "
let get_prompt () = prompt 
(* let set_prompt str = prompt := str *)
                 

OCaml

Innovation. Community. Security.