Skip to main content

rustc_builtin_macros/format_foreign/shell/
mod.rs

1use rustc_span::InnerSpan;
2
3use super::StrCursor as Cur;
4
5#[derive(#[automatically_derived]
impl<'a> ::core::clone::Clone for Substitution<'a> {
    #[inline]
    fn clone(&self) -> Substitution<'a> {
        match self {
            Substitution::Ordinal(__self_0, __self_1) =>
                Substitution::Ordinal(::core::clone::Clone::clone(__self_0),
                    ::core::clone::Clone::clone(__self_1)),
            Substitution::Name(__self_0, __self_1) =>
                Substitution::Name(::core::clone::Clone::clone(__self_0),
                    ::core::clone::Clone::clone(__self_1)),
            Substitution::Escape(__self_0) =>
                Substitution::Escape(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<'a> ::core::marker::StructuralPartialEq for Substitution<'a> { }
#[automatically_derived]
impl<'a> ::core::cmp::PartialEq for Substitution<'a> {
    #[inline]
    fn eq(&self, other: &Substitution<'a>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Substitution::Ordinal(__self_0, __self_1),
                    Substitution::Ordinal(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (Substitution::Name(__self_0, __self_1),
                    Substitution::Name(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (Substitution::Escape(__self_0),
                    Substitution::Escape(__arg1_0)) => __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl<'a> ::core::fmt::Debug for Substitution<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Substitution::Ordinal(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "Ordinal", __self_0, &__self_1),
            Substitution::Name(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Name",
                    __self_0, &__self_1),
            Substitution::Escape(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Escape",
                    &__self_0),
        }
    }
}Debug)]
6pub(crate) enum Substitution<'a> {
7    Ordinal(u8, (usize, usize)),
8    Name(&'a str, (usize, usize)),
9    Escape((usize, usize)),
10}
11
12impl ToString for Substitution<'_> {
13    fn to_string(&self) -> String {
14        match self {
15            Substitution::Ordinal(n, _) => ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("${0}", n)) })format!("${n}"),
16            Substitution::Name(n, _) => ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("${0}", n)) })format!("${n}"),
17            Substitution::Escape(_) => "$$".into(),
18        }
19    }
20}
21
22impl Substitution<'_> {
23    pub(crate) fn position(&self) -> InnerSpan {
24        let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
25        InnerSpan::new(pos.0, pos.1)
26    }
27
28    fn set_position(&mut self, start: usize, end: usize) {
29        let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
30        *pos = (start, end);
31    }
32
33    pub(crate) fn translate(&self) -> Result<String, Option<String>> {
34        match self {
35            Substitution::Ordinal(n, _) => Ok(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{{{0}}}", n))
    })format!("{{{}}}", n)),
36            Substitution::Name(n, _) => Ok(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{{{0}}}", n))
    })format!("{{{}}}", n)),
37            Substitution::Escape(_) => Err(None),
38        }
39    }
40}
41
42/// Returns an iterator over all substitutions in a given string.
43pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> {
44    Substitutions { s, pos: start_pos }
45}
46
47/// Iterator over substitutions in a string.
48pub(crate) struct Substitutions<'a> {
49    s: &'a str,
50    pos: usize,
51}
52
53impl<'a> Iterator for Substitutions<'a> {
54    type Item = Substitution<'a>;
55    fn next(&mut self) -> Option<Self::Item> {
56        let (mut sub, tail) = parse_next_substitution(self.s)?;
57        self.s = tail;
58        let InnerSpan { start, end } = sub.position();
59        sub.set_position(start + self.pos, end + self.pos);
60        self.pos += end;
61        Some(sub)
62    }
63
64    fn size_hint(&self) -> (usize, Option<usize>) {
65        (0, Some(self.s.len()))
66    }
67}
68
69/// Parse the next substitution from the input string.
70fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> {
71    let at = {
72        let start = s.find('$')?;
73        match s[start + 1..].chars().next()? {
74            '$' => return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])),
75            c @ '0'..='9' => {
76                let n = (c as u8) - b'0';
77                return Some((Substitution::Ordinal(n, (start, start + 2)), &s[start + 2..]));
78            }
79            _ => { /* fall-through */ }
80        }
81
82        Cur::new_at(s, start)
83    };
84
85    let at = at.at_next_cp()?;
86    let (c, inner) = at.next_cp()?;
87
88    if !is_ident_head(c) {
89        None
90    } else {
91        let end = at_next_cp_while(inner, is_ident_tail);
92        let slice = at.slice_between(end).unwrap();
93        let start = at.at - 1;
94        let end_pos = at.at + slice.len();
95        Some((Substitution::Name(slice, (start, end_pos)), end.slice_after()))
96    }
97}
98
99fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_>
100where
101    F: FnMut(char) -> bool,
102{
103    loop {
104        match cur.next_cp() {
105            Some((c, next)) if pred(c) => {
106                cur = next;
107            }
108            _ => return cur,
109        }
110    }
111}
112
113fn is_ident_head(c: char) -> bool {
114    c.is_ascii_alphabetic() || c == '_'
115}
116
117fn is_ident_tail(c: char) -> bool {
118    c.is_ascii_alphanumeric() || c == '_'
119}
120
121#[cfg(test)]
122mod tests;