12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091open!ImportmoduleT=structtypet=longident=Lidentofstring|Ldotoft*string|Lapplyoft*tletcompare:t->t->int=Poly.compareletis_normal_ident_char=function|'A'..'Z'|'a'..'z'|'0'..'9'|'_'|'\''->true|_->falseletis_normal_ident=function|"asr"|"land"|"lor"|"lsl"|"lsr"|"lxor"|"mod"|"or"->false|string->String.for_allstring~f:is_normal_ident_charletshort_namestring=ifis_normal_identstringthenstringelse"( "^string^" )"letrecname=function|Lidents->short_names|Ldot(a,b)->namea^"."^short_nameb|Lapply(a,b)->Printf.sprintf"%s(%s)"(namea)(nameb)letsexp_of_tt=Sexp.Atom(namet)endincludeTletrecflataccu=function|Lidents->s::accu|Ldot(lid,s)->flat(s::accu)lid|Lapply(_,_)->invalid_arg"Ppxlib.Longident.flatten"letflatten_exnlid=flat[]lidletlast_exn=function|Lidents->s|Ldot(_,s)->s|Lapply(_,_)->invalid_arg"Ppxlib.Longident.flatten"letunflatten~initl=List.fold_leftl~init~f:(funaccs->Ldot(acc,s))(* for cases without dotted operators (e.g. [parse "A.B.C"]) *)letparse_simples=matchString.split_on_chars~sep:'.'with|[]->assertfalse|s::l->unflatten~init:(Lidents)l(* find the first matching pair of parentheses *)letrecparentheseslposopenedposlens=ifpos>=lenthenifopened>0thenError()elseOkNoneelsematchs.[pos]with|'('->letlpos=ifopened=0thenposelselposinparentheseslpos(opened+1)(pos+1)lens|')'->letopened=opened-1inifopened=0thenOk(Some(lpos,pos))elseifopened<0thenError()elseparentheseslposopened(pos+1)lens|_->parentheseslposopened(pos+1)lens(* handle ["A.B.(+.+)"] or ["Vec.(.%.()<-)"] *)letparses=letinvalidvariant=invalid_arg(Printf.sprintf"Ppxlib.Longident.parse(%s): %S"variants)inifString.lengths<1theninvalid"empty string";letpar=parentheses(-1)00(String.lengths)sinmatch(s.[0],par)with|('A'..'Z'|'a'..'z'|'_'),OkNone->parse_simples|_,OkNone->Lidents(* This is a raw operator, no module path *)|_,Error_->invalid"unbalanced parenthesis"|_,Ok(Some(l,r))->(ifInt.(r<>String.lengths-1)theninvalid"right parenthesis misplaced";letgroup=letinside=String.trim(String.subs~pos:(l+1)~len:(r-l-1))inifString.(inside="")then"()"elseinsideinifInt.(l=0)thenLidentgroupelseifChar.(s.[l-1]<>'.')theninvalid"application in path"elseletbefore=String.subs~pos:0~len:(l-1)inmatchString.split_on_charbefore~sep:'.'with|[]->assertfalse|s::l->Ldot(unflatten~init:(Lidents)l,group))moduleMap=Map.Make(T)moduleSet=Set.Make(T)