1756 lines
50 KiB
OCaml
1756 lines
50 KiB
OCaml
|
(***********************************************************************)
|
||
|
(* OCamldoc *)
|
||
|
(* *)
|
||
|
(* Maxence Guesdon, projet Cristal, INRIA Rocquencourt *)
|
||
|
(* *)
|
||
|
(* Copyright 2001 Institut National de Recherche en Informatique et *)
|
||
|
(* en Automatique. All rights reserved. This file is distributed *)
|
||
|
(* under the terms of the Q Public License version 1.0. *)
|
||
|
(* *)
|
||
|
(***********************************************************************)
|
||
|
|
||
|
|
||
|
(** The types and functions to create a html table representing a dag. Thanks to Daniel De Rauglaudre. *)
|
||
|
|
||
|
type 'a dag = { mutable dag : 'a node array }
|
||
|
and 'a node =
|
||
|
{ mutable pare : idag list; valu : 'a; mutable chil : idag list }
|
||
|
and idag = int
|
||
|
;;
|
||
|
|
||
|
external int_of_idag : idag -> int = "%identity";;
|
||
|
external idag_of_int : int -> idag = "%identity";;
|
||
|
|
||
|
type 'a table = { mutable table : 'a data array array }
|
||
|
and 'a data = { mutable elem : 'a elem; mutable span : span_id }
|
||
|
and 'a elem = Elem of 'a | Ghost of ghost_id | Nothing
|
||
|
and span_id
|
||
|
and ghost_id
|
||
|
;;
|
||
|
|
||
|
external span_id_of_int : int -> span_id = "%identity";;
|
||
|
external int_of_span_id : span_id -> int = "%identity";;
|
||
|
external ghost_id_of_int : int -> ghost_id = "%identity";;
|
||
|
external int_of_ghost_id : ghost_id -> int = "%identity";;
|
||
|
|
||
|
let new_span_id = let i = ref 0 in fun () -> incr i; span_id_of_int !i;;
|
||
|
|
||
|
let new_ghost_id = let i = ref 0 in fun () -> incr i; ghost_id_of_int !i;;
|
||
|
|
||
|
(** creating the html table structure *)
|
||
|
|
||
|
type align = LeftA | CenterA | RightA;;
|
||
|
type table_data = TDstring of string | TDhr of align;;
|
||
|
type html_table = (int * align * table_data) array array;;
|
||
|
|
||
|
let html_table_struct indi_txt phony d t =
|
||
|
let phony =
|
||
|
function
|
||
|
Elem e -> phony d.dag.(int_of_idag e)
|
||
|
| Ghost _ -> false
|
||
|
| Nothing -> true
|
||
|
in
|
||
|
let jlast = Array.length t.table.(0) - 1 in
|
||
|
let elem_txt =
|
||
|
function
|
||
|
Elem e -> indi_txt d.dag.(int_of_idag e)
|
||
|
| Ghost _ -> "|"
|
||
|
| Nothing -> " "
|
||
|
in
|
||
|
let bar_txt =
|
||
|
function
|
||
|
Elem _ | Ghost _ -> "|"
|
||
|
| Nothing -> " "
|
||
|
in
|
||
|
let all_empty i =
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then true
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Nothing -> loop (j + 1)
|
||
|
| e -> if phony e then loop (j + 1) else false
|
||
|
in
|
||
|
loop 0
|
||
|
in
|
||
|
let line_elem_txt i =
|
||
|
let les =
|
||
|
let rec loop les j =
|
||
|
if j = Array.length t.table.(i) then les
|
||
|
else
|
||
|
let x = t.table.(i).(j) in
|
||
|
let next_j =
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then j
|
||
|
else if t.table.(i).(j) = x then loop (j + 1)
|
||
|
else j
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let colspan = 3 * (next_j - j) in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in
|
||
|
let les =
|
||
|
let s =
|
||
|
if t.table.(i).(j).elem = Nothing then " "
|
||
|
else elem_txt t.table.(i).(j).elem
|
||
|
in
|
||
|
(colspan - 2, CenterA, TDstring s) :: les
|
||
|
in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in loop les next_j
|
||
|
in
|
||
|
loop [] 0
|
||
|
in
|
||
|
Array.of_list (List.rev les)
|
||
|
in
|
||
|
let vbars_txt k i =
|
||
|
let les =
|
||
|
let rec loop les j =
|
||
|
if j = Array.length t.table.(i) then les
|
||
|
else
|
||
|
let x = t.table.(i).(j) in
|
||
|
let next_j =
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then j
|
||
|
else if t.table.(i).(j) = x then loop (j + 1)
|
||
|
else j
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let colspan = 3 * (next_j - j) in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in
|
||
|
let les =
|
||
|
let s =
|
||
|
if k > 0 && t.table.(k - 1).(j).elem = Nothing ||
|
||
|
t.table.(k).(j).elem = Nothing then
|
||
|
" "
|
||
|
else if phony t.table.(i).(j).elem then " "
|
||
|
else bar_txt t.table.(i).(j).elem
|
||
|
in
|
||
|
(colspan - 2, CenterA, TDstring s) :: les
|
||
|
in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in loop les next_j
|
||
|
in
|
||
|
loop [] 0
|
||
|
in
|
||
|
Array.of_list (List.rev les)
|
||
|
in
|
||
|
let alone_bar_txt i =
|
||
|
let les =
|
||
|
let rec loop les j =
|
||
|
if j = Array.length t.table.(i) then les
|
||
|
else
|
||
|
let next_j =
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then j
|
||
|
else if t.table.(i).(j).span = x then loop (j + 1)
|
||
|
else j
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let colspan = 3 * (next_j - j) - 2 in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in
|
||
|
let les =
|
||
|
if t.table.(i).(j).elem = Nothing ||
|
||
|
t.table.(i + 1).(j).elem = Nothing then
|
||
|
(colspan, LeftA, TDstring " ") :: les
|
||
|
else
|
||
|
let s =
|
||
|
let all_ph =
|
||
|
let rec loop j =
|
||
|
if j = next_j then true
|
||
|
else if phony t.table.(i + 1).(j).elem then loop (j + 1)
|
||
|
else false
|
||
|
in
|
||
|
loop j
|
||
|
in
|
||
|
if all_ph then " " else "|"
|
||
|
in
|
||
|
(colspan, CenterA, TDstring s) :: les
|
||
|
in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in loop les next_j
|
||
|
in
|
||
|
loop [] 0
|
||
|
in
|
||
|
Array.of_list (List.rev les)
|
||
|
in
|
||
|
let exist_several_branches i k =
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then false
|
||
|
else
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let e = t.table.(k).(j).elem in
|
||
|
let rec loop1 j =
|
||
|
if j = Array.length t.table.(i) then false
|
||
|
else if t.table.(i).(j).elem = Nothing then loop j
|
||
|
else if t.table.(i).(j).span <> x then loop j
|
||
|
else if t.table.(k).(j).elem <> e then true
|
||
|
else loop1 (j + 1)
|
||
|
in
|
||
|
loop1 (j + 1)
|
||
|
in
|
||
|
loop 0
|
||
|
in
|
||
|
let hbars_txt i k =
|
||
|
let les =
|
||
|
let rec loop les j =
|
||
|
if j = Array.length t.table.(i) then les
|
||
|
else
|
||
|
let next_j =
|
||
|
let e = t.table.(i).(j).elem in
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i) then j
|
||
|
else if e = Nothing && t.table.(i).(j).elem = Nothing then
|
||
|
loop (j + 1)
|
||
|
else if t.table.(i).(j).span = x then loop (j + 1)
|
||
|
else j
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let rec loop1 les l =
|
||
|
if l = next_j then loop les next_j
|
||
|
else
|
||
|
let next_l =
|
||
|
let y = t.table.(k).(l) in
|
||
|
match y.elem with
|
||
|
Elem _ | Ghost _ ->
|
||
|
let rec loop l =
|
||
|
if l = Array.length t.table.(i) then l
|
||
|
else if t.table.(k).(l) = y then loop (l + 1)
|
||
|
else l
|
||
|
in
|
||
|
loop (l + 1)
|
||
|
| _ -> l + 1
|
||
|
in
|
||
|
if next_l > next_j then
|
||
|
begin
|
||
|
Printf.eprintf
|
||
|
"assert false i %d k %d l %d next_l %d next_j %d\n" i k l
|
||
|
next_l next_j;
|
||
|
flush stderr
|
||
|
end;
|
||
|
let next_l = min next_l next_j in
|
||
|
let colspan = 3 * (next_l - l) - 2 in
|
||
|
let les =
|
||
|
match t.table.(i).(l).elem, t.table.(i + 1).(l).elem with
|
||
|
Nothing, _ | _, Nothing ->
|
||
|
(colspan + 2, LeftA, TDstring " ") :: les
|
||
|
| _ ->
|
||
|
let ph s =
|
||
|
if phony t.table.(k).(l).elem then TDstring " "
|
||
|
else s
|
||
|
in
|
||
|
if l = j && next_l = next_j then
|
||
|
let les = (1, LeftA, TDstring " ") :: les in
|
||
|
let s = ph (TDstring "|") in
|
||
|
let les = (colspan, CenterA, s) :: les in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in les
|
||
|
else if l = j then
|
||
|
let les = (1, LeftA, TDstring " ") :: les in
|
||
|
let s = ph (TDhr RightA) in
|
||
|
let les = (colspan, RightA, s) :: les in
|
||
|
let s = ph (TDhr CenterA) in
|
||
|
let les = (1, LeftA, s) :: les in les
|
||
|
else if next_l = next_j then
|
||
|
let s = ph (TDhr CenterA) in
|
||
|
let les = (1, LeftA, s) :: les in
|
||
|
let s = ph (TDhr LeftA) in
|
||
|
let les = (colspan, LeftA, s) :: les in
|
||
|
let les = (1, LeftA, TDstring " ") :: les in les
|
||
|
else
|
||
|
let s = ph (TDhr CenterA) in
|
||
|
(colspan + 2, LeftA, s) :: les
|
||
|
in
|
||
|
loop1 les next_l
|
||
|
in
|
||
|
loop1 les j
|
||
|
in
|
||
|
loop [] 0
|
||
|
in
|
||
|
Array.of_list (List.rev les)
|
||
|
in
|
||
|
let hts =
|
||
|
let rec loop hts i =
|
||
|
if i = Array.length t.table then hts
|
||
|
else if i = Array.length t.table - 1 && all_empty i then hts
|
||
|
else
|
||
|
let hts = line_elem_txt i :: hts in
|
||
|
let hts =
|
||
|
if i < Array.length t.table - 1 then
|
||
|
let hts = vbars_txt (i + 1) i :: hts in
|
||
|
let hts =
|
||
|
if exist_several_branches i i then
|
||
|
alone_bar_txt i :: hbars_txt i i :: hts
|
||
|
else hts
|
||
|
in
|
||
|
let hts =
|
||
|
if exist_several_branches i (i + 1) &&
|
||
|
(i < Array.length t.table - 2 ||
|
||
|
not (all_empty (i + 1))) then
|
||
|
vbars_txt (i + 1) (i + 1) :: hbars_txt i (i + 1) :: hts
|
||
|
else hts
|
||
|
in
|
||
|
hts
|
||
|
else hts
|
||
|
in
|
||
|
loop hts (i + 1)
|
||
|
in
|
||
|
loop [] 0
|
||
|
in
|
||
|
Array.of_list (List.rev hts)
|
||
|
;;
|
||
|
|
||
|
(** transforming dag into table *)
|
||
|
|
||
|
let ancestors d =
|
||
|
let rec loop i =
|
||
|
if i = Array.length d.dag then []
|
||
|
else
|
||
|
let n = d.dag.(i) in
|
||
|
if n.pare = [] then idag_of_int i :: loop (i + 1) else loop (i + 1)
|
||
|
in
|
||
|
loop 0
|
||
|
;;
|
||
|
|
||
|
let get_children d parents =
|
||
|
let rec merge_children children el =
|
||
|
List.fold_right
|
||
|
(fun (x, _) children ->
|
||
|
match x with
|
||
|
Elem e ->
|
||
|
let e = d.dag.(int_of_idag e) in
|
||
|
List.fold_right
|
||
|
(fun c children ->
|
||
|
if List.mem c children then children else c :: children)
|
||
|
e.chil children
|
||
|
| _ -> [])
|
||
|
el children
|
||
|
in
|
||
|
merge_children [] parents
|
||
|
;;
|
||
|
|
||
|
let rec get_block t i j =
|
||
|
if j = Array.length t.table.(i) then None
|
||
|
else if j = Array.length t.table.(i) - 1 then
|
||
|
let x = t.table.(i).(j) in Some ([x.elem, 1], 1, x.span)
|
||
|
else
|
||
|
let x = t.table.(i).(j) in
|
||
|
let y = t.table.(i).(j + 1) in
|
||
|
if y.span = x.span then
|
||
|
match get_block t i (j + 1) with
|
||
|
Some ((x1, c1) :: list, mpc, span) ->
|
||
|
let (list, mpc) =
|
||
|
if x1 = x.elem then (x1, c1 + 1) :: list, max mpc (c1 + 1)
|
||
|
else (x.elem, 1) :: (x1, c1) :: list, max mpc c1
|
||
|
in
|
||
|
Some (list, mpc, span)
|
||
|
| _ -> assert false
|
||
|
else Some ([x.elem, 1], 1, x.span)
|
||
|
;;
|
||
|
|
||
|
let group_by_common_children d list =
|
||
|
let module O = struct type t = idag;; let compare = compare;; end
|
||
|
in
|
||
|
let module S = Set.Make (O)
|
||
|
in
|
||
|
let nlcsl =
|
||
|
List.map
|
||
|
(fun id ->
|
||
|
let n = d.dag.(int_of_idag id) in
|
||
|
let cs = List.fold_right S.add n.chil S.empty in [id], cs)
|
||
|
list
|
||
|
in
|
||
|
let nlcsl =
|
||
|
let rec loop =
|
||
|
function
|
||
|
[] -> []
|
||
|
| (nl, cs) :: rest ->
|
||
|
let rec loop1 beg =
|
||
|
function
|
||
|
(nl1, cs1) :: rest1 ->
|
||
|
if S.is_empty (S.inter cs cs1) then
|
||
|
loop1 ((nl1, cs1) :: beg) rest1
|
||
|
else
|
||
|
loop ((nl @ nl1, S.union cs cs1) :: (List.rev beg @ rest1))
|
||
|
| [] -> (nl, cs) :: loop rest
|
||
|
in
|
||
|
loop1 [] rest
|
||
|
in
|
||
|
loop nlcsl
|
||
|
in
|
||
|
List.fold_right
|
||
|
(fun (nl, _) a ->
|
||
|
let span = new_span_id () in
|
||
|
List.fold_right (fun n a -> {elem = Elem n; span = span} :: a) nl a)
|
||
|
nlcsl []
|
||
|
;;
|
||
|
|
||
|
let copy_data d = {elem = d.elem; span = d.span};;
|
||
|
|
||
|
let insert_columns t nb j =
|
||
|
let t1 = Array.create (Array.length t.table) [| |] in
|
||
|
for i = 0 to Array.length t.table - 1 do
|
||
|
let line = t.table.(i) in
|
||
|
let line1 = Array.create (Array.length line + nb) line.(0) in
|
||
|
t1.(i) <- line1;
|
||
|
let rec loop k =
|
||
|
if k = Array.length line then ()
|
||
|
else
|
||
|
begin
|
||
|
if k < j then line1.(k) <- copy_data line.(k)
|
||
|
else if k = j then
|
||
|
for r = 0 to nb do line1.(k + r) <- copy_data line.(k) done
|
||
|
else line1.(k + nb) <- copy_data line.(k);
|
||
|
loop (k + 1)
|
||
|
end
|
||
|
in
|
||
|
loop 0
|
||
|
done;
|
||
|
{table = t1}
|
||
|
;;
|
||
|
|
||
|
let rec gcd a b =
|
||
|
if a < b then gcd b a else if b = 0 then a else gcd b (a mod b)
|
||
|
;;
|
||
|
|
||
|
let treat_new_row d t =
|
||
|
let i = Array.length t.table - 1 in
|
||
|
let rec loop t i j =
|
||
|
match get_block t i j with
|
||
|
Some (parents, max_parent_colspan, span) ->
|
||
|
let children = get_children d parents in
|
||
|
let children =
|
||
|
if children = [] then [{elem = Nothing; span = new_span_id ()}]
|
||
|
else
|
||
|
List.map (fun n -> {elem = Elem n; span = new_span_id ()})
|
||
|
children
|
||
|
in
|
||
|
let simple_parents_colspan =
|
||
|
List.fold_left (fun x (_, c) -> x + c) 0 parents
|
||
|
in
|
||
|
if simple_parents_colspan mod List.length children = 0 then
|
||
|
let j = j + simple_parents_colspan in
|
||
|
let children =
|
||
|
let cnt = simple_parents_colspan / List.length children in
|
||
|
List.fold_right
|
||
|
(fun d list ->
|
||
|
let rec loop cnt list =
|
||
|
if cnt = 1 then d :: list
|
||
|
else copy_data d :: loop (cnt - 1) list
|
||
|
in
|
||
|
loop cnt list)
|
||
|
children []
|
||
|
in
|
||
|
let (t, children_rest) = loop t i j in t, children @ children_rest
|
||
|
else
|
||
|
let parent_colspan =
|
||
|
List.fold_left
|
||
|
(fun scm (_, c) -> let g = gcd scm c in scm / g * c)
|
||
|
max_parent_colspan parents
|
||
|
in
|
||
|
let (t, parents, _) =
|
||
|
List.fold_left
|
||
|
(fun (t, parents, j) (x, c) ->
|
||
|
let to_add = parent_colspan / c - 1 in
|
||
|
let t =
|
||
|
let rec loop cc t j =
|
||
|
if cc = 0 then t
|
||
|
else
|
||
|
let t = insert_columns t to_add j in
|
||
|
loop (cc - 1) t (j + to_add + 1)
|
||
|
in
|
||
|
loop c t j
|
||
|
in
|
||
|
t, (x, parent_colspan) :: parents, j + parent_colspan)
|
||
|
(t, [], j) parents
|
||
|
in
|
||
|
let parents = List.rev parents in
|
||
|
let parents_colspan = parent_colspan * List.length parents in
|
||
|
let children_colspan = List.length children in
|
||
|
let g = gcd parents_colspan children_colspan in
|
||
|
let (t, j) =
|
||
|
let cnt = children_colspan / g in
|
||
|
List.fold_left
|
||
|
(fun (t, j) (_, c) ->
|
||
|
let rec loop cc t j =
|
||
|
if cc = 0 then t, j
|
||
|
else
|
||
|
let t = insert_columns t (cnt - 1) j in
|
||
|
let j = j + cnt in loop (cc - 1) t j
|
||
|
in
|
||
|
loop c t j)
|
||
|
(t, j) parents
|
||
|
in
|
||
|
let children =
|
||
|
let cnt = parents_colspan / g in
|
||
|
List.fold_right
|
||
|
(fun d list ->
|
||
|
let rec loop cnt list =
|
||
|
if cnt = 0 then list else d :: loop (cnt - 1) list
|
||
|
in
|
||
|
loop cnt list)
|
||
|
children []
|
||
|
in
|
||
|
let (t, children_rest) = loop t i j in t, children @ children_rest
|
||
|
| None -> t, []
|
||
|
in
|
||
|
loop t i 0
|
||
|
;;
|
||
|
|
||
|
let down_it t i k y =
|
||
|
t.table.(Array.length t.table - 1).(k) <- t.table.(i).(k);
|
||
|
for r = i to Array.length t.table - 2 do
|
||
|
t.table.(r).(k) <- {elem = Ghost (new_ghost_id ()); span = new_span_id ()}
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
(* equilibrate:
|
||
|
in the last line, for all elem A, make fall all As, which are located at
|
||
|
its right side above, to its line,
|
||
|
A |
|
||
|
i.e. transform all . into |
|
||
|
A....... A......A
|
||
|
*)
|
||
|
|
||
|
let equilibrate t =
|
||
|
let ilast = Array.length t.table - 1 in
|
||
|
let last = t.table.(ilast) in
|
||
|
let len = Array.length last in
|
||
|
let rec loop j =
|
||
|
if j = len then ()
|
||
|
else
|
||
|
match last.(j).elem with
|
||
|
Elem x ->
|
||
|
let rec loop1 i =
|
||
|
if i = ilast then loop (j + 1)
|
||
|
else
|
||
|
let rec loop2 k =
|
||
|
if k = len then loop1 (i + 1)
|
||
|
else
|
||
|
match t.table.(i).(k).elem with
|
||
|
Elem y when x = y -> down_it t i k y; loop 0
|
||
|
| _ -> loop2 (k + 1)
|
||
|
in
|
||
|
loop2 0
|
||
|
in
|
||
|
loop1 0
|
||
|
| _ -> loop (j + 1)
|
||
|
in
|
||
|
loop 0
|
||
|
;;
|
||
|
|
||
|
(* group_elem:
|
||
|
transform all x y into x x
|
||
|
A A A A *)
|
||
|
|
||
|
let group_elem t =
|
||
|
for i = 0 to Array.length t.table - 2 do
|
||
|
for j = 1 to Array.length t.table.(0) - 1 do
|
||
|
match t.table.(i + 1).(j - 1).elem, t.table.(i + 1).(j).elem with
|
||
|
Elem x, Elem y when x = y ->
|
||
|
t.table.(i).(j).span <- t.table.(i).(j - 1).span
|
||
|
| _ -> ()
|
||
|
done
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
(* group_ghost:
|
||
|
x x x x |a |a |a |a
|
||
|
transform all |a |b into |a |a and all x y into x x
|
||
|
y z y y A A A A *)
|
||
|
|
||
|
let group_ghost t =
|
||
|
for i = 0 to Array.length t.table - 2 do
|
||
|
for j = 1 to Array.length t.table.(0) - 1 do
|
||
|
begin match t.table.(i + 1).(j - 1).elem, t.table.(i + 1).(j).elem with
|
||
|
Ghost x, Ghost _ ->
|
||
|
if t.table.(i).(j - 1).span = t.table.(i).(j).span then
|
||
|
t.table.(i + 1).(j) <-
|
||
|
{elem = Ghost x; span = t.table.(i + 1).(j - 1).span}
|
||
|
| _ -> ()
|
||
|
end;
|
||
|
match t.table.(i).(j - 1).elem, t.table.(i).(j).elem with
|
||
|
Ghost x, Ghost _ ->
|
||
|
if t.table.(i + 1).(j - 1).elem = t.table.(i + 1).(j).elem then
|
||
|
begin
|
||
|
t.table.(i).(j) <-
|
||
|
{elem = Ghost x; span = t.table.(i).(j - 1).span};
|
||
|
if i > 0 then
|
||
|
t.table.(i - 1).(j).span <- t.table.(i - 1).(j - 1).span
|
||
|
end
|
||
|
| _ -> ()
|
||
|
done
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
(* group_children:
|
||
|
transform all A A into A A
|
||
|
x y x x *)
|
||
|
|
||
|
let group_children t =
|
||
|
for i = 0 to Array.length t.table - 1 do
|
||
|
let line = t.table.(i) in
|
||
|
let len = Array.length line in
|
||
|
for j = 1 to len - 1 do
|
||
|
if line.(j).elem = line.(j - 1).elem && line.(j).elem <> Nothing then
|
||
|
line.(j).span <- line.(j - 1).span
|
||
|
done
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
(* group_span_by_common_children:
|
||
|
in the last line, transform all
|
||
|
A B into A B
|
||
|
x y x x
|
||
|
if A and B have common children *)
|
||
|
|
||
|
let group_span_by_common_children d t =
|
||
|
let module O = struct type t = idag;; let compare = compare;; end
|
||
|
in
|
||
|
let module S = Set.Make (O)
|
||
|
in
|
||
|
let i = Array.length t.table - 1 in
|
||
|
let line = t.table.(i) in
|
||
|
let rec loop j cs =
|
||
|
if j = Array.length line then ()
|
||
|
else
|
||
|
match line.(j).elem with
|
||
|
Elem id ->
|
||
|
let n = d.dag.(int_of_idag id) in
|
||
|
let curr_cs = List.fold_right S.add n.chil S.empty in
|
||
|
if S.is_empty (S.inter cs curr_cs) then loop (j + 1) curr_cs
|
||
|
else
|
||
|
begin
|
||
|
line.(j).span <- line.(j - 1).span;
|
||
|
loop (j + 1) (S.union cs curr_cs)
|
||
|
end
|
||
|
| _ -> loop (j + 1) S.empty
|
||
|
in
|
||
|
loop 0 S.empty
|
||
|
;;
|
||
|
|
||
|
let find_same_parents t i j1 j2 j3 j4 =
|
||
|
let rec loop i j1 j2 j3 j4 =
|
||
|
if i = 0 then i, j1, j2, j3, j4
|
||
|
else
|
||
|
let x1 = t.(i - 1).(j1) in
|
||
|
let x2 = t.(i - 1).(j2) in
|
||
|
let x3 = t.(i - 1).(j3) in
|
||
|
let x4 = t.(i - 1).(j4) in
|
||
|
if x1.span = x4.span then i, j1, j2, j3, j4
|
||
|
else
|
||
|
let j1 =
|
||
|
let rec loop j =
|
||
|
if j < 0 then 0
|
||
|
else if t.(i - 1).(j).span = x1.span then loop (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
loop (j1 - 1)
|
||
|
in
|
||
|
let j2 =
|
||
|
let rec loop j =
|
||
|
if j >= Array.length t.(i) then j - 1
|
||
|
else if t.(i - 1).(j).span = x2.span then loop (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
loop (j2 + 1)
|
||
|
in
|
||
|
let j3 =
|
||
|
let rec loop j =
|
||
|
if j < 0 then 0
|
||
|
else if t.(i - 1).(j).span = x3.span then loop (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
loop (j3 - 1)
|
||
|
in
|
||
|
let j4 =
|
||
|
let rec loop j =
|
||
|
if j >= Array.length t.(i) then j - 1
|
||
|
else if t.(i - 1).(j).span = x4.span then loop (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
loop (j4 + 1)
|
||
|
in
|
||
|
loop (i - 1) j1 j2 j3 j4
|
||
|
in
|
||
|
loop i j1 j2 j3 j4
|
||
|
;;
|
||
|
|
||
|
let find_linked_children t i j1 j2 j3 j4 =
|
||
|
let rec loop i j1 j2 j3 j4 =
|
||
|
if i = Array.length t - 1 then j1, j2, j3, j4
|
||
|
else
|
||
|
let x1 = t.(i).(j1) in
|
||
|
let x2 = t.(i).(j2) in
|
||
|
let x3 = t.(i).(j3) in
|
||
|
let x4 = t.(i).(j4) in
|
||
|
let j1 =
|
||
|
let rec loop j =
|
||
|
if j < 0 then 0
|
||
|
else if t.(i).(j).span = x1.span then loop (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
loop (j1 - 1)
|
||
|
in
|
||
|
let j2 =
|
||
|
let rec loop j =
|
||
|
if j >= Array.length t.(i) then j - 1
|
||
|
else if t.(i).(j).span = x2.span then loop (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
loop (j2 + 1)
|
||
|
in
|
||
|
let j3 =
|
||
|
let rec loop j =
|
||
|
if j < 0 then 0
|
||
|
else if t.(i).(j).span = x3.span then loop (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
loop (j3 - 1)
|
||
|
in
|
||
|
let j4 =
|
||
|
let rec loop j =
|
||
|
if j >= Array.length t.(i) then j - 1
|
||
|
else if t.(i).(j).span = x4.span then loop (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
loop (j4 + 1)
|
||
|
in
|
||
|
loop (i + 1) j1 j2 j3 j4
|
||
|
in
|
||
|
loop i j1 j2 j3 j4
|
||
|
;;
|
||
|
|
||
|
let mirror_block t i1 i2 j1 j2 =
|
||
|
for i = i1 to i2 do
|
||
|
let line = t.(i) in
|
||
|
let rec loop j1 j2 =
|
||
|
if j1 >= j2 then ()
|
||
|
else
|
||
|
let v = line.(j1) in
|
||
|
line.(j1) <- line.(j2); line.(j2) <- v; loop (j1 + 1) (j2 - 1)
|
||
|
in
|
||
|
loop j1 j2
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
let exch_blocks t i1 i2 j1 j2 j3 j4 =
|
||
|
for i = i1 to i2 do
|
||
|
let line = t.(i) in
|
||
|
let saved = Array.copy line in
|
||
|
for j = j1 to j2 do line.(j4 - j2 + j) <- saved.(j) done;
|
||
|
for j = j3 to j4 do line.(j1 - j3 + j) <- saved.(j) done
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
let find_block_with_parents t i jj1 jj2 jj3 jj4 =
|
||
|
let rec loop ii jj1 jj2 jj3 jj4 =
|
||
|
let (nii, njj1, njj2, njj3, njj4) =
|
||
|
find_same_parents t i jj1 jj2 jj3 jj4
|
||
|
in
|
||
|
if nii <> ii || njj1 <> jj1 || njj2 <> jj2 || njj3 <> jj3 ||
|
||
|
njj4 <> jj4 then
|
||
|
let nii = min ii nii in
|
||
|
let (jj1, jj2, jj3, jj4) =
|
||
|
find_linked_children t nii njj1 njj2 njj3 njj4
|
||
|
in
|
||
|
if njj1 <> jj1 || njj2 <> jj2 || njj3 <> jj3 || njj4 <> jj4 then
|
||
|
loop nii jj1 jj2 jj3 jj4
|
||
|
else nii, jj1, jj2, jj3, jj4
|
||
|
else ii, jj1, jj2, jj3, jj4
|
||
|
in
|
||
|
loop i jj1 jj2 jj3 jj4
|
||
|
;;
|
||
|
|
||
|
let push_to_right d t i j1 j2 =
|
||
|
let line = t.(i) in
|
||
|
let rec loop j =
|
||
|
if j = j2 then j - 1
|
||
|
else
|
||
|
let ini_jj1 =
|
||
|
match line.(j - 1).elem with
|
||
|
Nothing -> j - 1
|
||
|
| x ->
|
||
|
let rec same_value j =
|
||
|
if j < 0 then 0
|
||
|
else if line.(j).elem = x then same_value (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
same_value (j - 2)
|
||
|
in
|
||
|
let jj1 = ini_jj1 in
|
||
|
let jj2 = j - 1 in
|
||
|
let jj3 = j in
|
||
|
let jj4 =
|
||
|
match line.(j).elem with
|
||
|
Nothing -> j
|
||
|
| x ->
|
||
|
let rec same_value j =
|
||
|
if j >= Array.length line then j - 1
|
||
|
else if line.(j).elem = x then same_value (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
same_value (j + 1)
|
||
|
in
|
||
|
let (ii, jj1, jj2, jj3, jj4) =
|
||
|
find_block_with_parents t i jj1 jj2 jj3 jj4
|
||
|
in
|
||
|
if jj4 < j2 && jj2 < jj3 then
|
||
|
begin exch_blocks t ii i jj1 jj2 jj3 jj4; loop (jj4 + 1) end
|
||
|
else if jj4 < j2 && jj1 = ini_jj1 && jj2 <= jj4 then
|
||
|
begin mirror_block t ii i jj1 jj4; loop (jj4 + 1) end
|
||
|
else j - 1
|
||
|
in
|
||
|
loop (j1 + 1)
|
||
|
;;
|
||
|
|
||
|
let push_to_left d t i j1 j2 =
|
||
|
let line = t.(i) in
|
||
|
let rec loop j =
|
||
|
if j = j1 then j + 1
|
||
|
else
|
||
|
let jj1 =
|
||
|
match line.(j).elem with
|
||
|
Nothing -> j
|
||
|
| x ->
|
||
|
let rec same_value j =
|
||
|
if j < 0 then 0
|
||
|
else if line.(j).elem = x then same_value (j - 1)
|
||
|
else j + 1
|
||
|
in
|
||
|
same_value (j - 1)
|
||
|
in
|
||
|
let jj2 = j in
|
||
|
let jj3 = j + 1 in
|
||
|
let ini_jj4 =
|
||
|
match line.(j + 1).elem with
|
||
|
Nothing -> j + 1
|
||
|
| x ->
|
||
|
let rec same_value j =
|
||
|
if j >= Array.length line then j - 1
|
||
|
else if line.(j).elem = x then same_value (j + 1)
|
||
|
else j - 1
|
||
|
in
|
||
|
same_value (j + 2)
|
||
|
in
|
||
|
let jj4 = ini_jj4 in
|
||
|
let (ii, jj1, jj2, jj3, jj4) =
|
||
|
find_block_with_parents t i jj1 jj2 jj3 jj4
|
||
|
in
|
||
|
if jj1 > j1 && jj2 < jj3 then
|
||
|
begin exch_blocks t ii i jj1 jj2 jj3 jj4; loop (jj1 - 1) end
|
||
|
else if jj1 > j1 && jj4 = ini_jj4 && jj3 >= jj1 then
|
||
|
begin mirror_block t ii i jj1 jj4; loop (jj1 - 1) end
|
||
|
else j + 1
|
||
|
in
|
||
|
loop (j2 - 1)
|
||
|
;;
|
||
|
|
||
|
let fill_gap d t i j1 j2 =
|
||
|
let t1 =
|
||
|
let t1 = Array.copy t.table in
|
||
|
for i = 0 to Array.length t.table - 1 do
|
||
|
t1.(i) <- Array.copy t.table.(i);
|
||
|
for j = 0 to Array.length t1.(i) - 1 do
|
||
|
t1.(i).(j) <- copy_data t.table.(i).(j)
|
||
|
done
|
||
|
done;
|
||
|
t1
|
||
|
in
|
||
|
let j2 = push_to_left d t1 i j1 j2 in
|
||
|
let j1 = push_to_right d t1 i j1 j2 in
|
||
|
if j1 = j2 - 1 then
|
||
|
let line = t1.(i - 1) in
|
||
|
let x = line.(j1).span in
|
||
|
let y = line.(j2).span in
|
||
|
let rec loop y j =
|
||
|
if j >= Array.length line then ()
|
||
|
else if line.(j).span = y || t1.(i).(j).elem = t1.(i).(j - 1).elem then
|
||
|
let y = line.(j).span in
|
||
|
line.(j).span <- x;
|
||
|
if i > 0 then t1.(i - 1).(j).span <- t1.(i - 1).(j - 1).span;
|
||
|
loop y (j + 1)
|
||
|
in
|
||
|
loop y j2; Some ({table = t1}, true)
|
||
|
else None
|
||
|
;;
|
||
|
|
||
|
let treat_gaps d t =
|
||
|
let i = Array.length t.table - 1 in
|
||
|
let rec loop t j =
|
||
|
let line = t.table.(i) in
|
||
|
if j = Array.length line then t
|
||
|
else
|
||
|
match line.(j).elem with
|
||
|
Elem _ as y ->
|
||
|
if y = line.(j - 1).elem then loop t (j + 1)
|
||
|
else
|
||
|
let rec loop1 t j1 =
|
||
|
if j1 < 0 then loop t (j + 1)
|
||
|
else if y = line.(j1).elem then
|
||
|
match fill_gap d t i j1 j with
|
||
|
Some (t, ok) -> if ok then loop t 2 else loop t (j + 1)
|
||
|
| None -> loop t (j + 1)
|
||
|
else loop1 t (j1 - 1)
|
||
|
in
|
||
|
loop1 t (j - 2)
|
||
|
| _ -> loop t (j + 1)
|
||
|
in
|
||
|
if Array.length t.table.(i) = 1 then t else loop t 2
|
||
|
;;
|
||
|
|
||
|
let group_span_last_row t =
|
||
|
let row = t.table.(Array.length t.table - 1) in
|
||
|
let rec loop i =
|
||
|
if i >= Array.length row then ()
|
||
|
else
|
||
|
begin
|
||
|
begin match row.(i).elem with
|
||
|
Elem _ | Ghost _ as x ->
|
||
|
if x = row.(i - 1).elem then row.(i).span <- row.(i - 1).span
|
||
|
| _ -> ()
|
||
|
end;
|
||
|
loop (i + 1)
|
||
|
end
|
||
|
in
|
||
|
loop 1
|
||
|
;;
|
||
|
|
||
|
let has_phony_children phony d t =
|
||
|
let line = t.table.(Array.length t.table - 1) in
|
||
|
let rec loop j =
|
||
|
if j = Array.length line then false
|
||
|
else
|
||
|
match line.(j).elem with
|
||
|
Elem x -> if phony d.dag.(int_of_idag x) then true else loop (j + 1)
|
||
|
| _ -> loop (j + 1)
|
||
|
in
|
||
|
loop 0
|
||
|
;;
|
||
|
|
||
|
let tablify phony no_optim no_group d =
|
||
|
let a = ancestors d in
|
||
|
let r = group_by_common_children d a in
|
||
|
let t = {table = [| Array.of_list r |]} in
|
||
|
let rec loop t =
|
||
|
let (t, new_row) = treat_new_row d t in
|
||
|
if List.for_all (fun x -> x.elem = Nothing) new_row then t
|
||
|
else
|
||
|
let t = {table = Array.append t.table [| Array.of_list new_row |]} in
|
||
|
let t =
|
||
|
if no_group && not (has_phony_children phony d t) then t
|
||
|
else
|
||
|
let _ = if no_optim then () else equilibrate t in
|
||
|
let _ = group_elem t in
|
||
|
let _ = group_ghost t in
|
||
|
let _ = group_children t in
|
||
|
let _ = group_span_by_common_children d t in
|
||
|
let t = if no_optim then t else treat_gaps d t in
|
||
|
let _ = group_span_last_row t in t
|
||
|
in
|
||
|
loop t
|
||
|
in
|
||
|
loop t
|
||
|
;;
|
||
|
|
||
|
let fall d t =
|
||
|
for i = 1 to Array.length t.table - 1 do
|
||
|
let line = t.table.(i) in
|
||
|
let rec loop j =
|
||
|
if j = Array.length line then ()
|
||
|
else
|
||
|
match line.(j).elem with
|
||
|
Ghost x ->
|
||
|
let j2 =
|
||
|
let rec loop j =
|
||
|
if j = Array.length line then j - 1
|
||
|
else
|
||
|
match line.(j).elem with
|
||
|
Ghost y when y = x -> loop (j + 1)
|
||
|
| _ -> j - 1
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let i1 =
|
||
|
let rec loop i =
|
||
|
if i < 0 then i + 1
|
||
|
else
|
||
|
let line = t.table.(i) in
|
||
|
if (j = 0 || line.(j - 1).span <> line.(j).span) &&
|
||
|
(j2 = Array.length line - 1 ||
|
||
|
line.(j2 + 1).span <> line.(j2).span) then
|
||
|
loop (i - 1)
|
||
|
else i + 1
|
||
|
in
|
||
|
loop (i - 1)
|
||
|
in
|
||
|
let i1 =
|
||
|
if i1 = i then i1
|
||
|
else if i1 = 0 then i1
|
||
|
else if t.table.(i1).(j).elem = Nothing then i1
|
||
|
else i
|
||
|
in
|
||
|
if i1 < i then
|
||
|
begin
|
||
|
for k = i downto i1 + 1 do
|
||
|
for j = j to j2 do
|
||
|
t.table.(k).(j).elem <- t.table.(k - 1).(j).elem;
|
||
|
if k < i then
|
||
|
t.table.(k).(j).span <- t.table.(k - 1).(j).span
|
||
|
done
|
||
|
done;
|
||
|
for l = j to j2 do
|
||
|
if i1 = 0 || t.table.(i1 - 1).(l).elem = Nothing then
|
||
|
t.table.(i1).(l).elem <- Nothing
|
||
|
else
|
||
|
t.table.(i1).(l) <-
|
||
|
if l = j ||
|
||
|
t.table.(i1 - 1).(l - 1).span <>
|
||
|
t.table.(i1 - 1).(l).span then
|
||
|
{elem = Ghost (new_ghost_id ());
|
||
|
span = new_span_id ()}
|
||
|
else copy_data t.table.(i1).(l - 1)
|
||
|
done
|
||
|
end;
|
||
|
loop (j2 + 1)
|
||
|
| _ -> loop (j + 1)
|
||
|
in
|
||
|
loop 0
|
||
|
done
|
||
|
;;
|
||
|
|
||
|
let fall2_cool_right t i1 i2 i3 j1 j2 =
|
||
|
let span = t.table.(i2 - 1).(j1).span in
|
||
|
for i = i2 - 1 downto 0 do
|
||
|
for j = j1 to j2 - 1 do
|
||
|
t.table.(i).(j) <-
|
||
|
if i - i2 + i1 >= 0 then t.table.(i - i2 + i1).(j)
|
||
|
else {elem = Nothing; span = new_span_id ()}
|
||
|
done
|
||
|
done;
|
||
|
for i = Array.length t.table - 1 downto 0 do
|
||
|
for j = j2 to Array.length t.table.(i) - 1 do
|
||
|
t.table.(i).(j) <-
|
||
|
if i - i2 + i1 >= 0 then t.table.(i - i2 + i1).(j)
|
||
|
else {elem = Nothing; span = new_span_id ()}
|
||
|
done
|
||
|
done;
|
||
|
let old_span = t.table.(i2 - 1).(j1).span in
|
||
|
let rec loop j =
|
||
|
if j = Array.length t.table.(i2 - 1) then ()
|
||
|
else if t.table.(i2 - 1).(j).span = old_span then
|
||
|
begin t.table.(i2 - 1).(j).span <- span; loop (j + 1) end
|
||
|
in
|
||
|
loop j1
|
||
|
;;
|
||
|
|
||
|
let fall2_cool_left t i1 i2 i3 j1 j2 =
|
||
|
let span = t.table.(i2 - 1).(j2).span in
|
||
|
for i = i2 - 1 downto 0 do
|
||
|
for j = j1 + 1 to j2 do
|
||
|
t.table.(i).(j) <-
|
||
|
if i - i2 + i1 >= 0 then t.table.(i - i2 + i1).(j)
|
||
|
else {elem = Nothing; span = new_span_id ()}
|
||
|
done
|
||
|
done;
|
||
|
for i = Array.length t.table - 1 downto 0 do
|
||
|
for j = j1 downto 0 do
|
||
|
t.table.(i).(j) <-
|
||
|
if i - i2 + i1 >= 0 then t.table.(i - i2 + i1).(j)
|
||
|
else {elem = Nothing; span = new_span_id ()}
|
||
|
done
|
||
|
done;
|
||
|
let old_span = t.table.(i2 - 1).(j2).span in
|
||
|
let rec loop j =
|
||
|
if j < 0 then ()
|
||
|
else if t.table.(i2 - 1).(j).span = old_span then
|
||
|
begin t.table.(i2 - 1).(j).span <- span; loop (j - 1) end
|
||
|
in
|
||
|
loop j2
|
||
|
;;
|
||
|
|
||
|
let do_fall2_right t i1 i2 j1 j2 =
|
||
|
let i3 =
|
||
|
let rec loop_i i =
|
||
|
if i < 0 then 0
|
||
|
else
|
||
|
let rec loop_j j =
|
||
|
if j = Array.length t.table.(i) then loop_i (i - 1)
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Nothing -> loop_j (j + 1)
|
||
|
| _ -> i + 1
|
||
|
in
|
||
|
loop_j j2
|
||
|
in
|
||
|
loop_i (Array.length t.table - 1)
|
||
|
in
|
||
|
let new_height = i3 + i2 - i1 in
|
||
|
let t =
|
||
|
if new_height > Array.length t.table then
|
||
|
let rec loop cnt t =
|
||
|
if cnt = 0 then t
|
||
|
else
|
||
|
let new_line =
|
||
|
Array.init (Array.length t.table.(0))
|
||
|
(fun i -> {elem = Nothing; span = new_span_id ()})
|
||
|
in
|
||
|
let t = {table = Array.append t.table [| new_line |]} in
|
||
|
loop (cnt - 1) t
|
||
|
in
|
||
|
loop (new_height - Array.length t.table) t
|
||
|
else t
|
||
|
in
|
||
|
fall2_cool_right t i1 i2 i3 j1 j2; t
|
||
|
;;
|
||
|
|
||
|
let do_fall2_left t i1 i2 j1 j2 =
|
||
|
let i3 =
|
||
|
let rec loop_i i =
|
||
|
if i < 0 then 0
|
||
|
else
|
||
|
let rec loop_j j =
|
||
|
if j < 0 then loop_i (i - 1)
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Nothing -> loop_j (j - 1)
|
||
|
| _ -> i + 1
|
||
|
in
|
||
|
loop_j j1
|
||
|
in
|
||
|
loop_i (Array.length t.table - 1)
|
||
|
in
|
||
|
let new_height = i3 + i2 - i1 in
|
||
|
let t =
|
||
|
if new_height > Array.length t.table then
|
||
|
let rec loop cnt t =
|
||
|
if cnt = 0 then t
|
||
|
else
|
||
|
let new_line =
|
||
|
Array.init (Array.length t.table.(0))
|
||
|
(fun i -> {elem = Nothing; span = new_span_id ()})
|
||
|
in
|
||
|
let t = {table = Array.append t.table [| new_line |]} in
|
||
|
loop (cnt - 1) t
|
||
|
in
|
||
|
loop (new_height - Array.length t.table) t
|
||
|
else t
|
||
|
in
|
||
|
fall2_cool_left t i1 i2 i3 j1 j2; t
|
||
|
;;
|
||
|
|
||
|
let do_shorten_too_long t i1 j1 j2 =
|
||
|
for i = i1 to Array.length t.table - 2 do
|
||
|
for j = j1 to j2 - 1 do t.table.(i).(j) <- t.table.(i + 1).(j) done
|
||
|
done;
|
||
|
let i = Array.length t.table - 1 in
|
||
|
for j = j1 to j2 - 1 do
|
||
|
t.table.(i).(j) <- {elem = Nothing; span = new_span_id ()}
|
||
|
done;
|
||
|
t
|
||
|
;;
|
||
|
|
||
|
let try_fall2_right t i j =
|
||
|
match t.table.(i).(j).elem with
|
||
|
Ghost _ ->
|
||
|
let i1 =
|
||
|
let rec loop i =
|
||
|
if i < 0 then 0
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Ghost _ -> loop (i - 1)
|
||
|
| _ -> i + 1
|
||
|
in
|
||
|
loop (i - 1)
|
||
|
in
|
||
|
let separated1 =
|
||
|
let rec loop i =
|
||
|
if i < 0 then true
|
||
|
else if
|
||
|
j > 0 && t.table.(i).(j - 1).span = t.table.(i).(j).span then
|
||
|
false
|
||
|
else loop (i - 1)
|
||
|
in
|
||
|
loop (i1 - 1)
|
||
|
in
|
||
|
let j2 =
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let rec loop j2 =
|
||
|
if j2 = Array.length t.table.(i) then j2
|
||
|
else
|
||
|
match t.table.(i).(j2) with
|
||
|
{elem = Ghost _; span = y} when y = x -> loop (j2 + 1)
|
||
|
| _ -> j2
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let separated2 =
|
||
|
let rec loop i =
|
||
|
if i = Array.length t.table then true
|
||
|
else if j2 = Array.length t.table.(i) then false
|
||
|
else if t.table.(i).(j2 - 1).span = t.table.(i).(j2).span then false
|
||
|
else loop (i + 1)
|
||
|
in
|
||
|
loop (i + 1)
|
||
|
in
|
||
|
if not separated1 || not separated2 then None
|
||
|
else Some (do_fall2_right t i1 (i + 1) j j2)
|
||
|
| _ -> None
|
||
|
;;
|
||
|
|
||
|
let try_fall2_left t i j =
|
||
|
match t.table.(i).(j).elem with
|
||
|
Ghost _ ->
|
||
|
let i1 =
|
||
|
let rec loop i =
|
||
|
if i < 0 then 0
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Ghost _ -> loop (i - 1)
|
||
|
| _ -> i + 1
|
||
|
in
|
||
|
loop (i - 1)
|
||
|
in
|
||
|
let separated1 =
|
||
|
let rec loop i =
|
||
|
if i < 0 then true
|
||
|
else if
|
||
|
j < Array.length t.table.(i) - 1 &&
|
||
|
t.table.(i).(j).span = t.table.(i).(j + 1).span then
|
||
|
false
|
||
|
else loop (i - 1)
|
||
|
in
|
||
|
loop (i1 - 1)
|
||
|
in
|
||
|
let j1 =
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let rec loop j1 =
|
||
|
if j1 < 0 then j1
|
||
|
else
|
||
|
match t.table.(i).(j1) with
|
||
|
{elem = Ghost _; span = y} when y = x -> loop (j1 - 1)
|
||
|
| _ -> j1
|
||
|
in
|
||
|
loop (j - 1)
|
||
|
in
|
||
|
let separated2 =
|
||
|
let rec loop i =
|
||
|
if i = Array.length t.table then true
|
||
|
else if j1 < 0 then false
|
||
|
else if t.table.(i).(j1).span = t.table.(i).(j1 + 1).span then false
|
||
|
else loop (i + 1)
|
||
|
in
|
||
|
loop (i + 1)
|
||
|
in
|
||
|
if not separated1 || not separated2 then None
|
||
|
else Some (do_fall2_left t i1 (i + 1) j1 j)
|
||
|
| _ -> None
|
||
|
;;
|
||
|
|
||
|
let try_shorten_too_long t i j =
|
||
|
match t.table.(i).(j).elem with
|
||
|
Ghost _ ->
|
||
|
let j2 =
|
||
|
let x = t.table.(i).(j).span in
|
||
|
let rec loop j2 =
|
||
|
if j2 = Array.length t.table.(i) then j2
|
||
|
else
|
||
|
match t.table.(i).(j2) with
|
||
|
{elem = Ghost _; span = y} when y = x -> loop (j2 + 1)
|
||
|
| _ -> j2
|
||
|
in
|
||
|
loop (j + 1)
|
||
|
in
|
||
|
let i1 =
|
||
|
let rec loop i =
|
||
|
if i = Array.length t.table then i
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Elem _ -> loop (i + 1)
|
||
|
| _ -> i
|
||
|
in
|
||
|
loop (i + 1)
|
||
|
in
|
||
|
let i2 =
|
||
|
let rec loop i =
|
||
|
if i = Array.length t.table then i
|
||
|
else
|
||
|
match t.table.(i).(j).elem with
|
||
|
Nothing -> loop (i + 1)
|
||
|
| _ -> i
|
||
|
in
|
||
|
loop i1
|
||
|
in
|
||
|
let separated_left =
|
||
|
let rec loop i =
|
||
|
if i = i2 then true
|
||
|
else if
|
||
|
j > 0 && t.table.(i).(j).span = t.table.(i).(j - 1).span then
|
||
|
false
|
||
|
else loop (i + 1)
|
||
|
in
|
||
|
loop i
|
||
|
in
|
||
|
let separated_right =
|
||
|
let rec loop i =
|
||
|
if i = i2 then true
|
||
|
else if
|
||
|
j2 < Array.length t.table.(i) &&
|
||
|
t.table.(i).(j2 - 1).span = t.table.(i).(j2).span then
|
||
|
false
|
||
|
else loop (i + 1)
|
||
|
in
|
||
|
loop i
|
||
|
in
|
||
|
if not separated_left || not separated_right then None
|
||
|
else if i2 < Array.length t.table then None
|
||
|
else Some (do_shorten_too_long t i j j2)
|
||
|
| _ -> None
|
||
|
;;
|
||
|
|
||
|
let fall2_right t =
|
||
|
let rec loop_i i t =
|
||
|
if i <= 0 then t
|
||
|
else
|
||
|
let rec loop_j j t =
|
||
|
if j < 0 then loop_i (i - 1) t
|
||
|
else
|
||
|
match try_fall2_right t i j with
|
||
|
Some t -> loop_i (Array.length t.table - 1) t
|
||
|
| None -> loop_j (j - 1) t
|
||
|
in
|
||
|
loop_j (Array.length t.table.(i) - 2) t
|
||
|
in
|
||
|
loop_i (Array.length t.table - 1) t
|
||
|
;;
|
||
|
|
||
|
let fall2_left t =
|
||
|
let rec loop_i i t =
|
||
|
if i <= 0 then t
|
||
|
else
|
||
|
let rec loop_j j t =
|
||
|
if j >= Array.length t.table.(i) then loop_i (i - 1) t
|
||
|
else
|
||
|
match try_fall2_left t i j with
|
||
|
Some t -> loop_i (Array.length t.table - 1) t
|
||
|
| None -> loop_j (j + 1) t
|
||
|
in
|
||
|
loop_j 1 t
|
||
|
in
|
||
|
loop_i (Array.length t.table - 1) t
|
||
|
;;
|
||
|
|
||
|
let shorten_too_long t =
|
||
|
let rec loop_i i t =
|
||
|
if i <= 0 then t
|
||
|
else
|
||
|
let rec loop_j j t =
|
||
|
if j >= Array.length t.table.(i) then loop_i (i - 1) t
|
||
|
else
|
||
|
match try_shorten_too_long t i j with
|
||
|
Some t -> loop_i (Array.length t.table - 1) t
|
||
|
| None -> loop_j (j + 1) t
|
||
|
in
|
||
|
loop_j 1 t
|
||
|
in
|
||
|
loop_i (Array.length t.table - 1) t
|
||
|
;;
|
||
|
|
||
|
(* top_adjust:
|
||
|
deletes all empty rows that might have appeared on top of the table
|
||
|
after the falls *)
|
||
|
|
||
|
let top_adjust t =
|
||
|
let di =
|
||
|
let rec loop i =
|
||
|
if i = Array.length t.table then i
|
||
|
else
|
||
|
let rec loop_j j =
|
||
|
if j = Array.length t.table.(i) then loop (i + 1)
|
||
|
else if t.table.(i).(j).elem <> Nothing then i
|
||
|
else loop_j (j + 1)
|
||
|
in
|
||
|
loop_j 0
|
||
|
in
|
||
|
loop 0
|
||
|
in
|
||
|
if di > 0 then
|
||
|
begin
|
||
|
for i = 0 to Array.length t.table - 1 - di do
|
||
|
t.table.(i) <- t.table.(i + di)
|
||
|
done;
|
||
|
{table = Array.sub t.table 0 (Array.length t.table - di)}
|
||
|
end
|
||
|
else t
|
||
|
;;
|
||
|
|
||
|
(* bottom_adjust:
|
||
|
deletes all empty rows that might have appeared on bottom of the table
|
||
|
after the falls *)
|
||
|
|
||
|
let bottom_adjust t =
|
||
|
let last_i =
|
||
|
let rec loop i =
|
||
|
if i < 0 then i
|
||
|
else
|
||
|
let rec loop_j j =
|
||
|
if j = Array.length t.table.(i) then loop (i - 1)
|
||
|
else if t.table.(i).(j).elem <> Nothing then i
|
||
|
else loop_j (j + 1)
|
||
|
in
|
||
|
loop_j 0
|
||
|
in
|
||
|
loop (Array.length t.table - 1)
|
||
|
in
|
||
|
if last_i < Array.length t.table - 1 then
|
||
|
{table = Array.sub t.table 0 (last_i + 1)}
|
||
|
else t
|
||
|
;;
|
||
|
|
||
|
(* invert *)
|
||
|
|
||
|
let invert_dag d =
|
||
|
let d = {dag = Array.copy d.dag} in
|
||
|
for i = 0 to Array.length d.dag - 1 do
|
||
|
let n = d.dag.(i) in
|
||
|
d.dag.(i) <-
|
||
|
{pare = List.map (fun x -> x) n.chil; valu = n.valu;
|
||
|
chil = List.map (fun x -> x) n.pare}
|
||
|
done;
|
||
|
d
|
||
|
;;
|
||
|
|
||
|
let invert_table t =
|
||
|
let t' = {table = Array.copy t.table} in
|
||
|
let len = Array.length t.table in
|
||
|
for i = 0 to len - 1 do
|
||
|
t'.table.(i) <-
|
||
|
Array.init (Array.length t.table.(0))
|
||
|
(fun j ->
|
||
|
let d = t.table.(len - 1 - i).(j) in
|
||
|
{elem = d.elem; span = d.span});
|
||
|
if i < len - 1 then
|
||
|
for j = 0 to Array.length t'.table.(i) - 1 do
|
||
|
t'.table.(i).(j).span <- t.table.(len - 2 - i).(j).span
|
||
|
done
|
||
|
done;
|
||
|
t'
|
||
|
;;
|
||
|
|
||
|
(* main *)
|
||
|
|
||
|
let table_of_dag phony no_optim invert no_group d =
|
||
|
let d = if invert then invert_dag d else d in
|
||
|
let t = tablify phony no_optim no_group d in
|
||
|
let t = if invert then invert_table t else t in
|
||
|
let _ = fall () t in
|
||
|
let t = fall2_right t in
|
||
|
let t = fall2_left t in
|
||
|
let t = shorten_too_long t in
|
||
|
let t = top_adjust t in let t = bottom_adjust t in t
|
||
|
;;
|
||
|
|
||
|
|
||
|
let version = "1.01";;
|
||
|
|
||
|
(* input dag *)
|
||
|
|
||
|
let strip_spaces str =
|
||
|
let start =
|
||
|
let rec loop i =
|
||
|
if i == String.length str then i
|
||
|
else
|
||
|
match str.[i] with
|
||
|
' ' | '\013' | '\n' | '\t' -> loop (i + 1)
|
||
|
| _ -> i
|
||
|
in
|
||
|
loop 0
|
||
|
in
|
||
|
let stop =
|
||
|
let rec loop i =
|
||
|
if i == -1 then i + 1
|
||
|
else
|
||
|
match str.[i] with
|
||
|
' ' | '\013' | '\n' | '\t' -> loop (i - 1)
|
||
|
| _ -> i + 1
|
||
|
in
|
||
|
loop (String.length str - 1)
|
||
|
in
|
||
|
if start == 0 && stop == String.length str then str
|
||
|
else if start > stop then ""
|
||
|
else String.sub str start (stop - start)
|
||
|
;;
|
||
|
|
||
|
let rec get_line ic =
|
||
|
try
|
||
|
let line = input_line ic in
|
||
|
if String.length line > 0 && line.[0] = '#' then get_line ic
|
||
|
else Some (strip_spaces line)
|
||
|
with
|
||
|
End_of_file -> None
|
||
|
;;
|
||
|
|
||
|
let input_dag ic =
|
||
|
let rec find cnt s =
|
||
|
function
|
||
|
n :: nl ->
|
||
|
if n.valu = s then n, idag_of_int cnt else find (cnt - 1) s nl
|
||
|
| [] -> raise Not_found
|
||
|
in
|
||
|
let add_node pl cl nl cnt =
|
||
|
let cl = List.rev cl in
|
||
|
let pl = List.rev pl in
|
||
|
let (pl, pnl, nl, cnt) =
|
||
|
List.fold_left
|
||
|
(fun (pl, pnl, nl, cnt) p ->
|
||
|
try
|
||
|
let (n, p) = find (cnt - 1) p nl in p :: pl, n :: pnl, nl, cnt
|
||
|
with
|
||
|
Not_found ->
|
||
|
let n = {pare = []; valu = p; chil = []} in
|
||
|
let p = idag_of_int cnt in p :: pl, n :: pnl, n :: nl, cnt + 1)
|
||
|
([], [], nl, cnt) pl
|
||
|
in
|
||
|
let pl = List.rev pl in
|
||
|
let (cl, nl, cnt) =
|
||
|
List.fold_left
|
||
|
(fun (cl, nl, cnt) c ->
|
||
|
try
|
||
|
let (n, c) = find (cnt - 1) c nl in
|
||
|
n.pare <- n.pare @ pl; c :: cl, nl, cnt
|
||
|
with
|
||
|
Not_found ->
|
||
|
let n = {pare = pl; valu = c; chil = []} in
|
||
|
let c = idag_of_int cnt in c :: cl, n :: nl, cnt + 1)
|
||
|
([], nl, cnt) cl
|
||
|
in
|
||
|
let cl = List.rev cl in
|
||
|
List.iter (fun p -> p.chil <- p.chil @ cl) pnl; nl, cnt
|
||
|
in
|
||
|
let rec input_parents nl pl cnt =
|
||
|
function
|
||
|
Some "" -> input_parents nl pl cnt (get_line ic)
|
||
|
| Some line ->
|
||
|
begin match line.[0] with
|
||
|
'o' ->
|
||
|
let p =
|
||
|
strip_spaces (String.sub line 1 (String.length line - 1))
|
||
|
in
|
||
|
if p = "" then failwith line
|
||
|
else input_parents nl (p :: pl) cnt (get_line ic)
|
||
|
| '-' ->
|
||
|
if pl = [] then failwith line
|
||
|
else input_children nl pl [] cnt (Some line)
|
||
|
| _ -> failwith line
|
||
|
end
|
||
|
| None -> if pl = [] then nl, cnt else failwith "end of file 1"
|
||
|
and input_children nl pl cl cnt =
|
||
|
function
|
||
|
Some "" -> input_children nl pl cl cnt (get_line ic)
|
||
|
| Some line ->
|
||
|
begin match line.[0] with
|
||
|
'o' ->
|
||
|
if cl = [] then failwith line
|
||
|
else
|
||
|
let (nl, cnt) = add_node pl cl nl cnt in
|
||
|
input_parents nl [] cnt (Some line)
|
||
|
| '-' ->
|
||
|
let c =
|
||
|
strip_spaces (String.sub line 1 (String.length line - 1))
|
||
|
in
|
||
|
if c = "" then failwith line
|
||
|
else input_children nl pl (c :: cl) cnt (get_line ic)
|
||
|
| _ -> failwith line
|
||
|
end
|
||
|
| None ->
|
||
|
if cl = [] then failwith "end of file 2" else add_node pl cl nl cnt
|
||
|
in
|
||
|
let (nl, _) = input_parents [] [] 0 (get_line ic) in
|
||
|
{dag = Array.of_list (List.rev nl)}
|
||
|
;;
|
||
|
|
||
|
(* testing *)
|
||
|
|
||
|
let map_dag f d =
|
||
|
let a =
|
||
|
Array.map (fun d -> {pare = d.pare; valu = f d.valu; chil = d.chil}) d.dag
|
||
|
in
|
||
|
{dag = a}
|
||
|
;;
|
||
|
|
||
|
let tag_dag d =
|
||
|
let c = ref 'A' in
|
||
|
map_dag
|
||
|
(fun v ->
|
||
|
let v = !c in
|
||
|
c :=
|
||
|
if !c = 'Z' then 'a'
|
||
|
else if !c = 'z' then '1'
|
||
|
else Char.chr (Char.code !c + 1);
|
||
|
String.make 1 v)
|
||
|
d
|
||
|
;;
|
||
|
|
||
|
(* *)
|
||
|
|
||
|
let phony _ = false;;
|
||
|
let indi_txt n = n.valu;;
|
||
|
|
||
|
let string_table border hts =
|
||
|
let buf = Buffer.create 30 in
|
||
|
Printf.bprintf buf "<center><table border=%d" border;
|
||
|
Printf.bprintf buf " cellspacing=0 cellpadding=0>\n";
|
||
|
for i = 0 to Array.length hts - 1 do
|
||
|
Printf.bprintf buf "<tr>\n";
|
||
|
for j = 0 to Array.length hts.(i) - 1 do
|
||
|
let (colspan, align, td) = hts.(i).(j) in
|
||
|
Printf.bprintf buf "<td";
|
||
|
if colspan = 1 && (td = TDstring " " || td = TDhr CenterA) then ()
|
||
|
else Printf.bprintf buf " colspan=%d" colspan;
|
||
|
begin match align, td with
|
||
|
LeftA, TDhr LeftA -> Printf.bprintf buf " align=left"
|
||
|
| LeftA, _ -> ()
|
||
|
| CenterA, _ -> Printf.bprintf buf " align=center"
|
||
|
| RightA, _ -> Printf.bprintf buf " align=right"
|
||
|
end;
|
||
|
Printf.bprintf buf ">";
|
||
|
begin match td with
|
||
|
TDstring s -> Printf.bprintf buf "%s" s
|
||
|
| TDhr align ->
|
||
|
Printf.bprintf buf "<hr noshade size=1";
|
||
|
begin match align with
|
||
|
LeftA -> Printf.bprintf buf " width=\"50%%\" align=left"
|
||
|
| RightA -> Printf.bprintf buf " width=\"50%%\" align=right"
|
||
|
| _ -> ()
|
||
|
end;
|
||
|
Printf.bprintf buf ">";
|
||
|
()
|
||
|
end;
|
||
|
Printf.bprintf buf "</td>\n";
|
||
|
()
|
||
|
done
|
||
|
done;
|
||
|
Printf.bprintf buf "</table></center>\n";
|
||
|
Buffer.contents buf
|
||
|
;;
|
||
|
|
||
|
let fname = ref "";;
|
||
|
let invert = ref false;;
|
||
|
let char = ref false;;
|
||
|
let border = ref 0;;
|
||
|
let no_optim = ref false;;
|
||
|
let no_group = ref false;;
|
||
|
|
||
|
let html_of_dag d =
|
||
|
let print_indi n = print_string n.valu in
|
||
|
let t = table_of_dag phony !no_optim !invert !no_group d in
|
||
|
let hts = html_table_struct indi_txt phony d t in
|
||
|
string_table !border hts
|
||
|
;;
|
||
|
|
||
|
|
||
|
(********************************* Max's code **********************************)
|
||
|
(** This function takes a list of classes and a list of class types
|
||
|
and create the associate dag. *)
|
||
|
let create_class_dag cl_list clt_list =
|
||
|
let module M = Odoc_info.Class in
|
||
|
(* the list of all the classes concerned *)
|
||
|
let cl_list2 = List.map (fun c -> (c.M.cl_name, Some (M.Cl c))) cl_list in
|
||
|
let clt_list2 = List.map (fun ct -> (ct.M.clt_name, Some (M.Cltype (ct, [])))) clt_list in
|
||
|
let list = cl_list2 @ clt_list2 in
|
||
|
let all_classes =
|
||
|
let rec iter list2 =
|
||
|
List.fold_left
|
||
|
(fun acc -> fun (name, cct_opt) ->
|
||
|
let l =
|
||
|
match cct_opt with
|
||
|
None -> []
|
||
|
| Some (M.Cl c) ->
|
||
|
iter
|
||
|
(List.map
|
||
|
(fun inh ->(inh.M.ic_name, inh.M.ic_class))
|
||
|
(match c.M.cl_kind with
|
||
|
M.Class_structure (inher_l, _) ->
|
||
|
inher_l
|
||
|
| _ ->
|
||
|
[]
|
||
|
)
|
||
|
)
|
||
|
| Some (M.Cltype (ct, _)) ->
|
||
|
iter
|
||
|
(List.map
|
||
|
(fun inh ->(inh.M.ic_name, inh.M.ic_class))
|
||
|
(match ct.M.clt_kind with
|
||
|
M.Class_signature (inher_l, _) ->
|
||
|
inher_l
|
||
|
| _ ->
|
||
|
[]
|
||
|
)
|
||
|
)
|
||
|
in
|
||
|
(name, cct_opt) :: (acc @ l)
|
||
|
)
|
||
|
[]
|
||
|
list2
|
||
|
in
|
||
|
iter list
|
||
|
in
|
||
|
let rec distinct acc = function
|
||
|
[] ->
|
||
|
acc
|
||
|
| (name, cct_opt) :: q ->
|
||
|
if List.exists (fun (name2, _) -> name = name2) acc then
|
||
|
distinct acc q
|
||
|
else
|
||
|
distinct ((name, cct_opt) :: acc) q
|
||
|
in
|
||
|
let distinct_classes = distinct [] all_classes in
|
||
|
let liste_index =
|
||
|
let rec f n = function
|
||
|
[] -> []
|
||
|
| (name, _) :: q -> (name, n) :: (f (n+1) q)
|
||
|
in
|
||
|
f 0 distinct_classes
|
||
|
in
|
||
|
let array1 = Array.of_list distinct_classes in
|
||
|
(* create the dag array, filling parents and values *)
|
||
|
let fmap (name, cct_opt) =
|
||
|
{ pare = List.map
|
||
|
(fun inh -> List.assoc inh.M.ic_name liste_index )
|
||
|
(match cct_opt with
|
||
|
None -> []
|
||
|
| Some (M.Cl c) ->
|
||
|
(match c.M.cl_kind with
|
||
|
M.Class_structure (inher_l, _) ->
|
||
|
inher_l
|
||
|
| _ ->
|
||
|
[]
|
||
|
)
|
||
|
| Some (M.Cltype (ct, _)) ->
|
||
|
(match ct.M.clt_kind with
|
||
|
M.Class_signature (inher_l, _) ->
|
||
|
inher_l
|
||
|
| _ ->
|
||
|
[]
|
||
|
)
|
||
|
);
|
||
|
valu = (name, cct_opt) ;
|
||
|
chil = []
|
||
|
}
|
||
|
in
|
||
|
let dag = { dag = Array.map fmap array1 } in
|
||
|
(* fill the children *)
|
||
|
let fiter i node =
|
||
|
let l = Array.to_list dag.dag in
|
||
|
let l2 = List.map (fun n -> n.valu)
|
||
|
(List.filter (fun n -> List.mem i n.pare) l)
|
||
|
in
|
||
|
node.chil <- List.map (fun (name,_) -> List.assoc name liste_index) l2
|
||
|
in
|
||
|
Array.iteri fiter dag.dag;
|
||
|
dag
|
||
|
|
||
|
|
||
|
|
||
|
|