]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/format.rs
Rollup merge of #107316 - ChrisDenton:snap, r=oli-obk
[rust.git] / compiler / rustc_ast / src / format.rs
1 use crate::ptr::P;
2 use crate::Expr;
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_span::symbol::{Ident, Symbol};
5 use rustc_span::Span;
6
7 // Definitions:
8 //
9 // format_args!("hello {abc:.xyz$}!!", abc="world");
10 // └──────────────────────────────────────────────┘
11 //                     FormatArgs
12 //
13 // format_args!("hello {abc:.xyz$}!!", abc="world");
14 //                                     └─────────┘
15 //                                      argument
16 //
17 // format_args!("hello {abc:.xyz$}!!", abc="world");
18 //              └───────────────────┘
19 //                     template
20 //
21 // format_args!("hello {abc:.xyz$}!!", abc="world");
22 //               └────┘└─────────┘└┘
23 //                      pieces
24 //
25 // format_args!("hello {abc:.xyz$}!!", abc="world");
26 //               └────┘           └┘
27 //                   literal pieces
28 //
29 // format_args!("hello {abc:.xyz$}!!", abc="world");
30 //                     └─────────┘
31 //                     placeholder
32 //
33 // format_args!("hello {abc:.xyz$}!!", abc="world");
34 //                      └─┘  └─┘
35 //                      positions (could be names, numbers, empty, or `*`)
36
37 /// (Parsed) format args.
38 ///
39 /// Basically the "AST" for a complete `format_args!()`.
40 ///
41 /// E.g., `format_args!("hello {name}");`.
42 #[derive(Clone, Encodable, Decodable, Debug)]
43 pub struct FormatArgs {
44     pub span: Span,
45     pub template: Vec<FormatArgsPiece>,
46     pub arguments: FormatArguments,
47 }
48
49 /// A piece of a format template string.
50 ///
51 /// E.g. "hello" or "{name}".
52 #[derive(Clone, Encodable, Decodable, Debug)]
53 pub enum FormatArgsPiece {
54     Literal(Symbol),
55     Placeholder(FormatPlaceholder),
56 }
57
58 /// The arguments to format_args!().
59 ///
60 /// E.g. `1, 2, name="ferris", n=3`,
61 /// but also implicit captured arguments like `x` in `format_args!("{x}")`.
62 #[derive(Clone, Encodable, Decodable, Debug)]
63 pub struct FormatArguments {
64     arguments: Vec<FormatArgument>,
65     num_unnamed_args: usize,
66     num_explicit_args: usize,
67     names: FxHashMap<Symbol, usize>,
68 }
69
70 // FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
71 #[cfg(parallel_compiler)]
72 unsafe impl Sync for FormatArguments {}
73 #[cfg(parallel_compiler)]
74 unsafe impl Send for FormatArguments {}
75
76 impl FormatArguments {
77     pub fn new() -> Self {
78         Self {
79             arguments: Vec::new(),
80             names: FxHashMap::default(),
81             num_unnamed_args: 0,
82             num_explicit_args: 0,
83         }
84     }
85
86     pub fn add(&mut self, arg: FormatArgument) -> usize {
87         let index = self.arguments.len();
88         if let Some(name) = arg.kind.ident() {
89             self.names.insert(name.name, index);
90         } else if self.names.is_empty() {
91             // Only count the unnamed args before the first named arg.
92             // (Any later ones are errors.)
93             self.num_unnamed_args += 1;
94         }
95         if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
96             // This is an explicit argument.
97             // Make sure that all arguments so far are explcit.
98             assert_eq!(
99                 self.num_explicit_args,
100                 self.arguments.len(),
101                 "captured arguments must be added last"
102             );
103             self.num_explicit_args += 1;
104         }
105         self.arguments.push(arg);
106         index
107     }
108
109     pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
110         let i = *self.names.get(&name)?;
111         Some((i, &self.arguments[i]))
112     }
113
114     pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
115         (i < self.num_explicit_args).then(|| &self.arguments[i])
116     }
117
118     pub fn unnamed_args(&self) -> &[FormatArgument] {
119         &self.arguments[..self.num_unnamed_args]
120     }
121
122     pub fn named_args(&self) -> &[FormatArgument] {
123         &self.arguments[self.num_unnamed_args..self.num_explicit_args]
124     }
125
126     pub fn explicit_args(&self) -> &[FormatArgument] {
127         &self.arguments[..self.num_explicit_args]
128     }
129
130     pub fn all_args(&self) -> &[FormatArgument] {
131         &self.arguments[..]
132     }
133
134     pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
135         &mut self.arguments[..]
136     }
137 }
138
139 #[derive(Clone, Encodable, Decodable, Debug)]
140 pub struct FormatArgument {
141     pub kind: FormatArgumentKind,
142     pub expr: P<Expr>,
143 }
144
145 #[derive(Clone, Encodable, Decodable, Debug)]
146 pub enum FormatArgumentKind {
147     /// `format_args(…, arg)`
148     Normal,
149     /// `format_args(…, arg = 1)`
150     Named(Ident),
151     /// `format_args("… {arg} …")`
152     Captured(Ident),
153 }
154
155 impl FormatArgumentKind {
156     pub fn ident(&self) -> Option<Ident> {
157         match self {
158             &Self::Normal => None,
159             &Self::Named(id) => Some(id),
160             &Self::Captured(id) => Some(id),
161         }
162     }
163 }
164
165 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
166 pub struct FormatPlaceholder {
167     /// Index into [`FormatArgs::arguments`].
168     pub argument: FormatArgPosition,
169     /// The span inside the format string for the full `{…}` placeholder.
170     pub span: Option<Span>,
171     /// `{}`, `{:?}`, or `{:x}`, etc.
172     pub format_trait: FormatTrait,
173     /// `{}` or `{:.5}` or `{:-^20}`, etc.
174     pub format_options: FormatOptions,
175 }
176
177 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
178 pub struct FormatArgPosition {
179     /// Which argument this position refers to (Ok),
180     /// or would've referred to if it existed (Err).
181     pub index: Result<usize, usize>,
182     /// What kind of position this is. See [`FormatArgPositionKind`].
183     pub kind: FormatArgPositionKind,
184     /// The span of the name or number.
185     pub span: Option<Span>,
186 }
187
188 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
189 pub enum FormatArgPositionKind {
190     /// `{}` or `{:.*}`
191     Implicit,
192     /// `{1}` or `{:1$}` or `{:.1$}`
193     Number,
194     /// `{a}` or `{:a$}` or `{:.a$}`
195     Named,
196 }
197
198 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
199 pub enum FormatTrait {
200     /// `{}`
201     Display,
202     /// `{:?}`
203     Debug,
204     /// `{:e}`
205     LowerExp,
206     /// `{:E}`
207     UpperExp,
208     /// `{:o}`
209     Octal,
210     /// `{:p}`
211     Pointer,
212     /// `{:b}`
213     Binary,
214     /// `{:x}`
215     LowerHex,
216     /// `{:X}`
217     UpperHex,
218 }
219
220 #[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
221 pub struct FormatOptions {
222     /// The width. E.g. `{:5}` or `{:width$}`.
223     pub width: Option<FormatCount>,
224     /// The precision. E.g. `{:.5}` or `{:.precision$}`.
225     pub precision: Option<FormatCount>,
226     /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
227     pub alignment: Option<FormatAlignment>,
228     /// The fill character. E.g. the `.` in `{:.>10}`.
229     pub fill: Option<char>,
230     /// The `+` or `-` flag.
231     pub sign: Option<FormatSign>,
232     /// The `#` flag.
233     pub alternate: bool,
234     /// The `0` flag. E.g. the `0` in `{:02x}`.
235     pub zero_pad: bool,
236     /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
237     pub debug_hex: Option<FormatDebugHex>,
238 }
239
240 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
241 pub enum FormatSign {
242     /// The `+` flag.
243     Plus,
244     /// The `-` flag.
245     Minus,
246 }
247
248 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
249 pub enum FormatDebugHex {
250     /// The `x` flag in `{:x?}`.
251     Lower,
252     /// The `X` flag in `{:X?}`.
253     Upper,
254 }
255
256 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
257 pub enum FormatAlignment {
258     /// `{:<}`
259     Left,
260     /// `{:>}`
261     Right,
262     /// `{:^}`
263     Center,
264 }
265
266 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
267 pub enum FormatCount {
268     /// `{:5}` or `{:.5}`
269     Literal(usize),
270     /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
271     Argument(FormatArgPosition),
272 }