123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519(*********************************************************************************)(* Stog *)(* *)(* Copyright (C) 2012-2015 INRIA All rights reserved. *)(* Author: Maxence Guesdon, INRIA Saclay *)(* *)(* This program is free software; you can redistribute it and/or modify *)(* it under the terms of the GNU General Public License as *)(* published by the Free Software Foundation, version 3 of the License. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU General Public License for more details. *)(* *)(* You should have received a copy of the GNU General Public *)(* License along with this program; if not, write to the Free Software *)(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *)(* 02111-1307 USA *)(* *)(* As a special exception, you have permission to link this program *)(* with the OCaml compiler and distribute executables, as long as you *)(* follow the requirements of the GNU GPL in regard to all of the *)(* software in the executable aside from the OCaml compiler. *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(*********************************************************************************)(** *)openStog_base.Ocaml_types;;moduleXR=Xtmpl.RewritemoduleXml=Xtmpl.Xmltypeerr={line:int;start:int;stop:int;message:string;warning:bool}letprompt="# ";;letlength_prompt=String.lengthprompt;;letstog_ocaml_session=ref"stog-ocaml-session";;typesession={session_out:out_channel;session_in:in_channel;}moduleSmap=Types.Str_map;;letsessions=refSmap.empty;;letclose_sessions()=letfnamet=close_outt.session_out;close_int.session_in;Log.info(funm->m"Closing OCaml session %S"name);tryignore(Unix.close_process(t.session_in,t.session_out))withUnix.Unix_error(e,s1,s2)->Log.warn(funm->m"Closing OCaml session %S: %s %s %s"name(Unix.error_messagee)s1s2)inSmap.iterf!sessions;sessions:=Smap.empty;;letin_dirdirf=letold_cwd=Sys.getcwd()inSys.chdirdir;letx=f()inSys.chdirold_cwd;xletcreate_session()=trylet(ic,oc)=Unix.open_process!stog_ocaml_sessionin{session_out=oc;session_in=ic}withUnix.Unix_error(e,s1,s2)->failwith(Printf.sprintf"%s: %s %s"(Unix.error_messagee)s1s2);;letget_session?directoryname=trySmap.findname!sessionswithNot_found->Log.info(funm->m"Opening OCaml session %S%s"name(matchdirectorywithNone->""|Somes->" in "^s));lett=matchdirectorywithNone->create_session()|Somedir->in_dirdircreate_sessioninsessions:=Smap.addnamet!sessions;t;;leteval_ocaml_phrase?(session_name="default")?directoryphrase=letsession=get_session?directorysession_nameinStog_base.Ocaml_types.write_inputsession.session_out{in_phrase=phrase};Stog_base.Ocaml_types.read_resultsession.session_in;;letocaml_phrases_of_strings=lets=Stog_base.Misc.strip_stringsinletlen=String.lengthsinlets=iflen<2||String.subs(len-2)2<>";;"thens^";;"elsesinletacc=ref[]inletlast_start=ref0inletlen=String.lengthsinfori=0tolen-2doifs.[i]=';'&&s.[i+1]=';'thenbeginacc:=(String.subs!last_start(i+2-!last_start))::!acc;last_start:=i+2enddone;List.rev_mapStog_base.Misc.strip_string!acc;;(*
let fun_new_env env args subs =
let old_env = ! Toploop.toplevel_env in
let restore_env subs =
Toploop.toplevel_env := old_env ;
subs
in
let xml =
List.flatten (List.map (Xtmpl.eval_xml env) subs)
in
restore_env xml
;;
*)letconcat_code=letfb=functionXR.Dcode->Buffer.add_stringbcode.Xml.text|xml->failwith(Printf.sprintf"XML code in OCaml code: %s"(XR.to_string[xml]))infunxmls->letb=Buffer.create256inList.iter(fb)xmls;Buffer.contentsb;;letcut_errors=letre=Str.regexp"^Line \\([0-9]+\\), characters \\([0-9]+\\)\\(-[0-9]+\\)?:\n"infuns->letlen=String.lengthsinletnextp=trySome(Str.search_forwardresp)withNot_found->Noneinletrecfaccp=matchnextpwithNone->List.revacc|Somep2->letline_len=String.length(Str.matched_strings)inletline=int_of_string(Str.matched_group1s)inletstart=int_of_string(Str.matched_group2s)inletstop=try-(int_of_string(Str.matched_group3s))with_->startinletmessage=matchnext(p2+1)withNone->String.subs(p2+line_len)(len-(p2+line_len))|Somep3->String.subs(p2+line_len)(p3-(p2+line_len))inleterr={line;start;stop;message;warning=false}inletacc=err::accinfacc(p2+1)inmatchnext0withNone->(s,[])|Somep->(String.subs0p,f[]0);;letget_errors?(print_locs=false)s=let(before_errors,errors)=cut_errorssinletre_noerrline=Str.regexp"^[^ \t][^ \t][^ \t][^ \t][^ \t]"inletferr=letlen=String.lengtherr.messageiniflen<7then(* "Error: " or "Warning" has length 7 *)errelsematchString.suberr.message07with|"Warning"->leterr={errwithwarning=true}inbegin(* keep message until end of line *)matchtrySome(String.indexerr.message'\n')with_->NonewithNone->err|Somep->letmessage=String.suberr.message0pin{errwithmessage}end|"Error: "->begin(* find the first line not beginning with 5 spaces *)matchtrySome(Str.search_forwardre_noerrlineerr.message1)with_->NonewithNone->err|Somep->letmessage=String.suberr.message0pin{errwithmessage}end|_->errinletdetails=List.mapferrorsinletf=ifprint_locsthen(fune->Printf.sprintf"Line %d, characters %d-%d:\n%s"e.linee.starte.stope.message)else(fune->e.message)inleterr_output=String.concat""(List.mapferrors)in(before_errors^err_output,details);;letadd_loc_blockserrorscode=letblockerrs=letcl=iferr.warningthen"warning-loc"else"error-loc"inXR.node("","span")~atts:(XR.atts_of_list[("","title"),[XR.cdataerr.message];("","class"),[XR.cdatacl];])[XR.cdatas]inletrecferr(l,c)=function""->((l,c),[])|s->ifl>err.linethen((l,c),[XR.cdatas])elseifl=err.linethenifc>err.stopthen((l,c),[XR.cdatas])elsebeginletlen=String.lengthsinifc>=err.startthen(letrequired_size=err.stop-ciniflen<=required_sizethen((l,c+len),[blockerrs])else(lets1=String.subs0required_sizeinlets2=String.subsrequired_size(len-required_size)in((l,c+len),[blockerrs1;XR.cdatas2])))elseifc+len<err.startthen((l,c+len),[XR.cdatas])elseifc+len<err.stopthen(lets1=String.subs0(err.start-c)inlets2=String.subs(err.start-c)(len-(err.start-c))in((l,c+len),[XR.cdatas1;blockerrs2]))else(lets1=String.subs0(err.start-c)inlets2=String.subs(err.start-c)(err.stop-err.start)inlets3=String.subs(err.stop-c)(len-(err.stop-c))inletc=c+lenin((l,c+len),[XR.cdatas1;blockerrs2;XR.cdatas3]))endelse((* l < err.line *)letlines=Stog_base.Misc.split_string~keep_empty:trues['\n']inletnb_lines=List.lengthlinesin(*prerr_endline (Printf.sprintf "line=%d; err.line=%d, nb_lines=%d, s=%s" l err.line nb_lines s);*)ifl+nb_lines-1<err.linethen((l+nb_lines-1,String.length(List.hd(List.revlines))),[XR.cdatas])elseletreciter(l,c)=function[]->assertfalse|line::q->ifl=err.linethenferr(l,c)(String.concat"\n"(line::q))else(let(acc,l)=iter(l+1,0)qin(acc,(XR.cdata(line^"\n"))::l))initer(l,c)lines)inletrecfold_cdatafacc=function[]->(acc,[])|(XR.Ds)::q->let(acc,l)=faccs.Xml.textinlet(acc,l2)=fold_cdatafaccqin(acc,l@l2)|(XR.Enode)::q->let(acc,subs)=fold_cdatafaccnode.XR.subsinlet(acc,l)=fold_cdatafaccqin(acc,(XR.E{nodewithXR.subs})::l)|(XR.C_)::q|(XR.PI_)::q->fold_cdatafaccqinletf_errxmlserr=snd(fold_cdata(ferr)(1,0)xmls)inleterrors=List.sortStdlib.compareerrorsinList.fold_leftf_errcodeerrors;;lethighlight_warnings_and_errors?print_locsoutputcode=let(stderr,errors)=get_errors?print_locsoutput.stderrin({outputwithstderr},add_loc_blockserrorscode);;letconcat_nlx=function[]->[x]|l->x::(XR.cdata"\n")::lletlist_concat_nlx=function[]->x|l->matchxwith[]->l|_->x@((XR.cdata"\n")::l)letremove_ending_nls=letlen=String.lengthsiniflen>0&&String.gets(len-1)='\n'thenString.subs0(len-1)elsesletconcat_toplevel_outputsoutput=letmkacc(cl,s)=matchswith""->acc|_->letatts=XR.atts_one("","class")[XR.cdatacl]inletxml=XR.node("","span")~atts[XR.cdatas]inxml::accinletl=List.fold_leftmk[]["stderr",output.stderr;"stdout",output.stdout;"toplevel-out",remove_ending_nloutput.topout;]inList.revl;;letfun_evalstogenv?locargscode=tryletdirectory=matchXR.get_att_cdataargs("","directory")withNone|Some""->None|x->xinletexc=XR.opt_att_cdataargs~def:"true"("","error-exc")="true"inlettoplevel=XR.opt_att_cdataargs~def:"false"("","toplevel")="true"inletshow_code=XR.opt_att_cdataargs~def:"true"("","show-code")<>"false"inletshow_stdout=XR.opt_att_cdataargs~def:(iftoplevelthen"true"else"false")("","show-stdout")<>"false"inlethighlight_locs=XR.opt_att_cdataargs~def:"true"("","highlight-locs")<>"false"inletprint_locs=XR.opt_att_cdataargs~def:(ifhighlight_locsthen"false"else"true")("","print-locs")<>"false"inletin_xml_block=XR.opt_att_cdataargs~def:"true"("","in-xml-block")<>"false"inletsession_name=XR.get_att_cdataargs("","session")inletid_opt=XR.opt_att_cdataargs("","id")inletatts=XR.atts_of_list(matchid_optwith""->[]|id->[("","id"),[XR.cdataid]])inletcode=concat_codecodeinletphrases=ocaml_phrases_of_stringcodeinletreciteracc=function[]->List.revacc|phrase::q->letlang_file=letd=stog.Types.stog_dirinFilename.concatd"ocaml.lang"inletopts=ifSys.file_existslang_filethenSome(Printf.sprintf"--config-file=%s"lang_file)elseNoneinletcode=ifshow_codethenHighlight.highlight~lang:"ocaml"?optsphraseelse[]in(*prerr_endline (Printf.sprintf "evaluate %S" phrase);*)let(output,raised_exc)=matcheval_ocaml_phrase?session_name?directoryphrasewithStog_base.Ocaml_types.Okoutput->(output,false)|Handled_erroroutput->(output,true)|Excs->({stderr=s;stdout="";topout=""},true)inifraised_exc&&excthenbeginletmsg=Xtmpl.Xml.loc_sprintfloc"OCaml error with code:\n%s\n%s"phraseoutput.stderrinfailwithmsgend;letacc=matchtoplevelwithfalse->letcode=matchcodewith[]->[]|_->ifin_xml_blockthen[XR.node("","span")code]elsecodeinifshow_stdoutthenmatchoutput.stdoutwith""->list_concat_nlcodeacc|_->letxml=ifin_xml_blockthenXR.node("","span")~atts:(XR.atts_one("","class")[XR.cdata"ocaml-toplevel"])[XR.cdataoutput.stdout]elseXR.cdataoutput.stdoutinlist_concat_nl(concat_nlxmlcode)accelselist_concat_nlcodeacc|true->let(output,code)=ifhighlight_locsthenhighlight_warnings_and_errors~print_locsoutputcodeelse(output,code)inletcode=ifin_xml_blockthen[XR.node("","span")((XR.cdataprompt)::code)]elsecodeinletclasses=Printf.sprintf"ocaml-toplevel%s"(ifraised_excthen" ocaml-exc"else"")inmatchconcat_toplevel_outputsoutputwith[]->list_concat_nlcodeacc|outputs->letxml=XR.node("","span")~atts:(XR.atts_one("","class")[XR.cdataclasses])outputsinlist_concat_nl(concat_nlxmlcode)acciniteraccqinletxml=iter[]phrasesinifshow_code||toplevel||show_stdoutthenletxml=ifin_xml_blockthen[XR.node("","pre")~atts:(XR.atts_of_list~atts[("","class"),[XR.cdata"code-ocaml"]])xml]elsexmlin(stog,xml)else(stog,[XR.cdata""])withe->raisee;;letfun_printfstogenv?locargssubs=letcode=concat_codesubsinletformat=XR.opt_att_cdataargs~def:"%s"("","format")inletcode="Printf.printf \""^format^"\" "^code^"; flush Stdlib.stdout;;"inletargs=XR.atts_of_list~atts:args[("","show-stdout"),[XR.cdata"true"];("","show-code"),[XR.cdata"false"];("","in-xml-block"),[XR.cdata"false"];]infun_evalstogenvargs[XR.cdatacode];;