(** HTML Renderer Renders the output of computations on a given program as an HTML webpage. *) (** Generates a fresh unique identifier *) let fresh_uuid = let next = ref 0 in fun () -> let out = !next in incr next ; out (** Checks whether a submethod is relevant to show, or whether it should be hidden by default. *) let is_sub_relevant sub = Renderer.AnnotAsm.( List.exists (fun instr -> instr.instr_annot.Renderer.events <> []) sub.sub_asm ) (** Box `AnnotAsm.asm_info_t` as a Jingoo tvalue *) let render_prog_box annotated_prog = Jingoo.Jg_types.(Renderer.AnnotAsm.( let render_addr addr = (Format.sprintf "%04x" addr) in List.map (fun render_sub -> [ ("sub_section", box_string render_sub.sub_section); ("sub_name", box_string render_sub.sub_name); ("sub_addr", box_string (Format.sprintf "%016x" render_sub.sub_addr)); ("sub_uuid", box_int @@ fresh_uuid ()); ("sub_relevant", box_int @@ (match is_sub_relevant render_sub with | true -> 1 | false -> 0)); ("sub_asm", List.map (fun row -> [ ("instr_addr", box_string (render_addr row.instr_addr)); ("instr_bytes", box_string ( Format.asprintf "%a" Asm_acquire.pp_hex_bytes row.instr_bytes )); ("instr_asm", box_string row.instr_asm); ("instr_events", (List.map (fun event -> let typ, id, bound, data = Renderer.(match event with | BoxStart(id, bound, data) -> "start", id, bound, data | BoxEnd(id, bound, data) -> "end", id, bound, data ) in [ ("typ", box_string typ); ("id", box_int id); ("bound", box_string @@ render_addr bound); ("data", box_string @@ Format.sprintf "[%d] File %s, %d:%d" data.box_class_id data.box_file data.box_line data.box_col); ("box_eq", box_int data.box_class_id); ] |> box_obj) row.instr_annot.Renderer.events) |> box_list); ] |> box_obj) render_sub.sub_asm |> box_list; )] |> box_obj ) annotated_prog |> box_list )) let render_progs_box annotated_progs = Jingoo.Jg_types.( List.map (fun (prog_path, annotated_prog) -> [ ("path", box_string prog_path); ("prog", render_prog_box annotated_prog) ] |> box_obj) annotated_progs |> box_list ) module IntSet = Set.Make(struct type t = int let compare = compare end) let prog_box_classes render_data = Jingoo.Jg_types.( List.fold_left (fun accu prog -> List.fold_left (fun accu (Renderer.TaggedRange(_, _, box)) -> IntSet.add box.box_class_id accu) accu prog.Renderer.render_boxes) IntSet.empty render_data |> IntSet.elements |> List.map box_int |> box_list ) (** [render multi_render_data] renders the given [render_data] to a string. *) let render multi_render_data = Jingoo.( let annotated_progs = List.map (fun render_data -> render_data.Renderer.render_prog_path, Renderer.render_data_to_annotated_asm render_data) multi_render_data in let models = [ ("progs", render_progs_box annotated_progs); ("box_classes", prog_box_classes multi_render_data); ] in Jg_template.from_file "src/render_html.jingoo" ~models:models )