12345678910111213141516171819202122232425262728293031323334353637383940open!Baseletparse_identtokens=matchtokenswith|Sexp.Atom"*"->`star|Sexp.Atomident->`stringident|Sexp.Listidents->(* Nested parentheses are meaningless. *)letget_only_strings=function|Sexp.Atoms->s|Sexp.List_astokens->Printf.failwithf"nested parens are not supported: '%s'"(Sexp.to_stringtokens)()in`one_of(List.mapidents~f:get_only_strings|>Set.of_list(moduleString));;letparse_one=function(* This actually needn't return option, since we always have a valid parse. But we
leave it as-is for future language extensions that might be more restrictive. *)|[]->None|Sexp.Atom">"::unparsed_ident::rest->letident=parse_identunparsed_identinSome(`childrenident,rest)|ident::rest->Some(`descendants(parse_identident),rest);;letparses=letreclooptokens=matchparse_onetokenswith(* Needed, because we might use multiple symbols at one (> asdf -> `children asdf, []) *)|Some(action,rest)->action::looprest|None->[]in(* We parse the query by leveraging regular Sexp parsing to ensure parentheses are
matched correctly and to handle the grouping automatically. *)loop(Parsexp.Many.parse_string_exns);;