123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781openFormat(** Shadow map and split with tailrecursive variants. *)moduleList=structincludeList(** Tail recursive of map *)letmapfl=List.rev_mapfl|>List.rev(** Tail recursive versionofsplit *)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_name option;}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_name option;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|Labelof(t*label_param)*t|Custom of(formatter ->unit)typeescape=[`None|`Escapeof((string ->int->int->unit)->string->int->int->unit)|`Escape_string of (string->string)]type styles=(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)acc2 inmap_node(Label((new_x1,param),new_x2))acc|Custom_->letacc=init_accxinmap_nodexaccinauxx(*
Convert wrappablelists 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 treeto 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 =#if OCAML_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#if OCAML_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.length s1)inset_escapefmtescapeletdefine_stylesfmtescapel=ifl<>[]then(pp_set_tags fmttrue;lettbl1=Hashtbl.create(2*List.lengthl)inlettbl2 =Hashtbl.create(2*List.lengthl)inList.iter(fun(style_name,style)->Hashtbl.addtbl1 style_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_tagstyle_name->(tryHashtbl.findtbl2style_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_hovbox fmtindentelsepp_open_hvboxfmtindent|`Force_breaks|`Force_breaks_rec ->pp_open_vboxfmtindent|`No_breaks->pp_open_hboxfmt ()let open_tagfmt=functionNone->()|Somes->#ifOCAML_VERSION>=(5,0,0)pp_open_stag#else(pp_open_tag[@warning"-3"])#endiffmtslet close_tagfmt=functionNone->()|Some _->#ifOCAML_VERSION>=(5,0,0)pp_close_stag#else(pp_close_tag[@warning"-3"])#endiffmt()lettag_string fmtos=matchowithNone->pp_print_stringfmts|Sometag->#ifOCAML_VERSION>=(5,0,0)pp_open_stag fmt(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_tagfmt p.list_style;#endififp.align_closingthenfprint_listfmtNoneparamlelsefprint_list2fmtparam l;close_tagfmtp.list_style|Label(label,x)->fprint_pairfmtlabelx|Customf-> ffmtandfprint_list_body_stick_leftfmtpsephdtl=#ifOCAML_VERSION>=(5,0,0)open_tag fmt(matchp.body_stylewithSomebs->Some(Format.String_tagbs)|None->None);#elseopen_tag fmtp.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_t fmtx)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_stringfmtp.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_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_stylecl|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_box plinopen_extrafmt;fprint_list_body_stick_leftfmtpsephdtl;close_extra fmt;ifp.space_before_closingthenpp_print_breakfmt1(-indent)elsepp_print_breakfmt0(-indent);tag_stringfmtp.closing_stylecl;pp_close_boxfmt()andfprint_list_stick_right fmtlabel(op,sep,cl,p)hdtl l=letbase_indent=p.indent_bodyinletsep_indent=String.lengthsep+(ifp.space_after_separatorthen1else0)inletindent=base_indent+sep_indentinpp_open_xboxfmtpindent;fprint_opt_labelfmtlabel;tag_stringfmtp.opening_styleop;ifp.space_after_openingthenpp_print_space fmt()elsepp_print_cutfmt();letopen_extra,close_extra=extra_boxplinopen_extrafmt;fprint_t fmthd;List.iter(funx->ifp.space_before_separator thenpp_print_break fmt1(-sep_indent)elsepp_print_break fmt0(-sep_indent);tag_stringfmtp.separator_stylesep;ifp.space_after_separator thenpp_print_string fmt" ";fprint_tfmtx)tl;close_extrafmt;ifp.space_before_closing thenpp_print_breakfmt 1(-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_styleop;ifp.space_after_opening||p.space_before_closingthenpp_print_string fmt" ";tag_stringfmt p.closing_stylecl|hd::tlasl->tag_stringfmtp.opening_style op;ifp.space_after_openingthenpp_print_stringfmt" ";pp_open_nonaligned_boxfmtp0l;ifp.separators_stick_leftthenfprint_list_body_stick_leftfmtpsephdtlelsefprint_list_body_stick_rightfmtpsephdtl;pp_close_boxfmt();ifp.space_before_closingthenpp_print_stringfmt" ";tag_stringfmtp.closing_stylecl(* Printing a label:value pair.
The opening bracket stays on the sameline 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_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_breakfmt1indentelsepp_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()letto_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_channel ocindefine_stylesfmtescapestyles;to_formatterfmtxletto_stdout?escape?styles x=to_channel?escape?stylesstdoutxletto_stderr?escape?stylesx=to_channel?escape ?stylesstderrxendmoduleCompact=structopenPrintfletrecfprint_tbuf=functionAtom(s,_)->Buffer.add_stringbufs|List(param,l)->fprint_listbufparaml|Label(label,x)->fprint_pairbuflabelx|Customf->(* Will most likely not be compact*)letfmt=formatter_of_bufferbufinffmt;pp_print_flushfmt()andfprint_listbuf(op,sep,cl,_)=function[]->bprintfbuf"%s%s"opcl|x::tl->Buffer.add_string bufop;fprint_tbufx;List.iter(funx->Buffer.add_stringbufsep;fprint_tbufx)tl;Buffer.add_stringbufclandfprint_pairbuf(label,_)x=fprint_tbuflabel;fprint_tbufxletto_bufferbufx=fprint_tbufxletto_stringx=letbuf =Buffer.create500into_buffer bufx;Buffer.contentsbufletto_formatterfmtx=lets=to_stringxinFormat.fprintffmt"%s"s;pp_print_flushfmt()letto_channel ocx=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