123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109open!Coreopen!Ppxlibletdisable_warning_32~loc=letopen(valAst_builder.makeloc)inattribute~name:(Located.mk"ocaml.warning")~payload:(PStr[pstr_eval(estring"-32")[]]);;letmodule_type_of_identifiers~loc~identifiers=letopen(valAst_builder.makeloc)inidentifiers(* Sort because the ml and mli might have their identifiers in
different orders, but we still want the [module type S] to present
them in the same order. *)|>List.dedup_and_sort~compare:String.compare|>List.map~f:(funident->lettype_=[%type:string]inletname=Located.mkidentinpsig_value(value_description~name~type_~prim:[]));;letgenerate_struct~loc~path:_(expr:expression)=letloc={locwithloc_ghost=true}inletopen(valAst_builder.makeloc)in(* The [Some ""] means that the string will use the multiline string literal
syntax, but with no termination identifier. *)letstring_constantl=pexp_constant(Pconst_string(l,loc,Some""))inmatchexpr.pexp_descwith|Pexp_constant(Pconst_string(l,_,_))->let{Traverse_css.css_string;mapping}=Traverse_css.transform~pos:loc.loc_startlinletmapping=String.Table.to_alistmappinginletregister=[%strilet()=Inline_css.Private.append[%estring_constantcss_string]]inlett_sig=module_type_of_identifiers~loc~identifiers:(List.mapmapping~f:fst)|>pmty_signatureinlett_module=mapping|>List.map~f:(fun(k,v)->[%strilet[%pppat_var(Located.mkk)]=[%estring_constantv]])|>pmod_structureinpmod_structure[pstr_attribute(disable_warning_32~loc);register;[%strimoduletypeS=[%mt_sig]];[%stritypet=(moduleS)];[%strimoduleDefault=[%mt_module]];[%striincludeDefault];[%striletdefault:t=(moduleDefault)]]|_->Location.raise_errorf~loc"%%css must take a single string as input";;letgenerate_sig~loc~path:_payload=letloc={locwithloc_ghost=true}inletopen(valAst_builder.makeloc)inmatchpayloadwith|PTyp(type_:core_type)->letall_idents=objectinherit[stringlist]Ast_traverse.foldassupermethod!core_typeeacc=letacc=super#core_typeeaccinmatche.ptyp_descwith|Ptyp_constr({txt=Lidentidentifier;_},_)->identifier::acc|_->accendinletidentifiers=all_idents#core_typetype_[]inletbasic_sig=module_type_of_identifiers~loc~identifiersinpmty_signature([[%sigi:moduletypeS=[%mpmty_signaturebasic_sig]];[%sigi:typet=(moduleS)];[%sigi:valdefault:t]]@basic_sig)|PStr_|PSig_|PPat_->Location.raise_errorf~loc"you must pass %%css a space-separated sequence of identifiers which were used in \
the css string";;letml_extension=Extension.declare"css.raw"Extension.Context.module_exprAst_pattern.(single_expr_payload__)generate_struct;;letmli_extension=Extension.declare"css.raw"Extension.Context.module_typeAst_pattern.(__)generate_sig;;let()=Driver.register_transformation"css"~extensions:[ml_extension;mli_extension]moduleFor_testing=structletgenerate_struct=generate_struct~loc:Location.none~path:()letgenerate_sigtyp=generate_sig~loc:Location.none~path:()(PTyptyp)end