1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use codemap::{Span, respan};
16 use ext::build::AstBuilder;
18 use parse::token::InternedString;
23 use collections::{HashMap, HashSet};
40 ecx: &'a mut ExtCtxt<'a>,
43 // Parsed argument expressions and the types that we've found so far for
45 args: Vec<@ast::Expr>,
46 arg_types: Vec<Option<ArgumentType>>,
47 // Parsed named expressions and the types that we've found for them so far.
48 // Note that we keep a side-array of the ordering of the named arguments
49 // found to be sure that we can translate them in the same order that they
51 names: HashMap<~str, @ast::Expr>,
52 name_types: HashMap<~str, ArgumentType>,
53 name_ordering: Vec<~str>,
55 // Collection of the compiled `rt::Piece` structures
56 pieces: Vec<@ast::Expr> ,
57 name_positions: HashMap<~str, uint>,
58 method_statics: Vec<@ast::Item> ,
60 // Updated as arguments are consumed or methods are entered
65 /// Parses the arguments from the given list of tokens, returning None
66 /// if there's a parse error so we can continue parsing other format!
69 /// If parsing succeeds, the second return value is:
71 /// Some((fmtstr, unnamed arguments, ordering of named arguments,
73 fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
74 -> (@ast::Expr, Option<(@ast::Expr, Vec<@ast::Expr>, Vec<~str>,
75 HashMap<~str, @ast::Expr>)>) {
76 let mut args = Vec::new();
77 let mut names = HashMap::<~str, @ast::Expr>::new();
78 let mut order = Vec::new();
80 let mut p = rsparse::new_parser_from_tts(ecx.parse_sess(),
83 .map(|x| (*x).clone())
85 // Parse the leading function expression (maybe a block, maybe a path)
86 let extra = p.parse_expr();
87 if !p.eat(&token::COMMA) {
88 ecx.span_err(sp, "expected token: `,`");
92 if p.token == token::EOF {
93 ecx.span_err(sp, "requires at least a format string argument");
96 let fmtstr = p.parse_expr();
97 let mut named = false;
98 while p.token != token::EOF {
99 if !p.eat(&token::COMMA) {
100 ecx.span_err(sp, "expected token: `,`");
101 return (extra, None);
103 if p.token == token::EOF { break } // accept trailing commas
104 if named || (token::is_ident(&p.token) &&
105 p.look_ahead(1, |t| *t == token::EQ)) {
107 let ident = match p.token {
108 token::IDENT(i, _) => {
114 "expected ident, positional arguments \
115 cannot follow named arguments");
116 return (extra, None);
120 format!("expected ident for named argument, but found `{}`",
121 p.this_token_to_str()));
122 return (extra, None);
125 let interned_name = token::get_ident(ident);
126 let name = interned_name.get();
127 p.expect(&token::EQ);
128 let e = p.parse_expr();
129 match names.find_equiv(&name) {
132 ecx.span_err(e.span, format!("duplicate argument named `{}`", name));
133 ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
137 order.push(name.to_str());
138 names.insert(name.to_str(), e);
140 args.push(p.parse_expr());
143 return (extra, Some((fmtstr, args, order, names)));
146 impl<'a> Context<'a> {
147 /// Verifies one piece of a parse string. All errors are not emitted as
148 /// fatal so we can continue giving errors about this and possibly other
150 fn verify_piece(&mut self, p: &parse::Piece) {
152 parse::String(..) => {}
153 parse::CurrentArgument => {
154 if self.nest_level == 0 {
155 self.ecx.span_err(self.fmtsp,
156 "`#` reference used with nothing to \
160 parse::Argument(ref arg) => {
161 // width/precision first, if they have implicit positional
162 // parameters it makes more sense to consume them first.
163 self.verify_count(arg.format.width);
164 self.verify_count(arg.format.precision);
166 // argument second, if it's an implicit positional parameter
167 // it's written second, so it should come after width/precision.
168 let pos = match arg.position {
169 parse::ArgumentNext => {
170 let i = self.next_arg;
171 if self.check_positional_ok() {
176 parse::ArgumentIs(i) => Exact(i),
177 parse::ArgumentNamed(s) => Named(s.to_str()),
180 // and finally the method being applied
183 let ty = Known(arg.format.ty.to_str());
184 self.verify_arg_type(pos, ty);
186 Some(ref method) => { self.verify_method(pos, *method); }
192 fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
193 for piece in pieces.iter() {
194 self.verify_piece(piece);
198 fn verify_count(&mut self, c: parse::Count) {
200 parse::CountImplied | parse::CountIs(..) => {}
201 parse::CountIsParam(i) => {
202 self.verify_arg_type(Exact(i), Unsigned);
204 parse::CountIsName(s) => {
205 self.verify_arg_type(Named(s.to_str()), Unsigned);
207 parse::CountIsNextParam => {
208 if self.check_positional_ok() {
209 self.verify_arg_type(Exact(self.next_arg), Unsigned);
216 fn check_positional_ok(&mut self) -> bool {
217 if self.nest_level != 0 {
218 self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
219 arguments nested inside methods");
226 fn verify_method(&mut self, pos: Position, m: &parse::Method) {
227 self.nest_level += 1;
229 parse::Plural(_, ref arms, ref default) => {
230 let mut seen_cases = HashSet::new();
231 self.verify_arg_type(pos, Unsigned);
232 for arm in arms.iter() {
233 if !seen_cases.insert(arm.selector) {
235 parse::Keyword(name) => {
236 self.ecx.span_err(self.fmtsp,
237 format!("duplicate selector \
240 parse::Literal(idx) => {
241 self.ecx.span_err(self.fmtsp,
242 format!("duplicate selector \
247 self.verify_pieces(arm.result);
249 self.verify_pieces(*default);
251 parse::Select(ref arms, ref default) => {
252 self.verify_arg_type(pos, String);
253 let mut seen_cases = HashSet::new();
254 for arm in arms.iter() {
255 if !seen_cases.insert(arm.selector) {
256 self.ecx.span_err(self.fmtsp,
257 format!("duplicate selector `{}`",
259 } else if arm.selector == "" {
260 self.ecx.span_err(self.fmtsp,
261 "empty selector in `select`");
263 self.verify_pieces(arm.result);
265 self.verify_pieces(*default);
268 self.nest_level -= 1;
271 fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
274 if arg < 0 || self.args.len() <= arg {
275 let msg = format!("invalid reference to argument `{}` (there \
276 are {} arguments)", arg, self.args.len());
277 self.ecx.span_err(self.fmtsp, msg);
281 let arg_type = match self.arg_types.get(arg) {
283 &Some(ref x) => Some(x)
285 self.verify_same(self.args.get(arg).span, &ty, arg_type);
287 if self.arg_types.get(arg).is_none() {
288 *self.arg_types.get_mut(arg) = Some(ty);
293 let span = match self.names.find(&name) {
296 let msg = format!("there is no argument named `{}`", name);
297 self.ecx.span_err(self.fmtsp, msg);
301 self.verify_same(span, &ty, self.name_types.find(&name));
302 if !self.name_types.contains_key(&name) {
303 self.name_types.insert(name.clone(), ty);
305 // Assign this named argument a slot in the arguments array if
306 // it hasn't already been assigned a slot.
307 if !self.name_positions.contains_key(&name) {
308 let slot = self.name_positions.len();
309 self.name_positions.insert(name, slot);
315 /// When we're keeping track of the types that are declared for certain
316 /// arguments, we assume that `None` means we haven't seen this argument
317 /// yet, `Some(None)` means that we've seen the argument, but no format was
318 /// specified, and `Some(Some(x))` means that the argument was declared to
321 /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
322 /// that: `Some(None) == Some(Some(x))`
323 fn verify_same(&self,
326 before: Option<&ArgumentType>) {
327 let cur = match before {
335 (&Known(ref cur), &Known(ref ty)) => {
336 self.ecx.span_err(sp,
337 format!("argument redeclared with type `{}` when \
338 it was previously `{}`",
342 (&Known(ref cur), _) => {
343 self.ecx.span_err(sp,
344 format!("argument used to format with `{}` was \
345 attempted to not be used for formatting",
348 (_, &Known(ref ty)) => {
349 self.ecx.span_err(sp,
350 format!("argument previously used as a format \
351 argument attempted to be used as `{}`",
355 self.ecx.span_err(sp, "argument declared with multiple formats");
360 /// These attributes are applied to all statics that this syntax extension
362 fn static_attrs(&self) -> Vec<ast::Attribute> {
363 // Flag statics as `address_insignificant` so LLVM can merge duplicate
364 // globals as much as possible (which we're generating a whole lot of).
365 let unnamed = self.ecx
366 .meta_word(self.fmtsp,
368 "address_insignificant"));
369 let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
371 // Do not warn format string as dead code
372 let dead_code = self.ecx.meta_word(self.fmtsp,
373 InternedString::new("dead_code"));
374 let allow_dead_code = self.ecx.meta_list(self.fmtsp,
375 InternedString::new("allow"),
377 let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
378 return vec!(unnamed, allow_dead_code);
381 fn parsepath(&self, s: &str) -> Vec<ast::Ident> {
382 vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
383 self.ecx.ident_of("parse"), self.ecx.ident_of(s))
386 fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
387 vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
388 self.ecx.ident_of("rt"), self.ecx.ident_of(s))
391 fn ctpath(&self, s: &str) -> Vec<ast::Ident> {
392 vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
393 self.ecx.ident_of("parse"), self.ecx.ident_of(s))
396 fn none(&self) -> @ast::Expr {
397 let none = self.ecx.path_global(self.fmtsp, vec!(
398 self.ecx.ident_of("std"),
399 self.ecx.ident_of("option"),
400 self.ecx.ident_of("None")));
401 self.ecx.expr_path(none)
404 fn some(&self, e: @ast::Expr) -> @ast::Expr {
405 let p = self.ecx.path_global(self.fmtsp, vec!(
406 self.ecx.ident_of("std"),
407 self.ecx.ident_of("option"),
408 self.ecx.ident_of("Some")));
409 let p = self.ecx.expr_path(p);
410 self.ecx.expr_call(self.fmtsp, p, vec!(e))
413 fn trans_count(&self, c: parse::Count) -> @ast::Expr {
416 parse::CountIs(i) => {
417 self.ecx.expr_call_global(sp, self.rtpath("CountIs"),
418 vec!(self.ecx.expr_uint(sp, i)))
420 parse::CountIsParam(i) => {
421 self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
422 vec!(self.ecx.expr_uint(sp, i)))
424 parse::CountImplied => {
425 let path = self.ecx.path_global(sp, self.rtpath("CountImplied"));
426 self.ecx.expr_path(path)
428 parse::CountIsNextParam => {
429 let path = self.ecx.path_global(sp, self.rtpath("CountIsNextParam"));
430 self.ecx.expr_path(path)
432 parse::CountIsName(n) => {
433 let i = match self.name_positions.find_equiv(&n) {
435 None => 0, // error already emitted elsewhere
437 let i = i + self.args.len();
438 self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
439 vec!(self.ecx.expr_uint(sp, i)))
444 fn trans_method(&mut self, method: &parse::Method) -> @ast::Expr {
446 let method = match *method {
447 parse::Select(ref arms, ref default) => {
448 let arms = arms.iter().map(|arm| {
449 let p = self.ecx.path_global(sp, self.rtpath("SelectArm"));
450 let result = arm.result.iter().map(|p| {
453 let s = token::intern_and_get_ident(arm.selector);
454 let selector = self.ecx.expr_str(sp, s);
455 self.ecx.expr_struct(sp, p, vec!(
456 self.ecx.field_imm(sp,
457 self.ecx.ident_of("selector"),
459 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
460 self.ecx.expr_vec_slice(sp, result))))
462 let default = default.iter().map(|p| {
465 self.ecx.expr_call_global(sp, self.rtpath("Select"), vec!(
466 self.ecx.expr_vec_slice(sp, arms),
467 self.ecx.expr_vec_slice(sp, default)))
469 parse::Plural(offset, ref arms, ref default) => {
470 let offset = match offset {
471 Some(i) => { self.some(self.ecx.expr_uint(sp, i)) }
472 None => { self.none() }
474 let arms = arms.iter().map(|arm| {
475 let p = self.ecx.path_global(sp, self.rtpath("PluralArm"));
476 let result = arm.result.iter().map(|p| {
479 let (lr, selarg) = match arm.selector {
480 parse::Keyword(t) => {
481 let p = self.ctpath(format!("{:?}", t));
482 let p = self.ecx.path_global(sp, p);
483 (self.rtpath("Keyword"), self.ecx.expr_path(p))
485 parse::Literal(i) => {
486 (self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
489 let selector = self.ecx.expr_call_global(sp,
491 self.ecx.expr_struct(sp, p, vec!(
492 self.ecx.field_imm(sp,
493 self.ecx.ident_of("selector"),
495 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
496 self.ecx.expr_vec_slice(sp, result))))
498 let default = default.iter().map(|p| {
501 self.ecx.expr_call_global(sp, self.rtpath("Plural"), vec!(
503 self.ecx.expr_vec_slice(sp, arms),
504 self.ecx.expr_vec_slice(sp, default)))
507 let life = self.ecx.lifetime(sp, self.ecx.ident_of("static").name);
508 let ty = self.ecx.ty_path(self.ecx.path_all(
511 self.rtpath("Method"),
515 let st = ast::ItemStatic(ty, ast::MutImmutable, method);
516 let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
517 self.method_statics.len()));
518 let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
519 self.method_statics.push(item);
520 self.ecx.expr_ident(sp, static_name)
523 /// Translate a `parse::Piece` to a static `rt::Piece`
524 fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
527 parse::String(s) => {
528 let s = token::intern_and_get_ident(s);
529 self.ecx.expr_call_global(sp,
530 self.rtpath("String"),
532 self.ecx.expr_str(sp, s)
535 parse::CurrentArgument => {
536 let nil = self.ecx.expr_lit(sp, ast::LitNil);
537 self.ecx.expr_call_global(sp, self.rtpath("CurrentArgument"), vec!(nil))
539 parse::Argument(ref arg) => {
540 // Translate the position
541 let pos = match arg.position {
542 // These two have a direct mapping
543 parse::ArgumentNext => {
544 let path = self.ecx.path_global(sp,
545 self.rtpath("ArgumentNext"));
546 self.ecx.expr_path(path)
548 parse::ArgumentIs(i) => {
549 self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
550 vec!(self.ecx.expr_uint(sp, i)))
552 // Named arguments are converted to positional arguments at
553 // the end of the list of arguments
554 parse::ArgumentNamed(n) => {
555 let i = match self.name_positions.find_equiv(&n) {
557 None => 0, // error already emitted elsewhere
559 let i = i + self.args.len();
560 self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
561 vec!(self.ecx.expr_uint(sp, i)))
565 // Translate the format
566 let fill = match arg.format.fill { Some(c) => c, None => ' ' };
567 let fill = self.ecx.expr_lit(sp, ast::LitChar(fill as u32));
568 let align = match arg.format.align {
569 parse::AlignLeft => {
570 self.ecx.path_global(sp, self.parsepath("AlignLeft"))
572 parse::AlignRight => {
573 self.ecx.path_global(sp, self.parsepath("AlignRight"))
575 parse::AlignUnknown => {
576 self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
579 let align = self.ecx.expr_path(align);
580 let flags = self.ecx.expr_uint(sp, arg.format.flags);
581 let prec = self.trans_count(arg.format.precision);
582 let width = self.trans_count(arg.format.width);
583 let path = self.ecx.path_global(sp, self.rtpath("FormatSpec"));
584 let fmt = self.ecx.expr_struct(sp, path, vec!(
585 self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
586 self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
587 self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
588 self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
589 self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
591 // Translate the method (if any)
592 let method = match arg.method {
593 None => { self.none() }
595 let m = self.trans_method(*m);
596 self.some(self.ecx.expr_addr_of(sp, m))
599 let path = self.ecx.path_global(sp, self.rtpath("Argument"));
600 let s = self.ecx.expr_struct(sp, path, vec!(
601 self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
602 self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
603 self.ecx.field_imm(sp, self.ecx.ident_of("method"), method)));
604 self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))
609 /// Actually builds the expression which the iformat! block will be expanded
611 fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
612 let mut lets = Vec::new();
613 let mut locals = Vec::new();
614 let mut names = vec::from_fn(self.name_positions.len(), |_| None);
615 let mut pats = Vec::new();
616 let mut heads = Vec::new();
618 // First, declare all of our methods that are statics
619 for &method in self.method_statics.iter() {
620 let decl = respan(self.fmtsp, ast::DeclItem(method));
621 lets.push(@respan(self.fmtsp,
622 ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
625 // Next, build up the static array which will become our precompiled
627 let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
628 let piece_ty = self.ecx.ty_path(self.ecx.path_all(
631 self.ecx.ident_of("std"),
632 self.ecx.ident_of("fmt"),
633 self.ecx.ident_of("rt"),
634 self.ecx.ident_of("Piece")),
636 self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static").name)),
639 let ty = ast::TyFixedLengthVec(
641 self.ecx.expr_uint(self.fmtsp, self.pieces.len())
643 let ty = self.ecx.ty(self.fmtsp, ty);
644 let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
645 let static_name = self.ecx.ident_of("__STATIC_FMTSTR");
646 let item = self.ecx.item(self.fmtsp, static_name,
647 self.static_attrs(), st);
648 let decl = respan(self.fmtsp, ast::DeclItem(item));
649 lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
651 // Right now there is a bug such that for the expression:
653 // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
654 // vald for the call to `foo`. To work around this all arguments to the
655 // format! string are shoved into locals. Furthermore, we shove the address
656 // of each variable because we don't want to move out of the arguments
657 // passed to this function.
658 for (i, &e) in self.args.iter().enumerate() {
659 if self.arg_types.get(i).is_none() {
660 continue // error already generated
663 let name = self.ecx.ident_of(format!("__arg{}", i));
664 pats.push(self.ecx.pat_ident(e.span, name));
665 heads.push(self.ecx.expr_addr_of(e.span, e));
666 locals.push(self.format_arg(e.span, Exact(i),
667 self.ecx.expr_ident(e.span, name)));
669 for name in self.name_ordering.iter() {
670 let e = match self.names.find(name) {
671 Some(&e) if self.name_types.contains_key(name) => e,
672 Some(..) | None => continue
675 let lname = self.ecx.ident_of(format!("__arg{}", *name));
676 pats.push(self.ecx.pat_ident(e.span, lname));
677 heads.push(self.ecx.expr_addr_of(e.span, e));
678 names[*self.name_positions.get(name)] =
679 Some(self.format_arg(e.span,
680 Named((*name).clone()),
681 self.ecx.expr_ident(e.span, lname)));
684 // Now create a vector containing all the arguments
685 let slicename = self.ecx.ident_of("__args_vec");
687 let args = names.move_iter().map(|a| a.unwrap());
688 let mut args = locals.move_iter().chain(args);
689 let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
690 lets.push(self.ecx.stmt_let(self.fmtsp, false, slicename, args));
693 // Now create the fmt::Arguments struct with all our locals we created.
694 let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
695 let args_slice = self.ecx.expr_ident(self.fmtsp, slicename);
696 let result = self.ecx.expr_call_global(self.fmtsp, vec!(
697 self.ecx.ident_of("std"),
698 self.ecx.ident_of("fmt"),
699 self.ecx.ident_of("Arguments"),
700 self.ecx.ident_of("new")), vec!(fmt, args_slice));
702 // We did all the work of making sure that the arguments
703 // structure is safe, so we can safely have an unsafe block.
704 let result = self.ecx.expr_block(P(ast::Block {
705 view_items: Vec::new(),
708 id: ast::DUMMY_NODE_ID,
709 rules: ast::UnsafeBlock(ast::CompilerGenerated),
712 let resname = self.ecx.ident_of("__args");
713 lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
714 let res = self.ecx.expr_ident(self.fmtsp, resname);
715 let result = self.ecx.expr_call(extra.span, extra, vec!(
716 self.ecx.expr_addr_of(extra.span, res)));
717 let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
720 // Constructs an AST equivalent to:
722 // match (&arg0, &arg1) {
723 // (tmp0, tmp1) => body
732 // Because of #11585 the new temporary lifetime rule, the enclosing
733 // statements for these temporaries become the let's themselves.
734 // If one or more of them are RefCell's, RefCell borrow() will also
735 // end there; they don't last long enough for body to use them. The
736 // match expression solves the scope problem.
738 // Note, it may also very well be transformed to:
743 // ref tmp1 => body } } }
745 // But the nested match expression is proved to perform not as well
746 // as series of let's; the first approach does.
747 let pat = self.ecx.pat(self.fmtsp, ast::PatTup(pats));
748 let arm = self.ecx.arm(self.fmtsp, vec!(pat), body);
749 let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
750 self.ecx.expr_match(self.fmtsp, head, vec!(arm))
753 fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
755 let ty = match argno {
756 Exact(ref i) => self.arg_types.get(*i).get_ref(),
757 Named(ref s) => self.name_types.get(s)
760 let fmt_fn = match *ty {
761 Known(ref tyname) => {
762 match tyname.as_slice() {
764 "?" => "secret_poly",
765 "b" => "secret_bool",
766 "c" => "secret_char",
767 "d" | "i" => "secret_signed",
768 "e" => "secret_lower_exp",
769 "E" => "secret_upper_exp",
770 "f" => "secret_float",
771 "o" => "secret_octal",
772 "p" => "secret_pointer",
773 "s" => "secret_string",
774 "t" => "secret_binary",
775 "u" => "secret_unsigned",
776 "x" => "secret_lower_hex",
777 "X" => "secret_upper_hex",
779 self.ecx.span_err(sp, format!("unknown format trait `{}`",
786 return self.ecx.expr_call_global(sp, vec!(
787 self.ecx.ident_of("std"),
788 self.ecx.ident_of("fmt"),
789 self.ecx.ident_of("argumentstr")), vec!(arg))
792 return self.ecx.expr_call_global(sp, vec!(
793 self.ecx.ident_of("std"),
794 self.ecx.ident_of("fmt"),
795 self.ecx.ident_of("argumentuint")), vec!(arg))
799 let format_fn = self.ecx.path_global(sp, vec!(
800 self.ecx.ident_of("std"),
801 self.ecx.ident_of("fmt"),
802 self.ecx.ident_of(fmt_fn)));
803 self.ecx.expr_call_global(sp, vec!(
804 self.ecx.ident_of("std"),
805 self.ecx.ident_of("fmt"),
806 self.ecx.ident_of("argument")), vec!(self.ecx.expr_path(format_fn), arg))
810 pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
811 tts: &[ast::TokenTree]) -> base::MacResult {
813 match parse_args(ecx, sp, tts) {
814 (extra, Some((efmt, args, order, names))) => {
815 MRExpr(expand_preparsed_format_args(ecx, sp, extra, efmt, args,
818 (_, None) => MRExpr(ecx.expr_uint(sp, 2))
822 /// Take the various parts of `format_args!(extra, efmt, args...,
823 /// name=names...)` and construct the appropriate formatting
825 pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
827 efmt: @ast::Expr, args: Vec<@ast::Expr>,
828 name_ordering: Vec<~str>,
829 names: HashMap<~str, @ast::Expr>) -> @ast::Expr {
830 let arg_types = Vec::from_fn(args.len(), |_| None);
831 let mut cx = Context {
834 arg_types: arg_types,
836 name_positions: HashMap::new(),
837 name_types: HashMap::new(),
838 name_ordering: name_ordering,
842 method_statics: Vec::new(),
845 cx.fmtsp = efmt.span;
846 // Be sure to recursively expand macros just in case the format string uses
847 // a macro to build the format expression.
848 let expr = cx.ecx.expand_expr(efmt);
849 let fmt = match expr_to_str(cx.ecx,
851 "format argument must be a string literal.") {
852 Some((fmt, _)) => fmt,
853 None => return MacResult::raw_dummy_expr(sp)
856 let mut parser = parse::Parser::new(fmt.get());
858 match parser.next() {
860 if parser.errors.len() > 0 { break }
861 cx.verify_piece(&piece);
862 let piece = cx.trans_piece(&piece);
863 cx.pieces.push(piece);
868 match parser.errors.shift() {
870 cx.ecx.span_err(efmt.span, "invalid format string: " + error);
871 return MacResult::raw_dummy_expr(sp);
876 // Make sure that all arguments were used and all arguments have types.
877 for (i, ty) in cx.arg_types.iter().enumerate() {
879 cx.ecx.span_err(cx.args.get(i).span, "argument never used");
882 for (name, e) in cx.names.iter() {
883 if !cx.name_types.contains_key(name) {
884 cx.ecx.span_err(e.span, "named argument never used");