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_nameoption;}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_namestyle.tag_close)l;#ifOCAML_VERSION>=(5,0,0)letmark_open_tag=function|Format.String_tagstyle_name->(tryHashtbl.findtbl1style_namewithNot_found->"")|_->""inletmark_close_tag=function|Format.String_tag style_name->(tryHashtbl.find tbl2 style_namewithNot_found->"")|_->""#elseletmark_open_tagstyle_name=tryHashtbl.findtbl1style_namewithNot_found->""inletmark_close_tag style_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()letextra_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_hovboxfmt0),(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_hovboxfmt indentelsepp_open_hvbox fmtindent|`Force_breaks|`Force_breaks_rec->pp_open_vbox fmt indent|`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_stringfmtos=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_closingthenfprint_listfmtNoneparamlelsefprint_list2fmtparaml;close_tagfmtp.list_style|Label(label,x)->fprint_pairfmtlabelx|Customf->ffmtand fprint_list_body_stick_leftfmtpsephdtl=#ifOCAML_VERSION>=(5,0,0)open_tagfmt(match p.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_tagfmtp.body_style;#endiffprint_tfmthd;List.iter(funx->ifp.space_before_separatorthenpp_print_spacefmt()elsepp_print_cutfmt();tag_string fmtp.separator_stylesep;ifp.space_after_separatorthenpp_print_stringfmt" ";fprint_tfmtx)tl;close_tagfmtp.body_styleandfprint_opt_labelfmt=functionNone->()|Some(lab,lp)->#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;iflp.space_after_labelthenpp_print_stringfmt" "(* Either horizontal or vertical list *)andfprint_list fmtlabel((op,sep,cl,p)asparam)=function[]->fprint_opt_labelfmtlabel;tag_stringfmt p.opening_styleop;ifp.space_after_opening||p.space_before_closingthenpp_print_string fmt" ";tag_stringfmtp.closing_stylecl|hd::tlasl->iftl=[]||p.separators_stick_leftthenfprint_list_stick_leftfmtlabelparamhdtllelsefprint_list_stick_rightfmtlabelparamhdtllandfprint_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_extrafmt;fprint_list_body_stick_leftfmtpsephdtl;close_extrafmt;ifp.space_before_closingthenpp_print_breakfmt1(-indent)elsepp_print_breakfmt0(-indent);tag_string fmtp.closing_stylecl;pp_close_boxfmt()andfprint_list_stick_rightfmtlabel(op,sep,cl,p)hdtll=letbase_indent=p.indent_bodyinletsep_indent=String.lengthsep+(ifp.space_after_separatorthen1else 0)inletindent=base_indent+sep_indentinpp_open_xboxfmtpindent;fprint_opt_labelfmtlabel;tag_stringfmtp.opening_styleop;ifp.space_after_opening thenpp_print_space fmt()elsepp_print_cutfmt();letopen_extra,close_extra=extra_boxplinopen_extrafmt;fprint_tfmthd;List.iter(funx->ifp.space_before_separatorthenpp_print_breakfmt1(-sep_indent)elsepp_print_breakfmt0(-sep_indent);tag_stringfmtp.separator_stylesep;ifp.space_after_separator thenpp_print_stringfmt" ";fprint_tfmtx)tl;close_extrafmt;ifp.space_before_closingthenpp_print_breakfmt1(-indent)elsepp_print_breakfmt0(-indent);tag_stringfmtp.closing_stylecl;pp_close_box fmt()(* align_closing = false *)andfprint_list2 fmt(op,sep,cl,p)=function[]->tag_stringfmtp.opening_styleop;ifp.space_after_opening||p.space_before_closingthenpp_print_stringfmt" ";tag_stringfmtp.closing_stylecl|hd::tlasl->tag_stringfmtp.opening_styleop;ifp.space_after_openingthenpp_print_stringfmt" ";pp_open_nonaligned_boxfmtp0l;if p.separators_stick_leftthenfprint_list_body_stick_leftfmtpsephdtlelsefprint_list_body_stick_rightfmtpsephdtl;pp_close_boxfmt();ifp.space_before_closingthenpp_print_string fmt" ";tag_stringfmtp.closing_stylecl(* Printing a label:value pair.
The opening bracket stays on the same 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_pairfmt((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_stylewithSome ls->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_breakfmt 1indentelsepp_print_break fmt0indent|`Always|`Always_rec->pp_force_newlinefmt();pp_print_stringfmt(String.makeindent' ')|`Never->iflp.space_after_labelthenpp_print_charfmt' 'else());fprint_tfmtx;pp_close_boxfmt()letto_formatterfmtx=letx=rewritexinfprint_tfmtx;pp_print_flushfmt()letto_buffer?(escape=`None)?(styles=[])bufx=letfmt=Format.formatter_of_bufferbufindefine_stylesfmtescape styles;to_formatterfmtxletto_string?escape?stylesx=letbuf=Buffer.create500into_buffer?escape?stylesbufx;Buffer.contentsbufletto_channel?(escape=`None)?(styles=[])ocx=letfmt=formatter_of_out_channeloc indefine_stylesfmtescapestyles;to_formatterfmtxletto_stdout?escape?stylesx=to_channel?escape?stylesstdoutxletto_stderr?escape?stylesx=to_channel?escape?styles stderrxendmoduleCompact=structopenPrintfletrecfprint_tbuf=functionAtom(s,_)->Buffer.add_stringbufs|List(param,l)->fprint_listbufparaml|Label(label,x)->fprint_pairbuflabelx|Customf->(* Willmost 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_tbufx;List.iter(funx->Buffer.add_stringbufsep;fprint_tbufx)tl;Buffer.add_stringbufclandfprint_pairbuf(label,_)x=fprint_t buflabel;fprint_tbufxletto_bufferbufx=fprint_tbufxletto_stringx=letbuf=Buffer.create500into_bufferbufx;Buffer.contentsbufletto_formatterfmtx=lets=to_stringxinFormat.fprintffmt"%s"s;pp_print_flushfmt()letto_channel ocx=letbuf=Buffer.create500into_bufferbufx;Buffer.output_bufferocbufletto_stdoutx=to_channelstdout xletto_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;}let list_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