123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119(*
* Copyright (c) 2018 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)letsrc=Logs.Src.create"ocaml-mdx"moduleLog=(valLogs.src_logsrc:Logs.LOG)openAstringopenMisctypet={vpad:int;hpad:int;pos:Lexing.position;command:stringlist;output:Output.tlist;}letdump_lineppf=function|#Output.taso->Output.dumpppfo|`Command(c,_)->Fmt.pfppf"`Command %a"Fmt.(Dump.listdump_string)cletdump_lines=Fmt.(Dump.listdump_line)letdumpppf{vpad;hpad;command;output;_}=Fmt.pfppf"@[{vpad=%d;@ hpad=%d;@ command=%a;@ output=%a}@]"vpadhpadFmt.(Dump.listdump_string)commandFmt.(Dump.listOutput.dump)outputletpp_vpadppft=letrecaux=function|0->()|i->Fmt.pfppf"\n";aux(i-1)inauxt.vpadletpp_commandppf(t:t)=matcht.commandwith|[]->()|l->pp_vpadppft;List.iteri(funis->ifi=0thenFmt.pfppf"%a# %s\n"pp_padt.hpadselsematchswith|""->Fmt.stringppf"\n"|_->Fmt.pfppf"%a %s\n"pp_padt.hpads)lletppppf(t:t)=pp_commandppft;pp_lines(Output.pp~pad:t.vpad)ppft.outputletlexbuf~(pos:Lexing.position)s=letlexbuf=Lexing.from_stringsinlexbuf.lex_start_p<-pos;lexbuf.lex_curr_p<-pos;lexbufletvpad_of_linest=letrecauxi=function|`Outputh::twhenString.trimh=""->aux(i+1)t|t->(i,t)inaux0tletof_lines~syntax~(loc:Location.t)t=letpos=loc.loc_startinlethpad=matchsyntaxwithSyntax.Mli->pos.pos_cnum+2|_->hpad_of_linestinletunpadline=matchsyntaxwith|Syntax.Mli->String.trimline|Syntax.Normal|Syntax.Cram->ifString.is_emptylinethenlineelseifString.lengthline<hpadthenFmt.failwith"invalid padding: %S"lineelseString.with_index_rangeline~first:hpadinletlines=List.mapunpadtinletlines=matchsyntaxwithSyntax.Mli->""::lines|_->linesinletlines=String.concat~sep:"\n"linesinletlines=Lexer_top.token(lexbuf~poslines)inletvpad,lines=vpad_of_lineslinesinLog.debug(funl->l"Toplevel.of_lines (vpad=%d, hpad=%d) %a"vpadhpaddump_lineslines);letmkvpad(command,(loc:Location.t))output={vpad;hpad;pos=loc.loc_start;command;output=List.revoutput}inletrecauxvpadcommandoutputacc=function|[]->List.rev(mkvpadcommandoutput::acc)|(`Ellipsisaso)::t->auxvpadcommand(o::output)acct|(`Output_aso)::t->auxvpadcommand(o::output)acct|`Commandcmd::t->letvpad',output=vpad_of_linesoutputinauxvpad'cmd[](mkvpadcommandoutput::acc)tinmatchlineswith|`Commandcmd::t->auxvpadcmd[][]t|_->Fmt.failwith"invalid toplevel block: %a"Fmt.(Dump.liststring)t