Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file block.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482(*
* 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.
*)openResultopenCompatopenUtil.Result.InfixmoduleHeader=structtypet=Shellof[`Sh|`Bash]|OCaml|Otherofstringletppppf=function|Shell`Sh->Fmt.stringppf"sh"|Shell`Bash->Fmt.stringppf"bash"|OCaml->Fmt.stringppf"ocaml"|Others->Fmt.stringppfsletof_string=function|""->None|"sh"->Some(Shell`Sh)|"bash"->Some(Shell`Bash)|"ocaml"->SomeOCaml|s->Some(Others)letinfer_from_filefile=matchFilename.(remove_extension(basenamefile),extensionfile)with|("dune"|"dune-project"),_->Some(Other"scheme")|_,(".ml"|".mli"|".mlt"|".eliom"|".eliomi")->SomeOCaml|_,".sh"->Some(Shell`Sh)|_->Noneendtypesection=int*stringtypecram_value={language:[`Sh|`Bash];non_det:Label.non_detoption}typeocaml_value={env:Ocaml_env.t;non_det:Label.non_detoption;errors:Output.tlist;}typetoplevel_value={env:Ocaml_env.t;non_det:Label.non_detoption}typeinclude_ocaml_file={part_included:stringoption}typeinclude_other_file={header:Header.toption}typeinclude_file_kind=|Fk_ocamlofinclude_ocaml_file|Fk_otherofinclude_other_filetypeinclude_value={file_included:string;file_kind:include_file_kind}typeraw_value={header:Header.toption}typevalue=|Rawofraw_value|OCamlofocaml_value|Cramofcram_value|Topleveloftoplevel_value|Includeofinclude_valuetypet={loc:Location.t;section:sectionoption;dir:stringoption;source_trees:stringlist;required_packages:stringlist;labels:Label.tlist;legacy_labels:bool;contents:stringlist;skip:bool;version_enabled:bool;set_variables:(string*string)list;unset_variables:stringlist;value:value;}letdump_stringppfs=Fmt.pfppf"%S"sletdump_section=Fmt.(Dump.pairintstring)letheadert=matcht.valuewith|Rawb->b.header|OCaml_->SomeHeader.OCaml|Cram{language;_}->Some(Header.Shelllanguage)|Toplevel_->SomeHeader.OCaml|Include{file_kind=Fk_ocaml_;_}->SomeHeader.OCaml|Include{file_kind=Fk_otherb;_}->b.headerletdump_valueppf=function|Raw_->Fmt.stringppf"Raw"|OCaml_->Fmt.stringppf"OCaml"|Cram_->Fmt.stringppf"Cram"|Toplevel_->Fmt.stringppf"Toplevel"|Include_->Fmt.stringppf"Include"letdumpppf({loc;section;labels;contents;value;_}asb)=Fmt.pfppf"{@[loc: %a;@ section: %a;@ labels: %a;@ header: %a;@ contents: %a;@ \
value: %a@]}"Stable_printer.Location.print_loclocFmt.(Dump.optiondump_section)sectionFmt.Dump.(listLabel.pp)labelsFmt.(Dump.optionHeader.pp)(headerb)Fmt.(Dump.listdump_string)contentsdump_valuevalueletpp_linessyntaxt=letpp=matchsyntaxwith|SomeSyntax.Cram->Fmt.fmt" %s"|SomeSyntax.Mli->funppf->Fmt.fmt"%*s%s"ppf(t.loc.loc_start.pos_cnum+2)""|_->Fmt.stringinFmt.(list~sep:(unit"\n")pp)letlstripstring=lethpad=Misc.hpad_of_lines[string]inAstring.String.with_index_rangestring~first:hpadletpp_contents?syntaxppft=match(syntax,t.contents)with|SomeSyntax.Mli,[_]->Fmt.pfppf"%s"(String.concat"\n"t.contents)|SomeSyntax.Mli,_->Fmt.pfppf"\n%a"(pp_linessyntaxt)(List.maplstript.contents)|(SomeCram|SomeNormal|None),[]->()|(SomeCram|SomeNormal|None),_->Fmt.pfppf"%a\n"(pp_linessyntaxt)t.contentsletpp_errorsppft=matcht.valuewith|OCaml{errors;_}whenList.lengtherrors>0->Fmt.stringppf"```mdx-error\n";Fmt.pfppf"%a"Fmt.(list~sep:nopOutput.pp)errors;Fmt.stringppf"```\n"|_->()letpp_footer?syntaxppft=matchsyntaxwith|SomeSyntax.Mli->ifList.lengtht.contents=1thenFmt.pfppf""elseFmt.pfppf"\n"|SomeSyntax.Cram->()|_->Fmt.stringppf"```\n"letpp_legacy_labelsppf=function|[]->()|l->Fmt.pfppf" %a"Fmt.(list~sep:(unit",")Label.pp)lletpp_labelsppf=function|[]->()|l->Fmt.pfppf"<!-- $MDX %a -->\n"Fmt.(list~sep:(unit",")Label.pp)lletpp_header?syntaxppft=matchsyntaxwith|SomeSyntax.Cram->(matcht.labelswith|[]->()|[Non_detNone]->Fmt.pfppf"<-- non-deterministic\n"|[Non_det(SomeNd_output)]->Fmt.pfppf"<-- non-deterministic output\n"|[Non_det(SomeNd_command)]->Fmt.pfppf"<-- non-deterministic command\n"|_->failwith"cannot happen: checked during parsing")|SomeSyntax.Mli->()|_->ift.legacy_labelsthenFmt.pfppf"```%a%a\n"Fmt.(optionHeader.pp)(headert)pp_legacy_labelst.labelselseFmt.pfppf"%a```%a\n"pp_labelst.labelsFmt.(optionHeader.pp)(headert)letpp?syntaxppfb=pp_header?syntaxppfb;pp_contents?syntaxppfb;pp_footer?syntaxppfb;pp_errorsppfbletdirectoryt=t.dirletfilet=matcht.valuewithIncludet->Somet.file_included|_->Noneletsource_treest=t.source_treesletnon_dett=matcht.valuewith|OCamlb->b.non_det|Cramb->b.non_det|Toplevelb->b.non_det|Include_|Raw_->Noneletskipt=t.skipletset_variablest=t.set_variablesletunset_variablest=t.unset_variablesletexplicit_required_packagest=t.required_packagesletrequire_re=letopenReinseq[str"#require \"";group(rep1any);str"\""]letrequire_from_lineline=letopenUtil.Result.Infixinletre=Re.compilerequire_reinmatchRe.exec_optrelinewith|None->OkLibrary.Set.empty|Somegroup->letmatched=Re.Group.getgroup1inletlibs_str=String.split_on_char','matchedinUtil.Result.List.map~f:Library.from_stringlibs_str>>|funlibs->Library.Set.of_listlibsletrequire_from_lineslines=letopenUtil.Result.InfixinUtil.Result.List.map~f:require_from_linelines>>|funlibs->List.fold_leftLibrary.Set.unionLibrary.Set.emptylibsletrequired_libraries=function|{value=Toplevel_;contents;_}->require_from_linescontents|_->OkLibrary.Set.emptyletvaluet=t.valueletsectiont=t.sectionletguess_ocaml_kindcontents=letrecaux=function|[]->`Code|h::t->leth=String.trimhinifh=""thenauxtelseifString.lengthh>1&&h.[0]='#'then`Toplevelelse`Codeinauxcontentsletends_by_semi_semic=matchList.revcwith|h::_->letlen=String.lengthhinlen>2&&h.[len-1]=';'&&h.[len-2]=';'|_->falseletpp_line_directiveppf(file,line)=Fmt.pfppf"#%d %S"linefileletline_directive=Fmt.to_to_stringpp_line_directiveletexecutable_contents~syntaxb=letcontents=matchb.valuewith|OCaml_->b.contents|Raw_|Cram_|Include_->[]|Toplevel_->letphrases=Toplevel.of_lines~syntax~loc:b.locb.contentsinList.flatten(List.map(fun(t:Toplevel.t)->matcht.commandwith|[]->[]|cs->letmks=String.make(t.hpad+2)' '^sinline_directive(t.pos.pos_fname,t.pos.pos_lnum)::List.mapmkcs)phrases)inifcontents=[]||ends_by_semi_semicontentsthencontentselsecontents@[";;"]letversion_enabledversion=letopenUtil.Result.InfixinOcaml_version.of_stringSys.ocaml_version>>|funcurr_version->matchversionwith|Some(op,v)->Label.Relation.compareop(Ocaml_version.comparecurr_versionv)0|None->trueletget_labelf(labels:Label.tlist)=Util.List.find_mapflabelsletlabel_not_allowed~label~kind=Util.Result.errorf"`%s` label is not allowed for %s blocks."labelkindletlabel_required~label~kind=Util.Result.errorf"`%s` label is required for %s blocks."labelkindletcheck_not_setmsg=function|Some_->Util.Result.errorfmsg|None->Ok()letcheck_no_errors=function|[]->Ok()|_::_->Util.Result.errorf"error block cannot be attached to a non-OCaml block"typeblock_config={non_det:Label.non_detoption;part:stringoption;env:stringoption;dir:stringoption;skip:bool;version:(Label.Relation.t*Ocaml_version.t)option;source_trees:stringlist;required_packages:stringlist;set_variables:(string*string)list;unset_variables:stringlist;file_inc:stringoption;}letget_block_configl={non_det=get_label(function|Non_det(Somex)->Somex|Non_detNone->SomeLabel.default_non_det|_->None)l;part=get_label(functionPartx->Somex|_->None)l;env=get_label(functionEnvx->Somex|_->None)l;dir=get_label(functionDirx->Somex|_->None)l;skip=List.exists(functionLabel.Skip->true|_->false)l;version=get_label(functionVersion(x,y)->Some(x,y)|_->None)l;source_trees=List.filter_map(functionLabel.Source_treex->Somex|_->None)l;required_packages=List.filter_map(functionLabel.Require_packagex->Somex|_->None)l;set_variables=List.filter_map(functionLabel.Set(v,x)->Some(v,x)|_->None)l;unset_variables=List.filter_map(functionLabel.Unsetx->Somex|_->None)l;file_inc=get_label(functionFilex->Somex|_->None)l;}letmk_ocaml~config~contents~errors=letkind="OCaml"inmatchconfigwith|{file_inc=None;part=None;env;non_det;_}->(matchguess_ocaml_kindcontentswith|`Code->Ok(OCaml{env=Ocaml_env.mkenv;non_det;errors})|`Toplevel->Util.Result.errorf"toplevel syntax is not allowed in OCaml blocks.")|{file_inc=Some_;_}->label_not_allowed~label:"file"~kind|{part=Some_;_}->label_not_allowed~label:"part"~kindletmk_cram?language~config~header~errors()=letkind="shell"inmatchconfigwith|{file_inc=None;part=None;env=None;non_det;_}->check_no_errorserrors>>|fun()->letlanguage=Util.Option.valuelanguage~default:(matchheaderwith|Some(Header.Shelllanguage)->language|_->`Sh)inCram{language;non_det}|{file_inc=Some_;_}->label_not_allowed~label:"file"~kind|{part=Some_;_}->label_not_allowed~label:"part"~kind|{env=Some_;_}->label_not_allowed~label:"env"~kindletmk_toplevel~config~contents~errors=letkind="toplevel"inmatchconfigwith|{file_inc=None;part=None;env;non_det;_}->(matchguess_ocaml_kindcontentswith|`Code->Util.Result.errorf"invalid toplevel syntax in toplevel blocks."|`Toplevel->check_no_errorserrors>>|fun()->Toplevel{env=Ocaml_env.mkenv;non_det})|{file_inc=Some_;_}->label_not_allowed~label:"file"~kind|{part=Some_;_}->label_not_allowed~label:"part"~kindletmk_include~config~header~errors=letkind="include"inmatchconfigwith|{file_inc=Somefile_included;part;non_det=None;env=None;_}->(check_no_errorserrors>>=fun()->matchheaderwith|SomeHeader.OCaml->letfile_kind=Fk_ocaml{part_included=part}inOk(Include{file_included;file_kind})|_->(matchpartwith|None->letfile_kind=Fk_other{header}inOk(Include{file_included;file_kind})|Some_->label_not_allowed~label:"part"~kind:"non-OCaml include"))|{file_inc=None;_}->label_required~label:"file"~kind|{non_det=Some_;_}->label_not_allowed~label:"non-deterministic"~kind|{env=Some_;_}->label_not_allowed~label:"env"~kindletinfer_block~config~header~contents~errors=matchconfigwith|{file_inc=Some_;_}->mk_include~config~header~errors|{file_inc=None;part;_}->(matchheaderwith|Some(Header.Shelllanguage)->mk_cram~language~config~header~errors()|SomeHeader.OCaml->(matchguess_ocaml_kindcontentswith|`Code->mk_ocaml~config~contents~errors|`Toplevel->mk_toplevel~config~contents~errors)|_->check_not_set"`part` label requires a `file` label."part>>=fun()->check_no_errorserrors>>|fun()->Raw{header})letmk~loc~section~labels~legacy_labels~header~contents~errors=letblock_kind=get_label(functionBlock_kindx->Somex|_->None)labelsinletconfig=get_block_configlabelsin(matchblock_kindwith|SomeOCaml->mk_ocaml~config~contents~errors|SomeCram->mk_cram~config~header~errors()|SomeToplevel->mk_toplevel~config~contents~errors|SomeInclude->mk_include~config~header~errors|None->infer_block~config~header~contents~errors)>>=funvalue->version_enabledconfig.version>>|funversion_enabled->{loc;section;dir=config.dir;source_trees=config.source_trees;required_packages=config.required_packages;labels;legacy_labels;contents;skip=config.skip;version_enabled;set_variables=config.set_variables;unset_variables=config.unset_variables;value;}letmk_include~loc~section~labels=matchget_label(functionFilex->Somex|_->None)labelswith|Somefile_inc->letheader=Header.infer_from_filefile_incinmk~loc~section~labels~legacy_labels:false~header~contents:[]~errors:[]|None->label_required~label:"file"~kind:"include"letis_active?section:st=letactive=matchswith|Somep->(matcht.sectionwith|Somes->Re.execp(Re.Perl.compile_patp)(snds)|None->Re.execp(Re.Perl.compile_patp)"")|None->trueinactive&&t.version_enabled&¬t.skip