rustc_builtin_macros/format_foreign/shell/
mod.rs1use 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
42pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> {
44 Substitutions { s, pos: start_pos }
45}
46
47pub(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
69fn 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 _ => { }
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;