1
- [@@@ warning " +A-4-44" ]
1
+ [@@@ warning " +A-4-32- 44" ]
2
2
3
3
open ! Support
4
4
open Beluga
@@ -27,10 +27,13 @@ module CallsRecord : sig
27
27
28
28
val add_program_call : t -> Id .cid_prog -> unit
29
29
30
- val has_program_call : t -> Id .cid_prog -> bool [ @@ warning "-32" ]
30
+ val has_program_call : t -> Id .cid_prog -> bool
31
31
32
32
(* * [iter f r] iteratively applies [f] over the program calls added to [r]. *)
33
33
val iter : (Id .cid_prog -> unit ) -> t -> unit
34
+
35
+ (* * [to_set r] is the set of called program IDs recorded in [r]. *)
36
+ val to_set : t -> Id.Prog.Set .t
34
37
end = struct
35
38
type t = { mutable called_programs : Id.Prog.Set .t }
36
39
@@ -43,6 +46,8 @@ end = struct
43
46
Id.Prog.Set. mem prog calls.called_programs
44
47
45
48
let iter f calls = Id.Prog.Set. iter f calls.called_programs
49
+
50
+ let to_set calls = calls.called_programs
46
51
end
47
52
48
53
type calls_record = CallsRecord .t
@@ -206,6 +211,10 @@ module CallGraphState : sig
206
211
graph. *)
207
212
val add_program_calls_record : t -> Id .cid_prog -> calls_record -> unit
208
213
214
+ (* * [get_immediate_dependencies state cid] is the set of direct
215
+ dependencies of theorem [cid] in [state]. *)
216
+ val get_immediate_dependencies : t -> Id .cid_prog -> Id.Prog.Set .t
217
+
209
218
(* * [compute_program_call_dependencies state cid] is the set of transitive
210
219
dependencies of theorem [cid] in [state]. That is, it is the set of
211
220
nodes reachable from [cid] in the call graph.
@@ -219,7 +228,6 @@ module CallGraphState : sig
219
228
whenever memoized results have to be invalidated and recomputed from
220
229
scratch. *)
221
230
val clear_memoized_call_dependencies : t -> unit
222
- [@@ warning "-32" ]
223
231
224
232
(* * [set_program_display_name state cid n] sets [n] as the name to use to
225
233
refer to [cid] in [state]. This is only used for pretty-printing the
@@ -253,10 +261,19 @@ end = struct
253
261
Id.Prog.Hashtbl. add state.program_calls_records cid calls;
254
262
clear_memoized_call_dependencies state
255
263
264
+ let get_immediate_dependencies state cid =
265
+ match Id.Prog.Hashtbl. find_opt state.program_calls_records cid with
266
+ | Option. None -> Error. raise (Unknown_program cid)
267
+ | Option. Some calls_record -> CallsRecord. to_set calls_record
268
+
256
269
let compute_program_call_dependencies state cid =
257
270
let to_visit = Queue. create () in
258
271
let visited = Stdlib. ref Id.Prog.Set. empty in
259
- Queue. push cid to_visit;
272
+ (* Add direct dependencies to the [to_visit] queue *)
273
+ (match Id.Prog.Hashtbl. find_opt state.program_calls_records cid with
274
+ | Option. None -> Error. raise (Unknown_program cid)
275
+ | Option. Some calls_record ->
276
+ CallsRecord. iter (fun x -> Queue. add x to_visit) calls_record);
260
277
while Bool. not (Queue. is_empty to_visit) do
261
278
let current_cid = Queue. pop to_visit in
262
279
if Bool. not (Id.Prog.Set. mem current_cid ! visited) then (
@@ -415,6 +432,95 @@ and pp_call_graph_sgn_declaration :
415
432
| Sgn. Val _ ->
416
433
()
417
434
435
+ (* * {2 Dependency Data to JSON} *)
436
+
437
+ let json_of_location : Location.t -> Yojson.Safe.t =
438
+ fun location ->
439
+ if Location. is_ghost location then `Null
440
+ else
441
+ `Assoc
442
+ [ (" filename" , `String (Location. filename location))
443
+ ; (" start_line" , `Int (Location. start_line location))
444
+ ; (" start_column" , `Int (Location. start_column location))
445
+ ; (" stop_line" , `Int (Location. stop_line location))
446
+ ; (" stop_column" , `Int (Location. stop_column location))
447
+ ]
448
+
449
+ let rec json_of_call_graph_sgn : state -> Sgn.sgn -> Yojson.Safe.t =
450
+ fun state sgn ->
451
+ `List
452
+ (List. flatten
453
+ (List1. to_list (List1. map (json_of_call_graph_sgn_file state) sgn)))
454
+
455
+ and json_of_call_graph_sgn_file : state -> Sgn. sgn_file -> Yojson.Safe. t list
456
+ =
457
+ fun state { Sgn. entries; _ } ->
458
+ let programs =
459
+ entries
460
+ |> List. map (dependencies_to_json_call_graph_sgn_entry state)
461
+ |> List. flatten
462
+ in
463
+ programs
464
+
465
+ and dependencies_to_json_call_graph_sgn_entry :
466
+ state -> Sgn. entry -> Yojson.Safe. t list =
467
+ fun state -> function
468
+ | Sgn. Declaration { declaration; _ } ->
469
+ json_of_call_graph_sgn_declaration state declaration
470
+ | Sgn. Pragma _
471
+ | Sgn. Comment _ ->
472
+ []
473
+
474
+ and json_of_cid_prog : Id.cid_prog -> Yojson.Safe.t =
475
+ fun cid -> `Int (Id.Prog. to_int cid)
476
+
477
+ and json_of_call_graph_sgn_declaration :
478
+ state -> Sgn. decl -> Yojson.Safe. t list =
479
+ fun state -> function
480
+ | Sgn. Theorem { cid; _ } ->
481
+ let display_name =
482
+ cid |> CallGraphState. lookup_program_display_name state
483
+ in
484
+ let immediate_dependencies =
485
+ cid
486
+ |> CallGraphState. get_immediate_dependencies state
487
+ |> Id.Prog.Set. to_seq |> Seq. map json_of_cid_prog |> List. of_seq
488
+ in
489
+ let dependencies =
490
+ cid
491
+ |> CallGraphState. compute_program_call_dependencies state
492
+ |> Id.Prog.Set. to_seq |> Seq. map json_of_cid_prog |> List. of_seq
493
+ in
494
+ [ `Assoc
495
+ [ (" id" , json_of_cid_prog cid)
496
+ ; ( " qualified_identifier"
497
+ , `String (Qualified_identifier. show display_name) )
498
+ ; ( " location"
499
+ , json_of_location (Qualified_identifier. location display_name)
500
+ )
501
+ ; (" immediate_dependencies" , `List immediate_dependencies)
502
+ ; (" transitive_dependencies" , `List dependencies)
503
+ ]
504
+ ]
505
+ | Sgn. Recursive_declarations { declarations; _ } ->
506
+ List1. to_list declarations
507
+ |> List. map (json_of_call_graph_sgn_declaration state)
508
+ |> List. flatten
509
+ | Sgn. Module { entries; _ } ->
510
+ entries
511
+ |> List. map (dependencies_to_json_call_graph_sgn_entry state)
512
+ |> List. flatten
513
+ | Sgn. Typ _
514
+ | Sgn. Const _
515
+ | Sgn. CompTyp _
516
+ | Sgn. CompCotyp _
517
+ | Sgn. CompConst _
518
+ | Sgn. CompDest _
519
+ | Sgn. CompTypAbbrev _
520
+ | Sgn. Schema _
521
+ | Sgn. Val _ ->
522
+ []
523
+
418
524
(* * {2 Driver} *)
419
525
420
526
(* * CLI usage: [dune exec beluga_call_graph ./path-to-signature.cfg] *)
@@ -425,7 +531,9 @@ let main () =
425
531
| [ file ] ->
426
532
let _, sgn = Load. load_fresh file in
427
533
let call_graph = construct_call_graph_state sgn in
428
- pp_call_graph_sgn call_graph Format. std_formatter sgn
534
+ Format. fprintf Format. std_formatter " %a@."
535
+ (Yojson.Safe. pretty_print ~std: true )
536
+ (json_of_call_graph_sgn call_graph sgn)
429
537
| [] ->
430
538
Format. fprintf Format. err_formatter
431
539
" Provide the file path to the Beluga signature.@." ;
0 commit comments