3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_span::symbol::{Ident, Symbol};
9 // format_args!("hello {abc:.xyz$}!!", abc="world");
10 // └──────────────────────────────────────────────┘
13 // format_args!("hello {abc:.xyz$}!!", abc="world");
17 // format_args!("hello {abc:.xyz$}!!", abc="world");
18 // └───────────────────┘
21 // format_args!("hello {abc:.xyz$}!!", abc="world");
22 // └────┘└─────────┘└┘
25 // format_args!("hello {abc:.xyz$}!!", abc="world");
29 // format_args!("hello {abc:.xyz$}!!", abc="world");
33 // format_args!("hello {abc:.xyz$}!!", abc="world");
35 // positions (could be names, numbers, empty, or `*`)
37 /// (Parsed) format args.
39 /// Basically the "AST" for a complete `format_args!()`.
41 /// E.g., `format_args!("hello {name}");`.
42 #[derive(Clone, Debug)]
43 pub struct FormatArgs {
45 pub template: Vec<FormatArgsPiece>,
46 pub arguments: FormatArguments,
49 /// A piece of a format template string.
51 /// E.g. "hello" or "{name}".
52 #[derive(Clone, Debug)]
53 pub enum FormatArgsPiece {
55 Placeholder(FormatPlaceholder),
58 /// The arguments to format_args!().
60 /// E.g. `1, 2, name="ferris", n=3`,
61 /// but also implicit captured arguments like `x` in `format_args!("{x}")`.
62 #[derive(Clone, Debug)]
63 pub struct FormatArguments {
64 arguments: Vec<FormatArgument>,
65 num_unnamed_args: usize,
66 num_explicit_args: usize,
67 names: FxHashMap<Symbol, usize>,
70 impl FormatArguments {
71 pub fn new() -> Self {
73 arguments: Vec::new(),
74 names: FxHashMap::default(),
80 pub fn add(&mut self, arg: FormatArgument) -> usize {
81 let index = self.arguments.len();
82 if let Some(name) = arg.kind.ident() {
83 self.names.insert(name.name, index);
84 } else if self.names.is_empty() {
85 // Only count the unnamed args before the first named arg.
86 // (Any later ones are errors.)
87 self.num_unnamed_args += 1;
89 if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
90 // This is an explicit argument.
91 // Make sure that all arguments so far are explcit.
93 self.num_explicit_args,
95 "captured arguments must be added last"
97 self.num_explicit_args += 1;
99 self.arguments.push(arg);
103 pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
104 let i = *self.names.get(&name)?;
105 Some((i, &self.arguments[i]))
108 pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
109 (i < self.num_explicit_args).then(|| &self.arguments[i])
112 pub fn unnamed_args(&self) -> &[FormatArgument] {
113 &self.arguments[..self.num_unnamed_args]
116 pub fn named_args(&self) -> &[FormatArgument] {
117 &self.arguments[self.num_unnamed_args..self.num_explicit_args]
120 pub fn explicit_args(&self) -> &[FormatArgument] {
121 &self.arguments[..self.num_explicit_args]
124 pub fn into_vec(self) -> Vec<FormatArgument> {
129 #[derive(Clone, Debug)]
130 pub struct FormatArgument {
131 pub kind: FormatArgumentKind,
135 #[derive(Clone, Debug)]
136 pub enum FormatArgumentKind {
137 /// `format_args(…, arg)`
139 /// `format_args(…, arg = 1)`
141 /// `format_args("… {arg} …")`
145 impl FormatArgumentKind {
146 pub fn ident(&self) -> Option<Ident> {
148 &Self::Normal => None,
149 &Self::Named(id) => Some(id),
150 &Self::Captured(id) => Some(id),
155 #[derive(Clone, Debug, PartialEq, Eq)]
156 pub struct FormatPlaceholder {
157 /// Index into [`FormatArgs::arguments`].
158 pub argument: FormatArgPosition,
159 /// The span inside the format string for the full `{…}` placeholder.
160 pub span: Option<Span>,
161 /// `{}`, `{:?}`, or `{:x}`, etc.
162 pub format_trait: FormatTrait,
163 /// `{}` or `{:.5}` or `{:-^20}`, etc.
164 pub format_options: FormatOptions,
167 #[derive(Clone, Debug, PartialEq, Eq)]
168 pub struct FormatArgPosition {
169 /// Which argument this position refers to (Ok),
170 /// or would've referred to if it existed (Err).
171 pub index: Result<usize, usize>,
172 /// What kind of position this is. See [`FormatArgPositionKind`].
173 pub kind: FormatArgPositionKind,
174 /// The span of the name or number.
175 pub span: Option<Span>,
178 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
179 pub enum FormatArgPositionKind {
182 /// `{1}` or `{:1$}` or `{:.1$}`
184 /// `{a}` or `{:a$}` or `{:.a$}`
188 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
189 pub enum FormatTrait {
210 #[derive(Clone, Debug, Default, PartialEq, Eq)]
211 pub struct FormatOptions {
212 /// The width. E.g. `{:5}` or `{:width$}`.
213 pub width: Option<FormatCount>,
214 /// The precision. E.g. `{:.5}` or `{:.precision$}`.
215 pub precision: Option<FormatCount>,
216 /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
217 pub alignment: Option<FormatAlignment>,
218 /// The fill character. E.g. the `.` in `{:.>10}`.
219 pub fill: Option<char>,
220 /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
224 #[derive(Clone, Debug, PartialEq, Eq)]
225 pub enum FormatAlignment {
234 #[derive(Clone, Debug, PartialEq, Eq)]
235 pub enum FormatCount {
236 /// `{:5}` or `{:.5}`
238 /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
239 Argument(FormatArgPosition),