|
1 | 1 | use super::*;
|
2 | 2 | use rustc_ast as ast;
|
3 |
| -use rustc_span::sym; |
| 3 | +use rustc_span::symbol::{kw, sym, Ident}; |
4 | 4 |
|
5 | 5 | pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
|
6 | 6 | let macsp = ecx.with_def_site_ctxt(ecx.call_site());
|
7 | 7 |
|
8 |
| - … // TODO |
| 8 | + if fmt.template.is_empty() { |
| 9 | + return ecx.expr_call_global( |
| 10 | + macsp, |
| 11 | + ecx.std_path(&[sym::fmt, sym::Arguments, sym::from_static_str]), |
| 12 | + vec![ecx.expr_str(macsp, kw::Empty)], |
| 13 | + ); |
| 14 | + } |
| 15 | + |
| 16 | + if let &[FormatArgsPiece::Literal(s)] = &fmt.template[..] { |
| 17 | + return ecx.expr_call_global( |
| 18 | + macsp, |
| 19 | + ecx.std_path(&[sym::fmt, sym::Arguments, sym::from_static_str]), |
| 20 | + vec![ecx.expr_str(macsp, s)], |
| 21 | + ); |
| 22 | + } |
| 23 | + |
| 24 | + let args = Ident::new(sym::_args, macsp); |
| 25 | + let f = Ident::new(sym::f, macsp); |
| 26 | + |
| 27 | + let arguments = fmt.arguments.into_vec(); |
| 28 | + |
| 29 | + let mut statements = Vec::new(); |
| 30 | + |
| 31 | + let mut default_options = true; |
| 32 | + |
| 33 | + for piece in fmt.template { |
| 34 | + match piece { |
| 35 | + FormatArgsPiece::Literal(s) => { |
| 36 | + // Generate: |
| 37 | + // f.write_str("…")?; |
| 38 | + statements.push(ecx.stmt_expr(ecx.expr( |
| 39 | + macsp, |
| 40 | + ast::ExprKind::Try(ecx.expr( |
| 41 | + macsp, |
| 42 | + ast::ExprKind::MethodCall( |
| 43 | + ast::PathSegment::from_ident(Ident::new(sym::write_str, macsp)), |
| 44 | + ecx.expr_ident(macsp, f), |
| 45 | + vec![ecx.expr_str(macsp, s)], |
| 46 | + macsp, |
| 47 | + ), |
| 48 | + )), |
| 49 | + ))); |
| 50 | + } |
| 51 | + FormatArgsPiece::Placeholder(p) => { |
| 52 | + // Don't set options if they're still set to defaults |
| 53 | + // and this placeholder also uses default options. |
| 54 | + let d = p.format_options == FormatOptions::default(); |
| 55 | + if !default_options || !d { |
| 56 | + default_options = d; |
| 57 | + // Generate: |
| 58 | + // f.set_options(…); |
| 59 | + statements.push(ecx.stmt_expr(ecx.expr( |
| 60 | + macsp, |
| 61 | + ast::ExprKind::MethodCall( |
| 62 | + ast::PathSegment::from_ident(Ident::new(sym::set_options, macsp)), |
| 63 | + ecx.expr_ident(macsp, f), |
| 64 | + vec![ |
| 65 | + ecx.expr_u32(macsp, p.format_options.flags), |
| 66 | + ecx.expr_char(macsp, p.format_options.fill.unwrap_or(' ')), |
| 67 | + ecx.expr_path(ecx.path_global( |
| 68 | + macsp, |
| 69 | + ecx.std_path(&[ |
| 70 | + sym::fmt, |
| 71 | + sym::rt, |
| 72 | + sym::v1, |
| 73 | + sym::Alignment, |
| 74 | + match p.format_options.alignment { |
| 75 | + Some(FormatAlignment::Left) => sym::Left, |
| 76 | + Some(FormatAlignment::Right) => sym::Right, |
| 77 | + Some(FormatAlignment::Center) => sym::Center, |
| 78 | + None => sym::Unknown, |
| 79 | + }, |
| 80 | + ]), |
| 81 | + )), |
| 82 | + make_count(ecx, macsp, &arguments, args, p.format_options.width), |
| 83 | + make_count( |
| 84 | + ecx, |
| 85 | + macsp, |
| 86 | + &arguments, |
| 87 | + args, |
| 88 | + p.format_options.precision, |
| 89 | + ), |
| 90 | + ], |
| 91 | + macsp, |
| 92 | + ), |
| 93 | + ))); |
| 94 | + } |
| 95 | + // Generate: |
| 96 | + // ::core::fmt::Display::fmt(arg.0, f)?; |
| 97 | + let arg = if let Ok(i) = p.argument.index { |
| 98 | + ecx.expr_field( |
| 99 | + arguments[i].expr.span.with_ctxt(macsp.ctxt()), |
| 100 | + ecx.expr_ident(macsp, args), |
| 101 | + Ident::new(sym::integer(i), macsp), |
| 102 | + ) |
| 103 | + } else { |
| 104 | + DummyResult::raw_expr(macsp, true) |
| 105 | + }; |
| 106 | + let fmt_trait = match p.format_trait { |
| 107 | + FormatTrait::Display => sym::Display, |
| 108 | + FormatTrait::Debug => sym::Debug, |
| 109 | + FormatTrait::LowerExp => sym::LowerExp, |
| 110 | + FormatTrait::UpperExp => sym::UpperExp, |
| 111 | + FormatTrait::Octal => sym::Octal, |
| 112 | + FormatTrait::Pointer => sym::Pointer, |
| 113 | + FormatTrait::Binary => sym::Binary, |
| 114 | + FormatTrait::LowerHex => sym::LowerHex, |
| 115 | + FormatTrait::UpperHex => sym::UpperHex, |
| 116 | + }; |
| 117 | + statements.push(ecx.stmt_expr(ecx.expr( |
| 118 | + macsp, |
| 119 | + ast::ExprKind::Try(ecx.expr_call_global( |
| 120 | + arg.span, |
| 121 | + ecx.std_path(&[sym::fmt, fmt_trait, sym::fmt]), |
| 122 | + vec![arg, ecx.expr_ident(macsp, f)], |
| 123 | + )), |
| 124 | + ))); |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + // Generate: |
| 130 | + // Ok(()) |
| 131 | + statements.push(ecx.stmt_expr(ecx.expr_ok(macsp, ecx.expr_tuple(macsp, Vec::new())))); |
| 132 | + |
| 133 | + // Generate: |
| 134 | + // |f: &mut ::core::fmt::Formatter| -> ::core::fmt::Result { |
| 135 | + // … // statements |
| 136 | + // } |
| 137 | + let closure = ecx.expr( |
| 138 | + macsp, |
| 139 | + ast::ExprKind::Closure( |
| 140 | + ast::ClosureBinder::NotPresent, |
| 141 | + ast::CaptureBy::Ref, |
| 142 | + ast::Async::No, |
| 143 | + ast::Movability::Movable, |
| 144 | + ecx.fn_decl( |
| 145 | + vec![ecx.param( |
| 146 | + macsp, |
| 147 | + f, |
| 148 | + ecx.ty_rptr( |
| 149 | + macsp, |
| 150 | + ecx.ty_path(ecx.path_all( |
| 151 | + macsp, |
| 152 | + true, |
| 153 | + ecx.std_path(&[sym::fmt, sym::Formatter]), |
| 154 | + vec![ast::GenericArg::Lifetime(ast::Lifetime { |
| 155 | + id: ast::DUMMY_NODE_ID, |
| 156 | + ident: Ident::new(kw::UnderscoreLifetime, macsp), |
| 157 | + })], |
| 158 | + )), |
| 159 | + None, |
| 160 | + ast::Mutability::Mut, |
| 161 | + ), |
| 162 | + )], |
| 163 | + ast::FnRetTy::Ty( |
| 164 | + ecx.ty_path(ecx.path_global(macsp, ecx.std_path(&[sym::fmt, sym::Result]))), |
| 165 | + ), |
| 166 | + ), |
| 167 | + ecx.expr_block(ecx.block(macsp, statements)), |
| 168 | + macsp, |
| 169 | + ), |
| 170 | + ); |
9 | 171 |
|
10 | 172 | // Generate:
|
11 | 173 | // ::core::fmt::Arguments::new(
|
12 |
| - // … |
| 174 | + // &match (&arg0, &arg1, …) { |
| 175 | + // args => closure, |
| 176 | + // } |
13 | 177 | // )
|
14 | 178 | ecx.expr_call_global(
|
15 | 179 | macsp,
|
16 | 180 | ecx.std_path(&[sym::fmt, sym::Arguments, sym::new]),
|
17 |
| - vec![…], |
| 181 | + vec![ |
| 182 | + ecx.expr_addr_of( |
| 183 | + macsp, |
| 184 | + ecx.expr_match( |
| 185 | + macsp, |
| 186 | + ecx.expr_tuple( |
| 187 | + macsp, |
| 188 | + arguments |
| 189 | + .into_iter() |
| 190 | + .map(|arg| { |
| 191 | + ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr) |
| 192 | + }) |
| 193 | + .collect(), |
| 194 | + ), |
| 195 | + vec![ecx.arm(macsp, ecx.pat_ident(macsp, args), closure)], |
| 196 | + ), |
| 197 | + ), |
| 198 | + ], |
18 | 199 | )
|
19 | 200 | }
|
| 201 | + |
| 202 | +pub fn make_count( |
| 203 | + ecx: &ExtCtxt<'_>, |
| 204 | + macsp: Span, |
| 205 | + arguments: &[FormatArgument], |
| 206 | + args: Ident, |
| 207 | + count: Option<FormatCount>, |
| 208 | +) -> P<ast::Expr> { |
| 209 | + match count { |
| 210 | + Some(FormatCount::Literal(n)) => ecx.expr_some(macsp, ecx.expr_usize(macsp, n)), |
| 211 | + Some(FormatCount::Argument(arg)) => { |
| 212 | + if let Ok(i) = arg.index { |
| 213 | + let sp = arguments[i].expr.span.with_ctxt(macsp.ctxt()); |
| 214 | + ecx.expr_some( |
| 215 | + sp, |
| 216 | + ecx.expr_deref( |
| 217 | + sp, |
| 218 | + ecx.expr_field( |
| 219 | + sp, |
| 220 | + ecx.expr_ident(macsp, args), |
| 221 | + Ident::new(sym::integer(i), macsp), |
| 222 | + ), |
| 223 | + ), |
| 224 | + ) |
| 225 | + } else { |
| 226 | + DummyResult::raw_expr(macsp, true) |
| 227 | + } |
| 228 | + } |
| 229 | + None => ecx.expr_none(macsp), |
| 230 | + } |
| 231 | +} |
0 commit comments