1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283openMiscopenSexplib.Stdtypepath_segment=|Matchofstring|Paramofstring|Splat|FullSplat|Slash[@@derivingsexp]typematches={params:(string*string)list;splat:stringlist;}[@@derivingfields,sexp]typet=path_segmentlist[@@derivingsexp]letparse_params=ifs="/"thenSlashelseifs="*"thenSplatelseifs="**"thenFullSplatelsetryScanf.sscanfs":%s"(funs->Params)withScanf.Scan_failure_->Matchsletof_listl=letlast_i=List.lengthl-1inl|>List.mapi~f:(funis->matchparse_paramswith|FullSplatwheni<>last_i->invalid_arg"** is only allowed at the end"|x->x)letsplit_slash_delim=letre='/'|>Re.char|>Re.compileinfunpath->path|>Re.split_fullre|>List.map~f:(function|`Texts->`Texts|`Delim_->`Delim)letsplit_slashpath=path|>split_slash_delim|>List.map~f:(function|`Texts->s|`Delim->"/")letof_stringpath=path|>split_slash|>of_listletto_stringl=letr=l|>List.filter_map~f:(function|Matchs->Somes|Params->Some(":"^s)|Splat->Some"*"|FullSplat->Some"**"|Slash->None)|>String.concat"/"in"/"^rletrecmatch_urlturl({params;splat}asmatches)=matcht,urlwith|[],[]|FullSplat::[],_->Somematches|FullSplat::_,_->assertfalse(* splat can't be last *)|(Matchx)::t,(`Texty)::urlwhenx=y->match_urlturlmatches|Slash::t,(`Delim)::url->match_urlturlmatches|Splat::t,(`Texts)::url->match_urlturl{matcheswithsplat=((Uri.pct_decodes)::splat)}|(Paramname)::t,(`Textp)::url->match_urlturl{matcheswithparams=(name,(Uri.pct_decodep))::params}|Splat::_,(`Delim)::_|Param_::_,`Delim::_|(Match_)::_,_|Slash::_,_|_::_,[]|[],_::_->Noneletmatch_urlturl=letpath=url|>split_slash_deliminmatch_urltpath{params=[];splat=[]}