open Printf
type punctuation =
unit -> string
type 'a printer =
unit -> 'a -> string
let maxindent =
120
let whitespace =
String.make maxindent ' '
let indentation =
ref 0
let nl () =
"\n" ^ String.sub whitespace 0 !indentation
let indent ofs producer () x =
let old_indentation = !indentation in
let new_indentation = old_indentation + ofs in
if new_indentation <= maxindent then
indentation := new_indentation;
let result = sprintf "%t%a" nl producer x in
indentation := old_indentation;
result
let rec list elem () xs =
match xs with
| [] ->
""
| x :: xs ->
sprintf "%a%a" elem x (list elem) xs
let rec preclist delim elem () xs =
match xs with
| [] ->
""
| x :: xs ->
sprintf "%t%a%a" delim elem x (preclist delim elem) xs
let rec termlist delim elem () xs =
match xs with
| [] ->
""
| x :: xs ->
sprintf "%a%t%a" elem x delim (termlist delim elem) xs
let seplist sep elem () xs =
match xs with
| [] ->
""
| x :: xs ->
sprintf "%a%a" elem x (preclist sep elem) xs
let annlist announcement list () xs =
match xs with
| [] ->
""
| _ :: _ ->
sprintf "%t%a" announcement list xs
let space () =
sprintf " "
let comma () =
sprintf ", "
let semicolon () =
sprintf "; "
let var () =
sprintf "var "
let seminl () =
sprintf "%t%t" semicolon nl
let nlspace k () =
sprintf "%t%s" nl (String.make k ' ')
let nlnl () =
sprintf "%t%t" nl nl
let atmost n (delimiter : punctuation) (stop : punctuation) : punctuation =
let i =
ref 0
in
function () ->
incr i;
delimiter() ^
if !i = n then begin
i := 0;
stop()
end
else
""
let width column =
List.fold_left (fun width x ->
max width (String.length x)
) 0 column
let pad width x =
let y = String.make width ' ' in
String.blit x 0 y 0 (String.length x);
y
let pad column =
List.map (pad (width column)) column
let rec zipcat column1 column2 =
List.fold_right2 (fun x1 x2 column ->
(x1 ^ x2) :: column
) column1 column2 []
let catenate columns =
match columns with
| [] ->
[]
| column :: columns ->
List.fold_left (fun table column ->
zipcat table (pad column)
) (pad column) columns
let transposerev lines =
match lines with
| [] ->
[]
| line :: lines ->
List.fold_left (fun columns line ->
List.fold_right2 (fun x column columns ->
(x :: column) :: columns
) line columns []
) (List.map (fun x -> [ x ]) line) lines
let showif flag printer x =
if flag then begin
Printf.fprintf stdout "%s%!" (sprintf "%a" printer x);
x
end
else
x