123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* The different kinds of blocks are:
\begin{description}
\item[hbox:] Horizontal block no line breaking;
\item[vbox:] Vertical block each break leads to a new line;
\item[hvbox:] Horizontal-vertical block: same as vbox, except if
this block is small enough to fit on a single line
\item[hovbox:] Horizontal or Vertical block: breaks lead to new line
only when necessary to print the content of the block
\end{description}
*)typepp_tag=stringtypeblock_type=|Pp_hbox|Pp_vboxofint|Pp_hvboxofint|Pp_hovboxofinttypedoc_view=|Ppcmd_empty|Ppcmd_stringofstring|Ppcmd_glueofdoc_viewlist|Ppcmd_boxofblock_type*doc_view|Ppcmd_tagofpp_tag*doc_view(* Are those redundant? *)|Ppcmd_print_breakofint*int|Ppcmd_force_newline|Ppcmd_commentofstringlist(* Following discussion on #390, we play on the safe side and make the
internal representation opaque here. *)typet=doc_viewletreprx=xletunreprx=x(* Compute length of an UTF-8 encoded string
Rem 1 : utf8_length <= String.length (equal if pure ascii)
Rem 2 : if used for an iso8859_1 encoded string, the result is
wrong in very rare cases. Such a wrong case corresponds to any
sequence of a character in range 192..253 immediately followed by a
character in range 128..191 (typical case in french is "déçu" which
is counted 3 instead of 4); then no real harm to use always
utf8_length even if using an iso8859_1 encoding *)letutf8_lengths=letlen=String.lengthsandcnt=ref0andnc=ref0andp=ref0inwhile!p<lendobeginmatchs.[!p]with|'\000'..'\127'->nc:=0(* ascii char *)|'\128'..'\191'->nc:=0(* cannot start with a continuation byte *)|'\192'..'\223'->nc:=1(* expect 1 continuation byte *)|'\224'..'\239'->nc:=2(* expect 2 continuation bytes *)|'\240'..'\247'->nc:=3(* expect 3 continuation bytes *)|'\248'..'\251'->nc:=4(* expect 4 continuation bytes *)|'\252'..'\253'->nc:=5(* expect 5 continuation bytes *)|'\254'..'\255'->nc:=0(* invalid byte *)end;incrp;while!p<len&&!nc>0domatchs.[!p]with|'\128'..'\191'(* next continuation byte *)->incrp;decrnc|_(* not a continuation byte *)->nc:=0done;incrcntdone;!cntletrecappd1d2=matchd1,d2with|Ppcmd_empty,d|d,Ppcmd_empty->d(* Optimizations *)|Ppcmd_glue[l1;l2],Ppcmd_gluel3->Ppcmd_glue(l1::l2::l3)|Ppcmd_glue[l1;l2],d2->Ppcmd_glue[l1;l2;d2]|d1,Ppcmd_gluel2->Ppcmd_glue(d1::l2)|Ppcmd_tag(t1,d1),Ppcmd_tag(t2,d2)whent1=t2->Ppcmd_tag(t1,appd1d2)|d1,d2->Ppcmd_glue[d1;d2](* Optimizations deemed too costly *)(* | Ppcmd_glue l1, Ppcmd_glue l2 -> Ppcmd_glue (l1 @ l2) *)(* | Ppcmd_string s1, Ppcmd_string s2 -> Ppcmd_string (s1 ^ s2) *)letseqs=Ppcmd_glueslet(++)=app(* formatting commands *)letstrs=Ppcmd_stringsletbrk(a,b)=Ppcmd_print_break(a,b)letfnl()=Ppcmd_force_newlineletwsn=Ppcmd_print_break(n,0)letcommentl=Ppcmd_commentl(* derived commands *)letmt()=Ppcmd_emptyletspc()=Ppcmd_print_break(1,0)letcut()=Ppcmd_print_break(0,0)letalign()=Ppcmd_print_break(0,0)letintn=str(string_of_intn)letint64n=str(Int64.to_stringn)letrealr=str(string_of_floatr)letboolb=str(string_of_boolb)(* XXX: To Remove *)letstrbrks=letrecauxpn=ifn<String.lengthsthenifs.[n]=' 'thenifp=nthenspc()::aux(n+1)(n+1)elsestr(String.subsp(n-p))::spc()::aux(n+1)(n+1)elseauxp(n+1)elseifp=nthen[]else[str(String.subsp(n-p))]inPpcmd_glue(aux00)letismt=function|Ppcmd_empty->true|_->false(* boxing commands *)leths=Ppcmd_box(Pp_hbox,s)letvns=Ppcmd_box(Pp_vboxn,s)lethvns=Ppcmd_box(Pp_hvboxn,s)lethovns=Ppcmd_box(Pp_hovboxn,s)(* Opening and closing of tags *)lettagts=Ppcmd_tag(t,s)letqstrings=str(CString.quote_coq_strings)letqs=qstringletquotes=h(str"\""++s++str"\"")letrecpr_comfts=let(s1,os)=tryletn=String.indexs'\n'inString.subs0n,Some(String.subs(n+1)(String.lengths-n-1))withNot_found->s,NoneinFormat.pp_print_asft(utf8_lengths1)s1;matchoswithSomes2->Format.pp_force_newlineft();pr_comfts2|None->()letpr_comfts=pr_comfts;Format.pp_print_breakft00letstart_pfx="start."letend_pfx="end."letsplit_pfxpfxstr=let(str_len,pfx_len)=(String.lengthstr,String.lengthpfx)inifstr_len>=pfx_len&&(String.substr0pfx_len)=pfxthen(pfx,String.substrpfx_len(str_len-pfx_len))else("",str);;letsplit_tagtag=let(pfx,ttag)=split_pfxstart_pfxtaginifpfx<>""then(pfx,ttag)elselet(pfx,ttag)=split_pfxend_pfxtagin(pfx,ttag);;(* pretty printing functions *)letpp_withftpp=letcpp_open_box=function|Pp_hbox->Format.pp_open_hboxft()|Pp_vboxn->Format.pp_open_vboxftn|Pp_hvboxn->Format.pp_open_hvboxftn|Pp_hovboxn->Format.pp_open_hovboxftninletrecpp_cmd=letopenFormatinfunction|Ppcmd_empty->()|Ppcmd_gluesl->List.iterpp_cmdsl|Ppcmd_stringstr->letn=utf8_lengthstrinpp_print_asftnstr|Ppcmd_box(bty,ss)->cpp_open_boxbty;ifnot(over_max_boxes())thenpp_cmdss;pp_close_boxft()|Ppcmd_print_break(m,n)->pp_print_breakftmn|Ppcmd_force_newline->pp_force_newlineft()|Ppcmd_commentcoms->List.iter(pr_comft)coms|Ppcmd_tag(tag,s)->pp_open_stagft(String_tagtag);pp_cmds;pp_close_stagft()inpp_cmdpp(* If mixing some output and a goal display, please use msg_warning,
so that interfaces (proofgeneral for example) can easily dispatch
them to different windows. *)(** Output to a string formatter *)letstring_of_ppcmdsc=Format.fprintfFormat.str_formatter"@[%a@]"pp_withc;Format.flush_str_formatter()(* Copy paste from Util *)letpr_comma()=str","++spc()letpr_semicolon()=str";"++spc()letpr_bar()=str"|"++spc()letpr_spcbar()=str" |"++spc()letpr_argprx=spc()++prxletpr_non_empty_argprx=letpp=prxinifismtppthenmt()elsespc()++prxletpr_optpr=functionNone->mt()|Somex->pr_argprxletpr_opt_no_spcpr=functionNone->mt()|Somex->prxletpr_opt_defaultprdfpr=functionNone->prdf()|Somex->pr_argprxletpr_opt_no_spc_defaultprdfpr=functionNone->prdf()|Somex->prx(** TODO: merge with CString.ordinal *)letpr_nthn=lets=if(n/10)mod10=1then"th"elsematchnmod10with|1->"st"|2->"nd"|3->"rd"|_->"th"inintn++strs(* [prlist pr [a ; ... ; c]] outputs [pr a ++ ... ++ pr c] *)letprlistprl=Ppcmd_glue(List.mapprl)(* unlike all other functions below, [prlist] works lazily.
if a strict behavior is needed, use [prlist_strict] instead.
evaluation is done from left to right. *)letprlist_sep_lastsepno_emptysep_thunklastsep_thunkeleml=letsep=sep_thunk()inletlastsep=lastsep_thunk()inletelems=List.mapelemlinletfiltered_elems=ifno_emptythenList.filter(fune->not(ismte))elemselseelemsinletrecinsert_sepses=matcheswith|[]->mt()|[e]->e|h::[e]->h++lastsep++e|h::t->h++sep++insert_sepstininsert_sepsfiltered_elemsletprlist_strictprl=prlist_sep_lastseptruemtmtprl(* [prlist_with_sep sep pr [a ; ... ; c]] outputs
[pr a ++ sep() ++ ... ++ sep() ++ pr c] *)letprlist_with_sepsepprl=prlist_sep_lastsepfalsesepsepprl(* Print sequence of objects separated by space (unless an element is empty) *)letpr_sequenceprl=prlist_sep_lastseptruespcspcprl(* [pr_enum pr [a ; b ; ... ; c]] outputs
[pr a ++ str "," ++ pr b ++ str "," ++ ... ++ str "and" ++ pr c] *)letpr_enumprl=prlist_sep_lastseptruepr_comma(fun()->str" and"++spc())prlletpr_choiceprl=prlist_sep_lastseptruepr_comma(fun()->str" or"++spc())prlletpr_vertical_listpr=function|[]->str"none"++fnl()|l->fnl()++str" "++hov0(prlist_with_sepfnlprl)++fnl()(* [prvecti_with_sep sep pr [|a0 ; ... ; an|]] outputs
[pr 0 a0 ++ sep() ++ ... ++ sep() ++ pr n an] *)letprvecti_with_sepsepelemv=letv=CArray.mapi(funix->letpp=ifi=0thenmt()elsesep()inpp++elemix)vinseq(Array.to_listv)(* [prvecti pr [|a0 ; ... ; an|]] outputs [pr 0 a0 ++ ... ++ pr n an] *)letprvectielemv=prvecti_with_sepmtelemv(* [prvect_with_sep sep pr [|a ; ... ; c|]] outputs
[pr a ++ sep() ++ ... ++ sep() ++ pr c] *)letprvect_with_sepsepelemv=prvecti_with_sepsep(fun_->elem)v(* [prvect pr [|a ; ... ; c|]] outputs [pr a ++ ... ++ pr c] *)letprvectelemv=prvect_with_sepmtelemvletsurroundp=hov1(str"("++p++str")")(*** DEBUG code ***)letdb_print_ppfmtpp=letopenFormatinletblock_typefmtbtype=let(bt,v)=matchbtypewith|Pp_hbox->("Pp_hbox",None)|Pp_vboxv->("Pp_vbox",Somev)|Pp_hvboxv->("Pp_hvbox",Somev)|Pp_hovboxv->("Pp_hovbox",Somev)inmatchvwith|None->fprintffmt"%s"bt|Somev->fprintffmt"%s %d"btvinletrecdb_print_pp_rindentpp=letind()=fprintffmt"%s"(String.make(2*indent)' ')inind();matchppwith|Ppcmd_empty->fprintffmt"Ppcmd_empty@;"|Ppcmd_stringstr->fprintffmt"Ppcmd_string '%s'@;"str|Ppcmd_gluelist->fprintffmt"Ppcmd_glue@;";List.iter(funx->db_print_pp_r(indent+1)(reprx))list;|Ppcmd_box(block,pp)->fprintffmt"Ppcmd_box %a@;"block_typeblock;db_print_pp_r(indent+1)(reprpp);|Ppcmd_tag(tag,pp)->fprintffmt"Ppcmd_tag %s@;"tag;db_print_pp_r(indent+1)(reprpp);|Ppcmd_print_break(i,j)->fprintffmt"Ppcmd_print_break %d %d@;"ij|Ppcmd_force_newline->fprintffmt"Ppcmd_force_newline@;"|Ppcmd_commentlist->fprintffmt"Ppcmd_comment@;";List.iter(funx->ind();(fprintffmt"%s@;"x))listinpp_open_vboxfmt0;db_print_pp_r0pp;pp_close_boxfmt();pp_print_flushfmt()letdb_string_of_pppp=Format.asprintf"%a"db_print_ppppletrecflattenpp=matchppwith|Ppcmd_gluel->Ppcmd_glue(List.concat(List.map(funx->letx=flattenxinmatchxwith|Ppcmd_gluel2->l2|p->[p])l))|Ppcmd_box(block,pp)->Ppcmd_box(block,flattenpp)|Ppcmd_tag(tag,pp)->Ppcmd_tag(tag,flattenpp)|p->p