Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sertop_sexp.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)(* <O___,, * (see CREDITS file for the list of authors) *)(* \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) *)(************************************************************************)(************************************************************************)(* Coq serialization API/Plugin *)(* Copyright 2016-2018 MINES ParisTech -- Dual License LGPL 2.1 / GPL3+ *)(* Written by: Emilio J. Gallego Arias *)(************************************************************************)(* Status: Very Experimental *)(************************************************************************)openSexplibopenSexplib.ConvmoduleSP=Serapi.Serapi_protocol(******************************************************************************)(* Global Protocol Options *)(******************************************************************************)typeser_opts={in_chan:in_channel(* Input/Output channels *);out_chan:out_channel(* Printers *);printer:Sertop_ser.ser_printer;debug:bool;allow_sprop:bool;indices_matter:bool;print0:bool;lheader:bool(* Print lenght header (deprecated) *)(* Coq options *);no_init:bool(* Whether to create the initial document *);no_prelude:bool(* Whether to load stdlib's prelude *);topfile:stringoption(* Top name is derived from topfile name *);ml_path:stringlist;vo_path:Loadpath.vo_pathlist(** From -R and -Q options usually *);async:Sertop_init.async_flags}(******************************************************************************)(* Input/Output *)(******************************************************************************)(* *)(* Until this point, we've been independent of a particular format or *)(* or serialization, with all the operations defined at the symbolic level. *)(* *)(* It is now time to unfortunately abandon our fairy-tale and face the real, *)(* ugly world in these last 40 lines! *)(* *)(******************************************************************************)typesertop_cmd=|SerApiofSertop_ser.tagged_cmd(** Regular *)|Forkof{fifo_in:string;fifo_out:string}(** Fork SerAPI to a new process, useful for people doing search
[but heavy], the forked process will create and use the provided
FIFO's for input / output *)|Quit(** Exit sertop *)[@@derivingsexp]letis_cmd_quitcmd=matchcmdwith|Quit->true|_->false(* Loop state *)moduleCtx=structtypet={in_chan:Stdlib.in_channel;out_chan:Stdlib.out_channel;out_fmt:Format.formatter;cmd_id:int}letmake~cmd_id~in_chan~out_chan=letout_fmt=Format.formatter_of_out_channelout_chanin{out_chan;out_fmt;in_chan;cmd_id}end(* XXX: Improve by using manual tag parsing. *)letread_cmd~(ctx:Ctx.t)~pp_err=letrecread_loop()=tryletcmd_sexp=Sexp.input_sexpctx.in_chaninbegintrysertop_cmd_of_sexpcmd_sexpwith|_exn->begintrySerApi(Sertop_ser.tagged_cmd_of_sexpcmd_sexp)with|_exn->SerApi(string_of_intctx.cmd_id,Sertop_ser.cmd_of_sexpcmd_sexp)endendwith|End_of_file->Quit|exn->pp_errctx.out_fmt(sexp_of_exnexn);(read_loop[@ocaml.tailcall])()inread_loop()letout_sexpopts=letopenFormatinletpp_sexp=Sertop_ser.select_printeropts.printerinletpp_term=ifopts.print0thenfunfmt()->fprintffmt"%c"(Char.chr0)elsefunfmt()->fprintffmt"@\n"inifopts.lheaderthenfunfmta->fprintfstr_formatter"@[%a@]%a%!"pp_sexpapp_term();letout=flush_str_formatter()infprintffmt"@[byte-length: %d@\n%s@]%!"(String.lengthout)outelsefunfmta->fprintffmt"@[%a@]%a%!"pp_sexpapp_term()(** We could use Sexp.to_string too *)letout_answeropts=letpp_sexp=out_sexpoptsinfunfmta->pp_sexpfmt(Sertop_ser.sexp_of_answera)(** Set the topname from optional topfile string or default if None **)letdoc_typetopfile=matchtopfilewith|None->letsertop_dp=Names.(DirPath.make[Id.of_string"SerTop"])inStm.Interactive(TopLogicalsertop_dp)|Somefilename->Stm.Interactive(Stm.TopPhysicalfilename)letprocess_serloop_cmd~(ctx:Ctx.t)~pp_ack~pp_answer~pp_err~pp_feed(cmd:sertop_cmd):Ctx.t=letout=ctx.out_fmtin(* Collect terminated children *)let()=trylet_pid,_status=Unix.waitpid[Unix.WNOHANG](-1)in()withUnix.Unix_error(Unix.ECHILD,_,_)->(* No children for now *)()inmatchcmdwith|SerApi(cmd_tag,cmd)->pp_ackoutcmd_tag;List.iter(pp_answerout)@@List.map(funa->SP.Answer(cmd_tag,a))(SP.exec_cmdcmd);ctx|Fork{fifo_in;fifo_out}->letpid=Unix.fork()inifpid=0thenbegin(* Children: close previous channels *)Stdlib.close_inctx.in_chan;Format.pp_print_flushctx.out_fmt();Stdlib.close_outctx.out_chan;(* Create new ones *)let()=Unix.mkfifofifo_in0o640inletin_chan=Stdlib.open_infifo_ininlet()=Unix.mkfifofifo_out0o640inletout_chan=Stdlib.open_outfifo_outinletout_fmt=Format.formatter_of_out_channelout_chaninSertop_init.update_fb_handler~pp_feedout_fmt;{ctxwithin_chan;out_chan;out_fmt}endelse(* Parent *)let()=pp_erroutSexp.(List[Atom"Forked";Atom(string_of_intpid)])inctx|Quit->ctxletser_loopser_opts=(* Create closures for printers given initial options *)letpp_answer=out_answerser_optsinletpp_err=out_sexpser_optsin(* XXX EG: I don't understand this well, why is this lock needed ??
Review fork code in CoqworkmgrApi *)letpr_mutex=Mutex.create()inletser_lockfx=Mutex.lockpr_mutex;fx;Mutex.unlockpr_mutexin(* Wrap printers *)letpp_answerout=ser_lock(pp_answerout)inletpp_errout=ser_lock(pp_errout)inletpp_ackoutcid=pp_answerout(SP.Answer(cid,SP.Ack))inletpp_optfb=Sertop_util.feedback_opt_filterfbinletpp_feedoutfb=Option.iter(funfb->pp_answerout(SP.Feedback(Sertop_util.feedback_trfb)))(pp_optfb)inletctx=Ctx.make~cmd_id:0~in_chan:ser_opts.in_chan~out_chan:ser_opts.out_chanin(* Init Coq *)let()=Sertop_init.(coq_init{fb_handler=pp_feed;ml_load=None;debug=ser_opts.debug;allow_sprop=ser_opts.allow_sprop;indices_matter=ser_opts.indices_matter})ctx.out_fmtin(* Follow the same approach than coqtop for now: allow Coq to be
* interrupted by Ctrl-C. Not entirely safe or race free... but we
* trust the IDEs to send the signal on coherent IO state.
*)Sys.catch_breaktrue;letinjections=ifser_opts.no_preludethen[]else[Stm.RequireInjection("Coq.Init.Prelude",None,Somefalse)]inletml_load_path,vo_load_path=ser_opts.ml_path,ser_opts.vo_pathinletstm_options=Sertop_init.process_stm_flagsser_opts.asyncinifnotser_opts.no_initthenbeginletndoc={Stm.doc_type=doc_typeser_opts.topfile;injections;ml_load_path;vo_load_path;stm_options}inlet_=Stm.new_docndocin()end;letincr_cmdid(ctx:Ctx.t)={ctxwithcmd_id=ctx.cmd_id+1}in(* Main loop *)letrecloopctx=letquit,ctx=tryletscmd=read_cmd~ctx~pp_errin(is_cmd_quitscmd,process_serloop_cmd~ctx~pp_ack~pp_answer~pp_err~pp_feedscmd)withSys.Break->false,ctxinifquitthen()else(loop[@ocaml.tailcall])(incr_cmdidctx)inloopctx