123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2010 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)open!Stdlibtypepos={mutablep_line:int;mutablep_col:int}typeelt=|Textofstring|Breakofstring*int|Start_groupofint|End_group|Set_posofpostypet={mutableindent:int;mutablebox_indent:int;mutableprev_indents:(int*int)list;mutablelimit:int;mutablecur:int;mutablel:eltlist;mutablen:int;mutablew:int;mutablecompact:bool;mutableneeded_space:(char->char->bool)option;mutableadjust_indentation:(int->int)option;mutablepending_space:stringoption;mutablelast_char:charoption;mutableline:int;mutablecol:int;mutabletotal:int;output:string->int->int->unit}letspaces=String.make80' 'letoutputst(s:string)l=(tryletlast=String.rindex_froms(l-1)'\n'+1inletline=ref0infori=0tol-1doifChar.equals.[i]'\n'thenincrlinedone;st.line<-st.line+!line;st.col<-l-lastwithNot_found->st.col<-l+st.col);st.total<-st.total+String.lengths;st.outputs0lletrecoutput_spacesstn=letn=matchst.adjust_indentationwith|Somef->fn|None->ninoutputstspaces(minn80);ifn>80thenoutput_spacesst(n-80)letoutput_newlinest=outputst"\n"1letrecflat_renderstl=matchlwith|Texts::r|Break(s,_)::r->outputsts(String.lengths);flat_renderstr|Set_posp::r->p.p_line<-st.line;p.p_col<-st.col;flat_renderstr|(Start_group_|End_group)::r->flat_renderstr|[]->()letrecpushste=ifst.n=0then((* Vertical rendering *)matchewith|Texts->outputsts(String.lengths);st.cur<-st.cur+String.lengths|Set_posp->p.p_line<-st.line;p.p_col<-st.col|Break(_,offs)->output_newlinest;letindent=st.box_indent+offsinst.indent<-indent;output_spacesstindent;st.limit<-max(indent+60)78;st.cur<-st.indent|Start_groupn->st.n<-1;st.w<-st.limit-st.cur;st.prev_indents<-(st.box_indent,st.indent)::st.prev_indents;st.indent<-st.indent+n;st.box_indent<-st.indent|End_group->st.box_indent<-fst(List.hdst.prev_indents);st.indent<-snd(List.hdst.prev_indents);st.prev_indents<-List.tlst.prev_indents)else((* Fits? *)st.l<-e::st.l;matchewith|Texts|Break(s,_)->letw=st.w-String.lengthsinst.w<-w;ifw<0then(letl=List.revst.linst.l<-[];st.n<-0;List.iter~f:(fune->pushste)l)|Set_pos_->()|Start_group_->st.n<-st.n+1|End_group->st.n<-st.n-1;ifst.n=0then(flat_renderst(List.revst.l);st.box_indent<-fst(List.hdst.prev_indents);st.indent<-snd(List.hdst.prev_indents);st.prev_indents<-List.tlst.prev_indents;st.cur<-st.cur+st.w;st.l<-[]))letcheckst=assert(List.is_emptyst.prev_indents)(****)letstringst(s:string)=ifst.compactthen(letlen=String.lengthsiniflen<>0then((matchst.pending_spacewith|None->()|Somesp->(st.pending_space<-None;matchst.last_char,st.needed_spacewith|Somelast,Somef->ifflasts.[0]thenoutputstsp1|_,None->outputstsp1|_->()));outputstslen;st.last_char<-Somes.[len-1]))elsepushst(Texts)letgenbreakstsn=ifnotst.compactthenpushst(Break(s,n))letbreak_token=Break("",0)letbreakst=ifnotst.compactthenpushstbreak_tokenletbreak1st=ifnotst.compactthenpushst(Break("",1))letnon_breaking_space_token=Text" "letnon_breaking_spacest=ifst.compactthenst.pending_space<-Some" "elsepushstnon_breaking_space_tokenletspace?(indent=0)st=ifst.compactthenst.pending_space<-Some"\n"elsepushst(Break(" ",indent))letstart_groupstn=ifnotst.compactthenpushst(Start_groupn)letend_groupst=ifnotst.compactthenpushstEnd_group(*
let render l =
let st = { indent = 0; box_indent = 0; prev_indents = [];
limit = 78; cur = 0; l = []; n = 0; w = 0;
output = fun s i l -> output stdout s i l } in
push st (Start_group 0);
List.iter (fun e -> push st e) l;
push st End_group;
output_newline st
let rec tree n =
if n = 0 then [Text "Leaf"] else
[Start_group 10; Text "Node.... ("] @ tree (n - 1) @
[Text ","; Break (" ", 0)] @ tree (n - 1) @ [Text ")"; End_group]
let _ =
for i = 1 to 10 do render (tree i) done
*)lettotalt=t.totalletpost=ift.compactthen{p_line=t.line;p_col=t.col}elseletp={p_line=-1;p_col=-1}inpusht(Set_posp);pletnewlinest=output_newlinest;st.indent<-0;st.box_indent<-0;st.prev_indents<-[];st.cur<-0;st.l<-[];st.n<-0;st.w<-0letto_out_channelch={indent=0;box_indent=0;prev_indents=[];limit=78;cur=0;l=[];n=0;w=0;col=0;line=0;total=0;compact=false;pending_space=None;last_char=None;needed_space=None;adjust_indentation=None;output=output_substringch}letto_bufferb={indent=0;box_indent=0;prev_indents=[];limit=78;cur=0;l=[];n=0;w=0;col=0;line=0;total=0;compact=false;pending_space=None;last_char=None;needed_space=None;adjust_indentation=None;output=(funsil->Buffer.add_substringbsil)}letset_compactstv=st.compact<-vletcompactst=st.compactletset_needed_space_functionstf=st.needed_space<-Somefletset_adjust_indentation_functionstf=st.adjust_indentation<-Somef