123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604(*********************************************************************************)(* Ojs-base *)(* *)(* Copyright (C) 2014-2021 INRIA. All rights reserved. *)(* *)(* 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 Library 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 *)(* *)(*********************************************************************************)(** *)moduleSMap=Map.Make(String)letlid?(loc=Location.none)s=letb=Lexing.from_stringsinletp=loc.Location.loc_startinletb={bwithLexing.lex_start_p=p;lex_curr_p=p}inLocation.mkloc(Parse.longidentb)locletmkloc=Location.mklocleterrorlocmsg=raise(Location.Error(Location.error~locmsg))letkerrorloc=Printf.ksprintf(errorloc)openPpxlibopenAst_helpermoduleLocation=Ppxlib_ast__Import.LocationmoduleX=Xtmpl.Rewrite(*c==v=[File.string_of_file]=1.1====*)letstring_of_filename=letchanin=open_in_binnameinletlen=1024inlets=Bytes.createleninletbuf=Buffer.createleninletreciter()=tryletn=inputchanins0leninifn=0then()else(Buffer.add_subbytesbufs0n;iter())withEnd_of_file->()initer();close_inchanin;Buffer.contentsbuf(*/c==v=[File.string_of_file]=1.1====*)letfile_pathlocfile=letbase_path=matchloc.Location.loc_start.Lexing.pos_fnamewith|""->Filename.current_dir_name|f->Filename.dirnamefinmatchFilename.is_relativefilewith|true->Filename.concatbase_pathfile|false->fileletread_templatelocfile=tryletstr=string_of_filefileinX.from_stringstrwithSys_errormsg->errorloc(Printf.sprintf"File %S: %s"filemsg)typeinput_kind=|Button|Checkbox|Color|Date|Datetime|Datetime_local|Email|File|Hidden|Image|Month|Number|Password|Radio|Range|Reset|Search|Submit|Tel|Text|Time|Url|Week|Textarea|Selectletinput_kind_of_stringloc=function|"button"->Button|"checkbox"->Checkbox|"color"->Color|"date"->Date|"datetime"->Datetime|"datetime-local"->Datetime_local|"email"->Email|"file"->File|"hidden"->Hidden|"image"->Image|"month"->Month|"number"->Number|"password"->Password|"radio"->Radio|"range"->Range|"reset"->Reset|"search"->Search|"submit"->Submit|"tel"->Tel|"text"->Text|"time"->Time|"url"->Url|"week"->Week|s->kerrorloc"Invalid input type %S"stypeinput={i_name:string;i_kind:input_kind;i_mltype:[`CData|`Otherof(string*string*string)(* typ, to_string, of_string *)];i_value:X.treelistoption;i_mandatory:bool;i_mlname:stringoption;}letatt_s=("",s)letatt_param=att_"param_"letatt_to_xml=att_"to_xml_"letatt_to_string=att_"to_string"letatt_of_string=att_"of_string"letatt_type=att_"type"letatt_mltype=att_"type_"letatt_optional=att_"optional_"letatt_name=att_"name"letatt_mandatory=att_"mand_"letatt_value=att_"value"letatt_mlname=att_"name_"letget_nameatts=X.get_att_cdataattsatt_nameletstring_of_name=function("",s)->s|(p,s)->p^":"^sletto_idi=matchi.i_mlnamewith|Somes->s|None->String.map(function|'a'..'z'asc->c|'0'..'9'asc->c|'A'..'Z'asc->Char.lowercase_asciic|_->'_')i.i_nameletparse_ocaml_expressionlocstr=letlexbuf=Lexing.from_stringstrintryParse.expressionlexbufwithe->errorloc(Printf.sprintf"Error while parsing the following OCaml expression:\n%s\n%s"str(Printexc.to_stringe))letparse_ocaml_typelocstr=letlexbuf=Lexing.from_stringstrintryParse.core_typelexbufwithe->errorloc(Printf.sprintf"Error while parsing the following OCaml type:\n%s\n%s"str(Printexc.to_stringe))(* Check: utiliser de checked quand true, absence de la requete quand faux
Radio: ignorer si deja vu dans les parametres, doit etre decrit par le premier radio dans le xml *)letinput_of_attsloci_name?kindattssubs=leti_kind=matchkindwith|Somek->k|None->matchX.get_att_cdataattsatt_typewith|None->Text|Somes->input_kind_of_stringlocsinleti_mandatory=X.get_att_cdataattsatt_mandatory=Some"true"inleti_value=matchi_kindwithTextarea->Somesubs|_->X.get_attattsatt_valueinletdef_type=matchi_kindwith|Button|Reset|Submit->`CData|Date|Datetime|Datetime_local|Time->`CData|Checkbox->`Other("bool","fun _ -> \"true\"","fun _ -> true")|Email|File|Password|Tel|Text|Search|Url|Hidden->`CData|Color|Image->`CData|Textarea->`CData|Radio->`CData|Select->`CData|Month|Week->`CData|Number|Range->`Other("int","string_of_int","int_of_string")inleti_mltype=matchX.get_att_cdataattsatt_mltypewithNone->def_type|Some"cdata"->`CData|Somestr->matchX.get_att_cdataattsatt_to_string,X.get_att_cdataattsatt_of_stringwith|None,_->kerrorloc"Input %S: Missing attribute %s"i_name(string_of_nameatt_to_string)|_,None->kerrorloc"Input %S: Missing attribute %s"i_name(string_of_nameatt_of_string)|Someto_s,Someof_s->`Other(str,to_s,of_s)inleti_mlname=X.get_att_cdataattsatt_mlnamein{i_name;i_kind;i_mltype;i_value;i_mandatory;i_mlname;}letclear_attsatts=List.fold_rightX.atts_remove[att_mandatory;att_value;att_to_string;att_of_string]attsletmk_value_parami=letvalue_atts=lettype_atts=matchi.i_mltypewith|`CData->[att_mltype,[X.cdata"cdata"]]|`Other(t,to_s,_)->[att_mltype,[X.cdatat];att_to_xml,[X.cdata(Printf.sprintf"fun x__ -> [ Xtmpl.Rewrite.cdata ((%s) x__) ]"to_s)];]inX.atts_of_list((att_param,[X.cdata"true"])::(att_optional,[X.cdata"true"])::type_atts@(matchi.i_mlnamewithNone->[]|Someid->[att_mlname,[X.cdataid]]))inX.node("",i.i_name)~atts:value_atts(matchi.i_valuewithNone->[]|Somel->l)letadd_atts_of_inputiatts=letatts=matchi.i_kindwith|Textarea->atts|Checkbox->X.atts_one~attsatt_value[X.cdata"true"]|_->X.atts_one~attsatt_value[mk_value_parami]inletatts=matchi.i_kindwithCheckbox->X.atts_one~atts("","id")[X.cdatai.i_name]|_->attsinattsletxml_of_inputitagattssubs=letatts=add_atts_of_inputi(clear_attsatts)inletsubs=matchi.i_kindwith|Textarea->[mk_value_parami]|Checkbox->letatts=X.atts_of_list[("","type"),[X.cdata"text/javascript"]]inletv=mk_value_param{iwithi_mltype=`Other("bool","function true -> \"true\" | false -> \"false\"","")}inletnode=X.node("","script")~atts[X.cdata(Printf.sprintf"document.getElementById('%s').checked = "i.i_name);v;X.cdata";"]in[node]|_->[]inX.nodetag~attssubsletmap_textarealoctagnameattssubs=letinput=input_of_attslocname~kind:Textareaattssubsinletxml=xml_of_inputinputtagattssubsin(input,xml)letmap_selectloctagnameattssubs=letinput=input_of_attslocname~kind:Selectattssubsinletxml=xml_of_inputinputtagattssubsin(input,xml)letmap_inputloctagnameattssubs=letinput=input_of_attslocnameattssubsinletxml=xml_of_inputinputtagattssubsin(input,xml)letmap_buttonloctagnameattssubs=let(i,xml)=map_inputloctagnameattssubsinmatchi.i_kindwithReset|Submit|Button->(i,xml)|_->kerrorloc"Invalid type for button %S"nameletwith_nameacctagflocattssubs=matchget_nameattswithNone->(acc,None,X.nodetag~attssubs)|Somename->let(p,xml)=floctagnameattssubsin(acc,Somep,xml)letadd_form_attributes=letadd_attsatts=letname_method=att_"method"inletname_action=att_"action"inletatts=matchX.get_attattsname_methodwith|Some_->atts|None->letm_atts=X.atts_of_list[att_param,[X.cdata"true"];att_optional,[X.cdata"true"];att_to_xml,[X.cdata"fun s -> [Xtmpl.Rewrite.cdata (Cohttp.Code.string_of_method s)]"];att_mltype,[X.cdata"Cohttp.Code.meth"];att_mlname,[X.cdata"meth"];]inX.atts_one~attsname_method[X.node(name_method)~atts:m_atts[X.cdata"`POST"]]inletatts=matchX.get_attattsname_actionwith|Some_->atts|None->leta_atts=X.atts_of_list[att_param,[X.cdata"true"];att_optional,[X.cdata"true"];]inX.atts_one~attsname_action[X.nodename_action~atts:a_atts[]]inattsinletenv=X.env_of_list[("","form"),fun()env?locattssubs->letnew_atts=add_attsattsinifnew_atts=attsthenraiseX.No_changeelse((),[X.node("","form")~atts:new_attssubs])]infuntmpl->let(_,xmls)=X.apply_to_xmls()envtmplinxmlsletmap_form_tmplloctmpl=letreciter_listaccxmls=let(acc,xmls)=List.fold_left(fun(acc,acc_xmls)xml->let(acc,xml)=iteraccxmlin(acc,xml::acc_xmls))(acc,[])xmlsin(acc,List.revxmls)anditeraccxml=matchxmlwithX.D_|X.C_|X.PI_->(acc,xml)|X.E({X.name=("",stag)asname;atts;subs}asnode)->beginlet(acc,i_opt,xml)=matchstagwith|"textarea"->with_nameaccnamemap_textarealocattssubs|"select"->with_nameaccnamemap_selectlocattssubs|"input"->with_nameaccnamemap_inputlocattssubs|"button"->with_nameaccnamemap_buttonlocattssubs|_->let(acc,xmls)=iter_listaccsubsin(acc,None,X.E{nodewithX.subs=xmls})inmatchi_optwithNone->(acc,xml)|Somei->try(* do not replace radio button inputs *)ignore(SMap.findi.i_nameacc);(acc,xml)withNot_found->(SMap.addi.i_nameiacc,xml)end|X.Enode->let(acc,xmls)=iter_listaccnode.X.subsin(acc,X.E{nodewithX.subs=xmls})initer_listSMap.emptytmplletmk_templateloctmpl=Str.valueNonrecursive[Vb.mk(Pat.var(mkloc"template_"loc))(Exp.extension(mkloc"xtmpl.string"loc,(PStr[(Str.eval(Exp.constant(Pconst_string(X.to_stringtmpl,Location.none,None))))])))]letmk_typelocinputs=letfieldnameiacc=letid=to_idiinlettyp=letstr=matchi.i_mltypewith|`CData->"string"|`Other(typ,_,_)->typinlettyp=parse_ocaml_typelocstrinmatchi.i_kindwith|Checkbox->typ|_->ifi.i_mandatorythentypelseletlid_option=mkloc(Ldot(Lident"Option","t"))locinTyp.constrlid_option[typ]in(Type.field(mklocidloc)typ)::accinletfields=SMap.foldfieldinputs[]inletty=Type.mk~kind:(Ptype_recordfields)(mkloc"t"loc)inStr.type_Recursive[ty]letmk_typ_formloctmpl=letstr=Exp.constant(Pconst_string(X.to_stringtmpl,Location.none,None))inletextension=Typ.extension(mkloc"xtmpl.string"loc,(PStr[Str.evalstr]))inletty=Type.mk~manifest:extension(mkloc"form"loc)inStr.type_Recursive[ty]letmk_typ_templateloctmpl=letstr=Exp.constant(Pconst_string(X.to_stringtmpl,Location.none,None))inletextension=Typ.extension(mkloc"xtmpl.string"loc,(PStr[Str.evalstr]))inletty=Type.mk~manifest:extension(mkloc"template"loc)inStr.type_Recursive[ty]letmk_exnloc=Str.exception_(Te.mk_exception(Te.decl~args:(Pcstr_tuple[[%type:template*stringlist]])(mkloc"Error"loc)))letmk_read_formlocinputs=letread_inputnameiexp=letid=to_idiinletmand=ifi.i_mandatorythen[%exprtrue]else[%exprfalse]inletof_string=matchi.i_kindwithCheckbox->[%exprfun_->Sometrue]|_->matchi.i_mltypewith`CData->[%exprfunv->Somev]|`Other(_,_,of_s)->[%exprSome(([%eparse_ocaml_expressionlocof_s])v)]inlete_name=Exp.constant(Pconst_string(name,Location.none,None))in[%exprlet[%p(Pat.var(mklocidloc))]=read_param__[%emand][%ee_name][%eof_string]in[%eexp]]inletbodyexp=[%exprfunget_att->leterrors=ref[]inletdefs=ref[]inletread_param__mandatorynameof_string=letv=get_attnameindefs:=(("",name),funx_?loc__->(x,[Xtmpl.Rewrite.cdata(matchvwithNone->""|Somes->s)]))::!defs;trymatchmandatory,vwith|true,None->failwith(name^" is mandatory")|false,None->None|_,Somev->of_stringvwithe->letmsg=matchewith|Sys_errors|Invalid_arguments|Failures->s|e->Printexc.to_stringeinerrors:=msg::!errors;Nonein[%eexp]]inletfill_t=letfieldnameiacc=letlid_name=lid~loc(to_idi)inlete=letid=Exp.identlid_nameinmatchi.i_kindwith|Checkbox->[%exprmatch[%eid]withNone->false|Somev->v]|_->matchi.i_mandatorywith|true->[%exprmatch[%eid]withNone->assertfalse|Somev->v]|false->idin(lid_name,e)::accinletfields=SMap.foldfieldinputs[]inExp.recordfieldsNoneinletcall_form=letfnameiacc=letlabel=Optional(to_idi)inletexp=[%exprNone]in(label,exp)::accinletargs=SMap.foldfinputs[]inExp.apply[%exprform~env]argsinletending=[%exprlet(f:template)=fun?env->letenv=Xtmpl.Rewrite.env_of_list?env!defsin[%ecall_form]inmatch!errorswith[]->(f,[%efill_t])|_->raise(Error(f,!errors))]inletreads=SMap.foldread_inputinputsendingin[%striletread_form=[%ebodyreads]]letmap_ojs_formlocfilename=letfilepath=file_pathlocfilenameinlettmpl=read_templatelocfilepathinlettmpl=add_form_attributestmplinlet(inputs,tmpl_form)=map_form_tmplloctmplinlettyp_form=mk_typ_formloctmpl_forminlettyp_template=mk_typ_templateloctmplinletexn=mk_exnlocinletval_template=mk_templateloctmpl_forminletval_form=[%striletform=template_]inlettyp=mk_typelocinputsinletread_form=mk_read_formlocinputsinletitems=[typ_form;typ_template;exn;typ;val_template;val_form;read_form]inMod.structureitemsletexpand_form~ctxtfilename=letloc=Expansion_context.Extension.extension_point_locctxtintrymap_ojs_formlocfilenamewithXtmpl.Types.Errore->errorloc(Xtmpl.Types.string_of_errore)letext_form=Extension.V3.declare"ojs.form"Extension.Context.module_exprAst_pattern.(single_expr_payload(estring__))expand_formletrule_form=Ppxlib.Context_free.Rule.extensionext_formlet()=Driver.register_transformation~rules:[rule_form]"ojs"