133d722a9Sopenharmony_ciuse syn::ext::IdentExt;
233d722a9Sopenharmony_ciuse syn::parse::{Error, ParseStream, Result};
333d722a9Sopenharmony_ciuse syn::{Ident, LitStr, Token};
433d722a9Sopenharmony_ci
533d722a9Sopenharmony_cipub struct QualifiedName {
633d722a9Sopenharmony_ci    pub segments: Vec<Ident>,
733d722a9Sopenharmony_ci}
833d722a9Sopenharmony_ci
933d722a9Sopenharmony_ciimpl QualifiedName {
1033d722a9Sopenharmony_ci    pub fn parse_quoted(lit: &LitStr) -> Result<Self> {
1133d722a9Sopenharmony_ci        if lit.value().is_empty() {
1233d722a9Sopenharmony_ci            let segments = Vec::new();
1333d722a9Sopenharmony_ci            Ok(QualifiedName { segments })
1433d722a9Sopenharmony_ci        } else {
1533d722a9Sopenharmony_ci            lit.parse_with(|input: ParseStream| {
1633d722a9Sopenharmony_ci                let allow_raw = false;
1733d722a9Sopenharmony_ci                parse_unquoted(input, allow_raw)
1833d722a9Sopenharmony_ci            })
1933d722a9Sopenharmony_ci        }
2033d722a9Sopenharmony_ci    }
2133d722a9Sopenharmony_ci
2233d722a9Sopenharmony_ci    pub fn parse_unquoted(input: ParseStream) -> Result<Self> {
2333d722a9Sopenharmony_ci        let allow_raw = true;
2433d722a9Sopenharmony_ci        parse_unquoted(input, allow_raw)
2533d722a9Sopenharmony_ci    }
2633d722a9Sopenharmony_ci
2733d722a9Sopenharmony_ci    pub fn parse_quoted_or_unquoted(input: ParseStream) -> Result<Self> {
2833d722a9Sopenharmony_ci        if input.peek(LitStr) {
2933d722a9Sopenharmony_ci            let lit: LitStr = input.parse()?;
3033d722a9Sopenharmony_ci            Self::parse_quoted(&lit)
3133d722a9Sopenharmony_ci        } else {
3233d722a9Sopenharmony_ci            Self::parse_unquoted(input)
3333d722a9Sopenharmony_ci        }
3433d722a9Sopenharmony_ci    }
3533d722a9Sopenharmony_ci}
3633d722a9Sopenharmony_ci
3733d722a9Sopenharmony_cifn parse_unquoted(input: ParseStream, allow_raw: bool) -> Result<QualifiedName> {
3833d722a9Sopenharmony_ci    let mut segments = Vec::new();
3933d722a9Sopenharmony_ci    let mut trailing_punct = true;
4033d722a9Sopenharmony_ci    let leading_colons: Option<Token![::]> = input.parse()?;
4133d722a9Sopenharmony_ci    while trailing_punct && input.peek(Ident::peek_any) {
4233d722a9Sopenharmony_ci        let mut ident = Ident::parse_any(input)?;
4333d722a9Sopenharmony_ci        if let Some(unraw) = ident.to_string().strip_prefix("r#") {
4433d722a9Sopenharmony_ci            if !allow_raw {
4533d722a9Sopenharmony_ci                let msg = format!(
4633d722a9Sopenharmony_ci                    "raw identifier `{}` is not allowed in a quoted namespace; use `{}`, or remove quotes",
4733d722a9Sopenharmony_ci                    ident, unraw,
4833d722a9Sopenharmony_ci                );
4933d722a9Sopenharmony_ci                return Err(Error::new(ident.span(), msg));
5033d722a9Sopenharmony_ci            }
5133d722a9Sopenharmony_ci            ident = Ident::new(unraw, ident.span());
5233d722a9Sopenharmony_ci        }
5333d722a9Sopenharmony_ci        segments.push(ident);
5433d722a9Sopenharmony_ci        let colons: Option<Token![::]> = input.parse()?;
5533d722a9Sopenharmony_ci        trailing_punct = colons.is_some();
5633d722a9Sopenharmony_ci    }
5733d722a9Sopenharmony_ci    if segments.is_empty() && leading_colons.is_none() {
5833d722a9Sopenharmony_ci        return Err(input.error("expected path"));
5933d722a9Sopenharmony_ci    } else if trailing_punct {
6033d722a9Sopenharmony_ci        return Err(input.error("expected path segment"));
6133d722a9Sopenharmony_ci    }
6233d722a9Sopenharmony_ci    Ok(QualifiedName { segments })
6333d722a9Sopenharmony_ci}
64