123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781openFormat(** Shadow map and split with tailrecursive variants. *)moduleList=structincludeList(** Tail recursive of map *)letmapfl=List.rev_mapfl|>List.rev(** Tail recursive version ofsplit *)letrev_splitl=letrecinnerxsys=function|(x,y)::xys->inner(x::xs)(y::ys)xys|[]->(xs,ys)ininner[][]lletsplitl=rev_split (List.revl)endtypewrap=[|`Wrap_atoms|`Always_wrap|`Never_wrap|`Force_breaks|`Force_breaks_rec|`No_breaks]typelabel_break=[|`Auto|`Always|`Always_rec|`Never]typestyle_name=stringtypestyle={tag_open:string;tag_close :string}typeatom_param ={atom_style:style_nameoption;}letatom={atom_style=None}typelist_param={space_after_opening :bool;space_after_separator:bool;space_before_separator:bool;separators_stick_left:bool;space_before_closing:bool;stick_to_label:bool;align_closing:bool;wrap_body:wrap;indent_body:int;list_style:style_nameoption;opening_style:style_nameoption;body_style:style_nameoption;separator_style:style_nameoption;closing_style:style_name option;}letlist={space_after_opening =true;space_after_separator =true;space_before_separator=false;separators_stick_left=true;space_before_closing=true;stick_to_label=true;align_closing=true;wrap_body=`Wrap_atoms;indent_body=2;list_style=None;opening_style=None;body_style=None;separator_style=None;closing_style=None;}typelabel_param={label_break:label_break;space_after_label:bool;indent_after_label:int;label_style:style_nameoption;}letlabel={label_break=`Auto;space_after_label=true;indent_after_label=2;label_style=None;}typet=Atomofstring*atom_param|Listof(string*string*string*list_param)*tlist|Label of(t*label_param)*t|Custom of(formatter ->unit)typeescape=[`None|`Escapeof((string ->int ->int->unit)->string->int->int->unit)|`Escape_string of(string->string)]typestyles=(style_name*style)list(*
Transform a tree starting from the leaves, propagating and merging
accumulators until reaching the root.
*)letpropagate_from_leaf_to_root~init_acc(* create initial accumulator for a leaf *)~merge_acc(* merge two accumulators coming from child nodes *)~map_node(* (node, acc) -> (node, acc) *)x=letrecauxx=match xwith|Atom_->letacc=init_accxinmap_nodexacc|List(param,children)->letnew_children,accs=List.rev_split(List.rev_mapauxchildren)inletacc=List.fold_leftmerge_acc(init_accx)accsinmap_node(List(param,new_children))acc|Label((x1,param),x2)->letacc0 =init_accxinletnew_x1,acc1=auxx1inletnew_x2,acc2=auxx2inletacc=merge_acc(merge_accacc0acc1)acc2inmap_node(Label((new_x1,param),new_x2))acc|Custom _->let acc=init_accxinmap_nodexaccinauxx(*
Convert wrappable lists into vertical lists if any of their descendants
has the attribute wrap_body = `Force_breaks_rec.
*)letpropagate_forced_breaksx=(* acc = whether to force breaks in wrappable lists or labels*)letinit_acc=function|List((_,_,_,{wrap_body=`Force_breaks_rec}),_)|Label((_,{label_break=`Always_rec}),_)->true|Atom_|Label_|Custom_|List_->falseinletmerge_accforce_breaks1force_breaks2=force_breaks1||force_breaks2inletmap_node xforce_breaks =matchxwith|List((_,_,_,{wrap_body=`Force_breaks_rec }),_)->x,true|List((_,_,_,{wrap_body=`Force_breaks}),_)->x,force_breaks|List((op,sep,cl,({wrap_body=(`Wrap_atoms|`Never_wrap|`Always_wrap)}asp)),children)->ifforce_breaksthenletp={pwithwrap_body=`Force_breaks}inList((op,sep,cl,p),children),trueelsex,false|Label ((a,({label_break =`Auto}aslp)),b)->ifforce_breaksthenletlp={lpwithlabel_break=`Always}inLabel((a,lp),b),trueelsex,false|List((_,_,_,{wrap_body=`No_breaks}),_)|Label((_,{label_break=(`Always|`Always_rec|`Never)}),_)|Atom_|Custom_->x,force_breaksinletnew_x,forced_breaks=propagate_from_leaf_to_root~init_acc~merge_acc~map_nodexinnew_xmodulePretty=struct(*
Rewrite the tree to be printed.
Currently, this is used only to handle `Force_breaks_rec.
*)letrewritex=propagate_forced_breaksx(*
Relies on the fact that mark_open_tag and mark_close_tag
are called exactly once before calling pp_output_string once.
It's a reasonable assumption although not guaranteed by the
documentation of the Format module.
*)letset_escapefmtescape=letprint0,flush0=pp_get_formatter_output_functionsfmt()inlettagf0=#ifOCAML_VERSION>=(5,0,0)pp_get_formatter_stag_functions#else(pp_get_formatter_tag_functions[@warning"-3"])#endiffmt()inletis_tag=reffalseinletmottag=is_tag:=true;#ifOCAML_VERSION>=(5,0,0)tagf0.mark_open_stagtag#elsetagf0.mark_open_tagtag#endifinletmcttag=is_tag:=true;#ifOCAML_VERSION>=(5,0,0)tagf0.mark_close_stagtag#elsetagf0.mark_close_tagtag#endifinletprintspn=if!is_tagthen(print0spn;is_tag:=false)elseescapeprint0spninlettagf={tagf0with#ifOCAML_VERSION>=(5,0,0)mark_open_stag=mot;mark_close_stag=mct#elsemark_open_tag=mot;mark_close_tag =mct#endif}inpp_set_formatter_output_functionsfmtprintflush0;#ifOCAML_VERSION>=(5,0,0)pp_set_formatter_stag_functions#else(pp_set_formatter_tag_functions[@warning"-3"])#endiffmttagfletset_escape_stringfmtesc=letescapeprintspn=lets0=String.subspninlets1=escs0inprints10(String.lengths1)inset_escape fmtescapeletdefine_stylesfmtescapel=ifl<>[]then(pp_set_tagsfmttrue;lettbl1=Hashtbl.create(2*List.lengthl)inlettbl2=Hashtbl.create(2*List.lengthl)inList.iter(fun(style_name,style)->Hashtbl.addtbl1style_namestyle.tag_open;Hashtbl.addtbl2style_name style.tag_close)l;#if OCAML_VERSION>=(5,0,0)letmark_open_tag=function|Format.String_tagstyle_name->(tryHashtbl.findtbl1style_namewithNot_found->"")|_->""inletmark_close_tag=function|Format.String_tagstyle_name->(tryHashtbl.findtbl2style_namewithNot_found->"")|_->""#elseletmark_open_tagstyle_name=tryHashtbl.findtbl1style_namewithNot_found->""inletmark_close_tagstyle_name=tryHashtbl.findtbl2style_namewithNot_found->""#endifinlettagf={(#ifOCAML_VERSION>=(5,0,0)pp_get_formatter_stag_functions#else(pp_get_formatter_tag_functions[@warning"-3"])#endiffmt())with#ifOCAML_VERSION>=(5,0,0)mark_open_stag=mark_open_tag;mark_close_stag=mark_close_tag;#elsemark_open_tag=mark_open_tag;mark_close_tag=mark_close_tag;#endif}in#ifOCAML_VERSION>=(5,0,0)pp_set_formatter_stag_functions#else(pp_set_formatter_tag_functions[@warning"-3"])#endiffmttagf);(matchescapewith`None->()|`Escapeesc->set_escapefmtesc|`Escape_stringesc->set_escape_stringfmtesc)letpp_open_xboxfmtpindent=matchp.wrap_bodywith`Always_wrap|`Never_wrap|`Wrap_atoms->pp_open_hvboxfmtindent|`Force_breaks|`Force_breaks_rec->pp_open_vboxfmtindent|`No_breaks->pp_open_hboxfmt()let extra_boxpl=letwrap=matchp.wrap_bodywith`Always_wrap->true|`Never_wrap|`Force_breaks|`Force_breaks_rec|`No_breaks->false|`Wrap_atoms->List.for_all(functionAtom_->true|_->false)linifwrapthen((funfmt->pp_open_hovbox fmt0),(funfmt->pp_close_boxfmt()))else((funfmt->()),(funfmt->()))letpp_open_nonaligned_boxfmtpindentl=matchp.wrap_bodywith`Always_wrap->pp_open_hovboxfmtindent|`Never_wrap->pp_open_hvboxfmtindent|`Wrap_atoms->ifList.for_all(functionAtom_->true|_->false)lthenpp_open_hovbox fmtindentelsepp_open_hvboxfmtindent|`Force_breaks|`Force_breaks_rec->pp_open_vboxfmtindent|`No_breaks->pp_open_hboxfmt()letopen_tagfmt=functionNone->()|Somes->#ifOCAML_VERSION>=(5,0,0)pp_open_stag#else(pp_open_tag[@warning"-3"])#endiffmtsletclose_tagfmt=functionNone->()|Some_->#ifOCAML_VERSION>=(5,0,0)pp_close_stag#else(pp_close_tag[@warning"-3"])#endiffmt()lettag_stringfmt os=matchowithNone->pp_print_stringfmts|Sometag->#ifOCAML_VERSION>=(5,0,0)pp_open_stagfmt(Format.String_tagtag);#else(pp_open_tag[@warning"-3"])fmttag;#endifpp_print_stringfmts;#ifOCAML_VERSION>=(5,0,0)pp_close_stagfmt()#else(pp_close_tag[@warning"-3"])fmt()#endifletrecfprint_tfmt=functionAtom(s,p)->tag_stringfmtp.atom_styles;|List((_,_,_,p)asparam,l)->#ifOCAML_VERSION>=(5,0,0)open_tagfmt(matchp.list_stylewithSomels->Some(Format.String_tagls)|None->None);#elseopen_tagfmtp.list_style;#endififp.align_closing thenfprint_listfmtNoneparamlelsefprint_list2fmtparaml;close_tagfmtp.list_style|Label (label,x)->fprint_pairfmtlabelx|Customf->ffmtandfprint_list_body_stick_leftfmtpsephdtl=#ifOCAML_VERSION>=(5,0,0)open_tagfmt(matchp.body_stylewithSomebs->Some (Format.String_tagbs)|None->None);#elseopen_tagfmtp.body_style;#endiffprint_tfmthd;List.iter(funx->ifp.space_before_separatorthenpp_print_stringfmt" ";tag_stringfmtp.separator_stylesep;ifp.space_after_separatorthenpp_print_spacefmt()elsepp_print_cutfmt();fprint_tfmtx)tl;close_tagfmtp.body_styleandfprint_list_body_stick_rightfmtpsephdtl=#ifOCAML_VERSION>=(5,0,0)open_tagfmt(matchp.body_stylewithSomebs->Some(Format.String_tagbs)|None->None);#elseopen_tag fmtp.body_style;#endiffprint_tfmthd;List.iter(funx->ifp.space_before_separatorthenpp_print_spacefmt()elsepp_print_cutfmt();tag_stringfmtp.separator_stylesep;ifp.space_after_separatorthenpp_print_stringfmt" ";fprint_tfmtx)tl;close_tagfmtp.body_styleand fprint_opt_labelfmt=functionNone->()|Some(lab,lp)->#ifOCAML_VERSION>=(5,0,0)open_tag fmt(matchlp.label_stylewithSomels->Some(Format.String_tagls)|None->None);#elseopen_tagfmtlp.label_style;#endiffprint_tfmtlab;close_tagfmtlp.label_style;iflp.space_after_labelthenpp_print_stringfmt" "(* Either horizontal or vertical list *)andfprint_listfmtlabel((op,sep,cl,p)asparam)=function[]->fprint_opt_labelfmtlabel;tag_stringfmtp.opening_styleop;ifp.space_after_opening||p.space_before_closingthenpp_print_stringfmt" ";tag_stringfmtp.closing_style cl|hd::tlasl->iftl=[]||p.separators_stick_leftthenfprint_list_stick_leftfmtlabelparamhdtllelsefprint_list_stick_right fmtlabelparamhdtllandfprint_list_stick_leftfmtlabel(op,sep,cl,p)hdtll=letindent=p.indent_bodyinpp_open_xboxfmtpindent;fprint_opt_labelfmtlabel;tag_stringfmtp.opening_styleop;ifp.space_after_openingthenpp_print_spacefmt()elsepp_print_cutfmt();letopen_extra,close_extra=extra_boxplinopen_extra fmt;fprint_list_body_stick_leftfmtpsephdtl;close_extrafmt;ifp.space_before_closingthenpp_print_breakfmt1(-indent)elsepp_print_breakfmt0(-indent);tag_stringfmtp.closing_stylecl;pp_close_boxfmt()andfprint_list_stick_rightfmtlabel(op,sep,cl,p)hdtll=letbase_indent =p.indent_bodyinletsep_indent=String.length sep+(ifp.space_after_separatorthen1else0)inletindent=base_indent+sep_indentinpp_open_xbox fmtpindent;fprint_opt_labelfmtlabel;tag_stringfmtp.opening_styleop;ifp.space_after_openingthenpp_print_spacefmt()elsepp_print_cutfmt();letopen_extra,close_extra=extra_boxplinopen_extrafmt;fprint_tfmthd;List.iter(funx->ifp.space_before_separator thenpp_print_break fmt1(-sep_indent)elsepp_print_breakfmt0(-sep_indent);tag_stringfmtp.separator_style sep;ifp.space_after_separatorthenpp_print_stringfmt" ";fprint_t fmtx)tl;close_extra fmt;ifp.space_before_closingthenpp_print_breakfmt1(-indent)elsepp_print_breakfmt0(-indent);tag_stringfmtp.closing_stylecl;pp_close_boxfmt()(* align_closing = false *)andfprint_list2fmt(op,sep,cl,p)=function[]->tag_stringfmtp.opening_style op;ifp.space_after_opening||p.space_before_closingthenpp_print_stringfmt" ";tag_stringfmtp.closing_stylecl|hd::tlasl->tag_stringfmtp.opening_styleop;if p.space_after_opening thenpp_print_string fmt" ";pp_open_nonaligned_boxfmtp0l;ifp.separators_stick_leftthenfprint_list_body_stick_left fmtpsephdtlelsefprint_list_body_stick_right fmtpsephdtl;pp_close_boxfmt();ifp.space_before_closingthenpp_print_string fmt" ";tag_stringfmtp.closing_stylecl(* Printing a label:value pair.
The opening bracket stays on thesame line as the key, no matter what, and the closing bracket is either on the same line
or vertically aligned with the beginning of the key.
*)andfprint_pair fmt((lab,lp)aslabel)x=matchxwithList((op,sep,cl,p),l)whenp.stick_to_label&&p.align_closing->fprint_listfmt(Somelabel)(op,sep,cl,p)l|_->letindent=lp.indent_after_labelinpp_open_hvboxfmt0;#ifOCAML_VERSION>=(5,0,0)open_tagfmt(matchlp.label_stylewithSomels->Some(Format.String_tagls)|None->None);#elseopen_tagfmtlp.label_style;#endiffprint_tfmtlab;close_tagfmtlp.label_style;(matchlp.label_breakwith|`Auto->iflp.space_after_labelthenpp_print_break fmt1indentelsepp_print_breakfmt0indent|`Always|`Always_rec->pp_force_newlinefmt();pp_print_stringfmt(String.makeindent' ')|`Never->iflp.space_after_labelthenpp_print_charfmt' 'else());fprint_tfmtx;pp_close_boxfmt()let to_formatterfmtx=letx=rewritexinfprint_tfmtx;pp_print_flushfmt()letto_buffer?(escape=`None)?(styles=[])bufx=letfmt=Format.formatter_of_bufferbufindefine_stylesfmtescapestyles;to_formatterfmtxletto_string?escape?stylesx=letbuf=Buffer.create500into_buffer?escape?stylesbufx;Buffer.contentsbufletto_channel?(escape =`None)?(styles=[])ocx=letfmt=formatter_of_out_channelocindefine_stylesfmtescapestyles;to_formatterfmtxletto_stdout?escape?stylesx=to_channel ?escape ?stylesstdoutxletto_stderr?escape?stylesx=to_channel?escape?stylesstderrxendmoduleCompact=structopenPrintfletrecfprint_tbuf=functionAtom(s,_)->Buffer.add_stringbufs|List(param,l)->fprint_listbuf paraml|Label(label,x)->fprint_pairbuflabelx|Customf->(* Will most likely not be compact *)letfmt=formatter_of_bufferbufinffmt;pp_print_flush fmt()andfprint_listbuf(op,sep,cl,_)=function[]->bprintfbuf "%s%s"opcl|x::tl->Buffer.add_stringbufop;fprint_tbuf x;List.iter(funx->Buffer.add_stringbufsep;fprint_t bufx)tl;Buffer.add_stringbufclandfprint_pair buf(label,_)x=fprint_tbuflabel;fprint_tbufxletto_bufferbufx=fprint_t bufxletto_string x=letbuf=Buffer.create500into_bufferbufx;Buffer.contentsbufletto_formatter fmtx=lets=to_string xinFormat.fprintf fmt "%s"s;pp_print_flushfmt()letto_channelocx=letbuf=Buffer.create500into_bufferbufx;Buffer.output_bufferocbufletto_stdoutx=to_channelstdoutxletto_stderrx=to_channelstderrxend(* Obsolete *)moduleParam=structletlist_true={space_after_opening=true;space_after_separator=true;space_before_separator=true;separators_stick_left=true;space_before_closing=true;stick_to_label=true;align_closing =true;wrap_body=`Wrap_atoms;indent_body=2;list_style=None;opening_style=None;body_style=None;separator_style=None;closing_style=None;}letlist_false={space_after_opening=false;space_after_separator =false;space_before_separator=false;separators_stick_left=false;space_before_closing =false;stick_to_label=false;align_closing=false;wrap_body=`Wrap_atoms;indent_body=2;list_style=None;opening_style=None;body_style=None;separator_style=None;closing_style=None;}letlabel_true={label_break=`Auto;space_after_label =true;indent_after_label=2;label_style=None;}letlabel_false ={label_break=`Auto;space_after_label=false;indent_after_label=2;label_style=None;}end