]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/format.rs
libfmt_macros: Remove all uses of `~str` from `libfmt_macros`
[rust.git] / src / libsyntax / ext / format.rs
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.
4 //
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.
10
11 use ast;
12 use ast::P;
13 use codemap::{Span, respan};
14 use ext::base::*;
15 use ext::base;
16 use ext::build::AstBuilder;
17 use parse::token::InternedString;
18 use parse::token;
19 use rsparse = parse;
20
21 use parse = fmt_macros;
22 use collections::{HashMap, HashSet};
23
24 #[deriving(Eq)]
25 enum ArgumentType {
26     Known(StrBuf),
27     Unsigned,
28     String,
29 }
30
31 enum Position {
32     Exact(uint),
33     Named(StrBuf),
34 }
35
36 struct Context<'a, 'b> {
37     ecx: &'a mut ExtCtxt<'b>,
38     fmtsp: Span,
39
40     // Parsed argument expressions and the types that we've found so far for
41     // them.
42     args: Vec<@ast::Expr>,
43     arg_types: Vec<Option<ArgumentType>>,
44     // Parsed named expressions and the types that we've found for them so far.
45     // Note that we keep a side-array of the ordering of the named arguments
46     // found to be sure that we can translate them in the same order that they
47     // were declared in.
48     names: HashMap<StrBuf, @ast::Expr>,
49     name_types: HashMap<StrBuf, ArgumentType>,
50     name_ordering: Vec<StrBuf>,
51
52     // Collection of the compiled `rt::Piece` structures
53     pieces: Vec<@ast::Expr> ,
54     name_positions: HashMap<StrBuf, uint>,
55     method_statics: Vec<@ast::Item> ,
56
57     // Updated as arguments are consumed or methods are entered
58     nest_level: uint,
59     next_arg: uint,
60 }
61
62 pub enum Invocation {
63     Call(@ast::Expr),
64     MethodCall(@ast::Expr, ast::Ident),
65 }
66
67 /// Parses the arguments from the given list of tokens, returning None
68 /// if there's a parse error so we can continue parsing other format!
69 /// expressions.
70 ///
71 /// If parsing succeeds, the second return value is:
72 ///
73 ///     Some((fmtstr, unnamed arguments, ordering of named arguments,
74 ///           named arguments))
75 fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool,
76               tts: &[ast::TokenTree])
77     -> (Invocation, Option<(@ast::Expr, Vec<@ast::Expr>, Vec<StrBuf>,
78                             HashMap<StrBuf, @ast::Expr>)>) {
79     let mut args = Vec::new();
80     let mut names = HashMap::<StrBuf, @ast::Expr>::new();
81     let mut order = Vec::new();
82
83     let mut p = rsparse::new_parser_from_tts(ecx.parse_sess(),
84                                              ecx.cfg(),
85                                              tts.iter()
86                                                 .map(|x| (*x).clone())
87                                                 .collect());
88     // Parse the leading function expression (maybe a block, maybe a path)
89     let invocation = if allow_method {
90         let e = p.parse_expr();
91         if !p.eat(&token::COMMA) {
92             ecx.span_err(sp, "expected token: `,`");
93             return (Call(e), None);
94         }
95         MethodCall(e, p.parse_ident())
96     } else {
97         Call(p.parse_expr())
98     };
99     if !p.eat(&token::COMMA) {
100         ecx.span_err(sp, "expected token: `,`");
101         return (invocation, None);
102     }
103
104     if p.token == token::EOF {
105         ecx.span_err(sp, "requires at least a format string argument");
106         return (invocation, None);
107     }
108     let fmtstr = p.parse_expr();
109     let mut named = false;
110     while p.token != token::EOF {
111         if !p.eat(&token::COMMA) {
112             ecx.span_err(sp, "expected token: `,`");
113             return (invocation, None);
114         }
115         if p.token == token::EOF { break } // accept trailing commas
116         if named || (token::is_ident(&p.token) &&
117                      p.look_ahead(1, |t| *t == token::EQ)) {
118             named = true;
119             let ident = match p.token {
120                 token::IDENT(i, _) => {
121                     p.bump();
122                     i
123                 }
124                 _ if named => {
125                     ecx.span_err(p.span,
126                                  "expected ident, positional arguments \
127                                  cannot follow named arguments");
128                     return (invocation, None);
129                 }
130                 _ => {
131                     ecx.span_err(p.span,
132                                  format!("expected ident for named argument, but found `{}`",
133                                          p.this_token_to_str()));
134                     return (invocation, None);
135                 }
136             };
137             let interned_name = token::get_ident(ident);
138             let name = interned_name.get();
139             p.expect(&token::EQ);
140             let e = p.parse_expr();
141             match names.find_equiv(&name) {
142                 None => {}
143                 Some(prev) => {
144                     ecx.span_err(e.span, format!("duplicate argument named `{}`", name));
145                     ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
146                     continue
147                 }
148             }
149             order.push(name.to_strbuf());
150             names.insert(name.to_strbuf(), e);
151         } else {
152             args.push(p.parse_expr());
153         }
154     }
155     return (invocation, Some((fmtstr, args, order, names)));
156 }
157
158 impl<'a, 'b> Context<'a, 'b> {
159     /// Verifies one piece of a parse string. All errors are not emitted as
160     /// fatal so we can continue giving errors about this and possibly other
161     /// format strings.
162     fn verify_piece(&mut self, p: &parse::Piece) {
163         match *p {
164             parse::String(..) => {}
165             parse::CurrentArgument => {
166                 if self.nest_level == 0 {
167                     self.ecx.span_err(self.fmtsp,
168                                       "`#` reference used with nothing to \
169                                        reference back to");
170                 }
171             }
172             parse::Argument(ref arg) => {
173                 // width/precision first, if they have implicit positional
174                 // parameters it makes more sense to consume them first.
175                 self.verify_count(arg.format.width);
176                 self.verify_count(arg.format.precision);
177
178                 // argument second, if it's an implicit positional parameter
179                 // it's written second, so it should come after width/precision.
180                 let pos = match arg.position {
181                     parse::ArgumentNext => {
182                         let i = self.next_arg;
183                         if self.check_positional_ok() {
184                             self.next_arg += 1;
185                         }
186                         Exact(i)
187                     }
188                     parse::ArgumentIs(i) => Exact(i),
189                     parse::ArgumentNamed(s) => Named(s.to_strbuf()),
190                 };
191
192                 // and finally the method being applied
193                 match arg.method {
194                     None => {
195                         let ty = Known(arg.format.ty.to_strbuf());
196                         self.verify_arg_type(pos, ty);
197                     }
198                     Some(ref method) => { self.verify_method(pos, *method); }
199                 }
200             }
201         }
202     }
203
204     fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
205         for piece in pieces.iter() {
206             self.verify_piece(piece);
207         }
208     }
209
210     fn verify_count(&mut self, c: parse::Count) {
211         match c {
212             parse::CountImplied | parse::CountIs(..) => {}
213             parse::CountIsParam(i) => {
214                 self.verify_arg_type(Exact(i), Unsigned);
215             }
216             parse::CountIsName(s) => {
217                 self.verify_arg_type(Named(s.to_strbuf()), Unsigned);
218             }
219             parse::CountIsNextParam => {
220                 if self.check_positional_ok() {
221                     self.verify_arg_type(Exact(self.next_arg), Unsigned);
222                     self.next_arg += 1;
223                 }
224             }
225         }
226     }
227
228     fn check_positional_ok(&mut self) -> bool {
229         if self.nest_level != 0 {
230             self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
231                                            arguments nested inside methods");
232             false
233         } else {
234             true
235         }
236     }
237
238     fn verify_method(&mut self, pos: Position, m: &parse::Method) {
239         self.nest_level += 1;
240         match *m {
241             parse::Plural(_, ref arms, ref default) => {
242                 let mut seen_cases = HashSet::new();
243                 self.verify_arg_type(pos, Unsigned);
244                 for arm in arms.iter() {
245                     if !seen_cases.insert(arm.selector) {
246                         match arm.selector {
247                             parse::Keyword(name) => {
248                                 self.ecx.span_err(self.fmtsp,
249                                                   format!("duplicate selector \
250                                                            `{}`", name));
251                             }
252                             parse::Literal(idx) => {
253                                 self.ecx.span_err(self.fmtsp,
254                                                   format!("duplicate selector \
255                                                            `={}`", idx));
256                             }
257                         }
258                     }
259                     self.verify_pieces(arm.result.as_slice());
260                 }
261                 self.verify_pieces(default.as_slice());
262             }
263             parse::Select(ref arms, ref default) => {
264                 self.verify_arg_type(pos, String);
265                 let mut seen_cases = HashSet::new();
266                 for arm in arms.iter() {
267                     if !seen_cases.insert(arm.selector) {
268                         self.ecx.span_err(self.fmtsp,
269                                           format!("duplicate selector `{}`",
270                                                arm.selector));
271                     } else if arm.selector == "" {
272                         self.ecx.span_err(self.fmtsp,
273                                           "empty selector in `select`");
274                     }
275                     self.verify_pieces(arm.result.as_slice());
276                 }
277                 self.verify_pieces(default.as_slice());
278             }
279         }
280         self.nest_level -= 1;
281     }
282
283     fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
284         match arg {
285             Exact(arg) => {
286                 if self.args.len() <= arg {
287                     let msg = format!("invalid reference to argument `{}` (there \
288                                     are {} arguments)", arg, self.args.len());
289                     self.ecx.span_err(self.fmtsp, msg);
290                     return;
291                 }
292                 {
293                     let arg_type = match self.arg_types.get(arg) {
294                         &None => None,
295                         &Some(ref x) => Some(x)
296                     };
297                     self.verify_same(self.args.get(arg).span, &ty, arg_type);
298                 }
299                 if self.arg_types.get(arg).is_none() {
300                     *self.arg_types.get_mut(arg) = Some(ty);
301                 }
302             }
303
304             Named(name) => {
305                 let span = match self.names.find(&name) {
306                     Some(e) => e.span,
307                     None => {
308                         let msg = format!("there is no argument named `{}`", name);
309                         self.ecx.span_err(self.fmtsp, msg);
310                         return;
311                     }
312                 };
313                 self.verify_same(span, &ty, self.name_types.find(&name));
314                 if !self.name_types.contains_key(&name) {
315                     self.name_types.insert(name.clone(), ty);
316                 }
317                 // Assign this named argument a slot in the arguments array if
318                 // it hasn't already been assigned a slot.
319                 if !self.name_positions.contains_key(&name) {
320                     let slot = self.name_positions.len();
321                     self.name_positions.insert(name, slot);
322                 }
323             }
324         }
325     }
326
327     /// When we're keeping track of the types that are declared for certain
328     /// arguments, we assume that `None` means we haven't seen this argument
329     /// yet, `Some(None)` means that we've seen the argument, but no format was
330     /// specified, and `Some(Some(x))` means that the argument was declared to
331     /// have type `x`.
332     ///
333     /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
334     /// that: `Some(None) == Some(Some(x))`
335     fn verify_same(&self,
336                    sp: Span,
337                    ty: &ArgumentType,
338                    before: Option<&ArgumentType>) {
339         let cur = match before {
340             None => return,
341             Some(t) => t,
342         };
343         if *ty == *cur {
344             return
345         }
346         match (cur, ty) {
347             (&Known(ref cur), &Known(ref ty)) => {
348                 self.ecx.span_err(sp,
349                                   format!("argument redeclared with type `{}` when \
350                                            it was previously `{}`",
351                                           *ty,
352                                           *cur));
353             }
354             (&Known(ref cur), _) => {
355                 self.ecx.span_err(sp,
356                                   format!("argument used to format with `{}` was \
357                                            attempted to not be used for formatting",
358                                            *cur));
359             }
360             (_, &Known(ref ty)) => {
361                 self.ecx.span_err(sp,
362                                   format!("argument previously used as a format \
363                                            argument attempted to be used as `{}`",
364                                            *ty));
365             }
366             (_, _) => {
367                 self.ecx.span_err(sp, "argument declared with multiple formats");
368             }
369         }
370     }
371
372     /// These attributes are applied to all statics that this syntax extension
373     /// will generate.
374     fn static_attrs(&self) -> Vec<ast::Attribute> {
375         // Flag statics as `address_insignificant` so LLVM can merge duplicate
376         // globals as much as possible (which we're generating a whole lot of).
377         let unnamed = self.ecx
378                           .meta_word(self.fmtsp,
379                                      InternedString::new(
380                                          "address_insignificant"));
381         let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
382
383         // Do not warn format string as dead code
384         let dead_code = self.ecx.meta_word(self.fmtsp,
385                                            InternedString::new("dead_code"));
386         let allow_dead_code = self.ecx.meta_list(self.fmtsp,
387                                                  InternedString::new("allow"),
388                                                  vec!(dead_code));
389         let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
390         return vec!(unnamed, allow_dead_code);
391     }
392
393     fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
394         vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
395           self.ecx.ident_of("rt"), self.ecx.ident_of(s))
396     }
397
398     fn none(&self) -> @ast::Expr {
399         let none = self.ecx.path_global(self.fmtsp, vec!(
400                 self.ecx.ident_of("std"),
401                 self.ecx.ident_of("option"),
402                 self.ecx.ident_of("None")));
403         self.ecx.expr_path(none)
404     }
405
406     fn some(&self, e: @ast::Expr) -> @ast::Expr {
407         let p = self.ecx.path_global(self.fmtsp, vec!(
408                 self.ecx.ident_of("std"),
409                 self.ecx.ident_of("option"),
410                 self.ecx.ident_of("Some")));
411         let p = self.ecx.expr_path(p);
412         self.ecx.expr_call(self.fmtsp, p, vec!(e))
413     }
414
415     fn trans_count(&self, c: parse::Count) -> @ast::Expr {
416         let sp = self.fmtsp;
417         match c {
418             parse::CountIs(i) => {
419                 self.ecx.expr_call_global(sp, self.rtpath("CountIs"),
420                                           vec!(self.ecx.expr_uint(sp, i)))
421             }
422             parse::CountIsParam(i) => {
423                 self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
424                                           vec!(self.ecx.expr_uint(sp, i)))
425             }
426             parse::CountImplied => {
427                 let path = self.ecx.path_global(sp, self.rtpath("CountImplied"));
428                 self.ecx.expr_path(path)
429             }
430             parse::CountIsNextParam => {
431                 let path = self.ecx.path_global(sp, self.rtpath("CountIsNextParam"));
432                 self.ecx.expr_path(path)
433             }
434             parse::CountIsName(n) => {
435                 let i = match self.name_positions.find_equiv(&n) {
436                     Some(&i) => i,
437                     None => 0, // error already emitted elsewhere
438                 };
439                 let i = i + self.args.len();
440                 self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
441                                           vec!(self.ecx.expr_uint(sp, i)))
442             }
443         }
444     }
445
446     fn trans_method(&mut self, method: &parse::Method) -> @ast::Expr {
447         let sp = self.fmtsp;
448         let method = match *method {
449             parse::Select(ref arms, ref default) => {
450                 let arms = arms.iter().map(|arm| {
451                         let p = self.ecx.path_global(sp, self.rtpath("SelectArm"));
452                         let result = arm.result.iter().map(|p| {
453                             self.trans_piece(p)
454                         }).collect();
455                         let s = token::intern_and_get_ident(arm.selector);
456                         let selector = self.ecx.expr_str(sp, s);
457                         self.ecx.expr_struct(sp, p, vec!(
458                                 self.ecx.field_imm(sp,
459                                                    self.ecx.ident_of("selector"),
460                                                    selector),
461                                 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
462                                                    self.ecx.expr_vec_slice(sp, result))))
463                     }).collect();
464                 let default = default.iter().map(|p| {
465                         self.trans_piece(p)
466                     }).collect();
467                 self.ecx.expr_call_global(sp, self.rtpath("Select"), vec!(
468                         self.ecx.expr_vec_slice(sp, arms),
469                         self.ecx.expr_vec_slice(sp, default)))
470             }
471             parse::Plural(offset, ref arms, ref default) => {
472                 let offset = match offset {
473                     Some(i) => { self.some(self.ecx.expr_uint(sp, i)) }
474                     None => { self.none() }
475                 };
476                 let arms = arms.iter().map(|arm| {
477                         let p = self.ecx.path_global(sp, self.rtpath("PluralArm"));
478                         let result = arm.result.iter().map(|p| {
479                                 self.trans_piece(p)
480                             }).collect();
481                         let (lr, selarg) = match arm.selector {
482                             parse::Keyword(t) => {
483                                 let p = self.rtpath(t.to_str());
484                                 let p = self.ecx.path_global(sp, p);
485                                 (self.rtpath("Keyword"), self.ecx.expr_path(p))
486                             }
487                             parse::Literal(i) => {
488                                 (self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
489                             }
490                         };
491                         let selector = self.ecx.expr_call_global(sp,
492                                                                  lr, vec!(selarg));
493                         self.ecx.expr_struct(sp, p, vec!(
494                                 self.ecx.field_imm(sp,
495                                                    self.ecx.ident_of("selector"),
496                                                    selector),
497                                 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
498                                                    self.ecx.expr_vec_slice(sp, result))))
499                     }).collect();
500                 let default = default.iter().map(|p| {
501                         self.trans_piece(p)
502                     }).collect();
503                 self.ecx.expr_call_global(sp, self.rtpath("Plural"), vec!(
504                         offset,
505                         self.ecx.expr_vec_slice(sp, arms),
506                         self.ecx.expr_vec_slice(sp, default)))
507             }
508         };
509         let life = self.ecx.lifetime(sp, self.ecx.ident_of("static").name);
510         let ty = self.ecx.ty_path(self.ecx.path_all(
511                 sp,
512                 true,
513                 self.rtpath("Method"),
514                 vec!(life),
515                 Vec::new()
516                     ), None);
517         let st = ast::ItemStatic(ty, ast::MutImmutable, method);
518         let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
519                                                     self.method_statics.len()));
520         let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
521         self.method_statics.push(item);
522         self.ecx.expr_ident(sp, static_name)
523     }
524
525     /// Translate a `parse::Piece` to a static `rt::Piece`
526     fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
527         let sp = self.fmtsp;
528         match *piece {
529             parse::String(s) => {
530                 let s = token::intern_and_get_ident(s);
531                 self.ecx.expr_call_global(sp,
532                                           self.rtpath("String"),
533                                           vec!(
534                     self.ecx.expr_str(sp, s)
535                 ))
536             }
537             parse::CurrentArgument => {
538                 let nil = self.ecx.expr_lit(sp, ast::LitNil);
539                 self.ecx.expr_call_global(sp, self.rtpath("CurrentArgument"), vec!(nil))
540             }
541             parse::Argument(ref arg) => {
542                 // Translate the position
543                 let pos = match arg.position {
544                     // These two have a direct mapping
545                     parse::ArgumentNext => {
546                         let path = self.ecx.path_global(sp,
547                                                         self.rtpath("ArgumentNext"));
548                         self.ecx.expr_path(path)
549                     }
550                     parse::ArgumentIs(i) => {
551                         self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
552                                                   vec!(self.ecx.expr_uint(sp, i)))
553                     }
554                     // Named arguments are converted to positional arguments at
555                     // the end of the list of arguments
556                     parse::ArgumentNamed(n) => {
557                         let i = match self.name_positions.find_equiv(&n) {
558                             Some(&i) => i,
559                             None => 0, // error already emitted elsewhere
560                         };
561                         let i = i + self.args.len();
562                         self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
563                                                   vec!(self.ecx.expr_uint(sp, i)))
564                     }
565                 };
566
567                 // Translate the format
568                 let fill = match arg.format.fill { Some(c) => c, None => ' ' };
569                 let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
570                 let align = match arg.format.align {
571                     parse::AlignLeft => {
572                         self.ecx.path_global(sp, self.rtpath("AlignLeft"))
573                     }
574                     parse::AlignRight => {
575                         self.ecx.path_global(sp, self.rtpath("AlignRight"))
576                     }
577                     parse::AlignUnknown => {
578                         self.ecx.path_global(sp, self.rtpath("AlignUnknown"))
579                     }
580                 };
581                 let align = self.ecx.expr_path(align);
582                 let flags = self.ecx.expr_uint(sp, arg.format.flags);
583                 let prec = self.trans_count(arg.format.precision);
584                 let width = self.trans_count(arg.format.width);
585                 let path = self.ecx.path_global(sp, self.rtpath("FormatSpec"));
586                 let fmt = self.ecx.expr_struct(sp, path, vec!(
587                     self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
588                     self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
589                     self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
590                     self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
591                     self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
592
593                 // Translate the method (if any)
594                 let method = match arg.method {
595                     None => { self.none() }
596                     Some(ref m) => {
597                         let m = self.trans_method(*m);
598                         self.some(self.ecx.expr_addr_of(sp, m))
599                     }
600                 };
601                 let path = self.ecx.path_global(sp, self.rtpath("Argument"));
602                 let s = self.ecx.expr_struct(sp, path, vec!(
603                     self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
604                     self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
605                     self.ecx.field_imm(sp, self.ecx.ident_of("method"), method)));
606                 self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))
607             }
608         }
609     }
610
611     /// Actually builds the expression which the iformat! block will be expanded
612     /// to
613     fn to_expr(&self, invocation: Invocation) -> @ast::Expr {
614         let mut lets = Vec::new();
615         let mut locals = Vec::new();
616         let mut names = Vec::from_fn(self.name_positions.len(), |_| None);
617         let mut pats = Vec::new();
618         let mut heads = Vec::new();
619
620         // First, declare all of our methods that are statics
621         for &method in self.method_statics.iter() {
622             let decl = respan(self.fmtsp, ast::DeclItem(method));
623             lets.push(@respan(self.fmtsp,
624                               ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
625         }
626
627         // Next, build up the static array which will become our precompiled
628         // format "string"
629         let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
630         let piece_ty = self.ecx.ty_path(self.ecx.path_all(
631                 self.fmtsp,
632                 true, vec!(
633                     self.ecx.ident_of("std"),
634                     self.ecx.ident_of("fmt"),
635                     self.ecx.ident_of("rt"),
636                     self.ecx.ident_of("Piece")),
637                 vec!(self.ecx.lifetime(self.fmtsp,
638                                        self.ecx.ident_of("static").name)),
639                 Vec::new()
640             ), None);
641         let ty = ast::TyFixedLengthVec(
642             piece_ty,
643             self.ecx.expr_uint(self.fmtsp, self.pieces.len())
644         );
645         let ty = self.ecx.ty(self.fmtsp, ty);
646         let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
647         let static_name = self.ecx.ident_of("__STATIC_FMTSTR");
648         let item = self.ecx.item(self.fmtsp, static_name,
649                                  self.static_attrs(), st);
650         let decl = respan(self.fmtsp, ast::DeclItem(item));
651         lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
652
653         // Right now there is a bug such that for the expression:
654         //      foo(bar(&1))
655         // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
656         // vald for the call to `foo`. To work around this all arguments to the
657         // format! string are shoved into locals. Furthermore, we shove the address
658         // of each variable because we don't want to move out of the arguments
659         // passed to this function.
660         for (i, &e) in self.args.iter().enumerate() {
661             if self.arg_types.get(i).is_none() {
662                 continue // error already generated
663             }
664
665             let name = self.ecx.ident_of(format!("__arg{}", i));
666             pats.push(self.ecx.pat_ident(e.span, name));
667             heads.push(self.ecx.expr_addr_of(e.span, e));
668             locals.push(self.format_arg(e.span, Exact(i),
669                                         self.ecx.expr_ident(e.span, name)));
670         }
671         for name in self.name_ordering.iter() {
672             let e = match self.names.find(name) {
673                 Some(&e) if self.name_types.contains_key(name) => e,
674                 Some(..) | None => continue
675             };
676
677             let lname = self.ecx.ident_of(format!("__arg{}", *name));
678             pats.push(self.ecx.pat_ident(e.span, lname));
679             heads.push(self.ecx.expr_addr_of(e.span, e));
680             *names.get_mut(*self.name_positions.get(name)) =
681                 Some(self.format_arg(e.span,
682                                      Named((*name).clone()),
683                                      self.ecx.expr_ident(e.span, lname)));
684         }
685
686         // Now create a vector containing all the arguments
687         let slicename = self.ecx.ident_of("__args_vec");
688         {
689             let args = names.move_iter().map(|a| a.unwrap());
690             let mut args = locals.move_iter().chain(args);
691             let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
692             lets.push(self.ecx.stmt_let(self.fmtsp, false, slicename, args));
693         }
694
695         // Now create the fmt::Arguments struct with all our locals we created.
696         let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
697         let args_slice = self.ecx.expr_ident(self.fmtsp, slicename);
698         let result = self.ecx.expr_call_global(self.fmtsp, vec!(
699                 self.ecx.ident_of("std"),
700                 self.ecx.ident_of("fmt"),
701                 self.ecx.ident_of("Arguments"),
702                 self.ecx.ident_of("new")), vec!(fmt, args_slice));
703
704         // We did all the work of making sure that the arguments
705         // structure is safe, so we can safely have an unsafe block.
706         let result = self.ecx.expr_block(P(ast::Block {
707            view_items: Vec::new(),
708            stmts: Vec::new(),
709            expr: Some(result),
710            id: ast::DUMMY_NODE_ID,
711            rules: ast::UnsafeBlock(ast::CompilerGenerated),
712            span: self.fmtsp,
713         }));
714         let resname = self.ecx.ident_of("__args");
715         lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
716         let res = self.ecx.expr_ident(self.fmtsp, resname);
717         let result = match invocation {
718             Call(e) => {
719                 self.ecx.expr_call(e.span, e,
720                                    vec!(self.ecx.expr_addr_of(e.span, res)))
721             }
722             MethodCall(e, m) => {
723                 self.ecx.expr_method_call(e.span, e, m,
724                                           vec!(self.ecx.expr_addr_of(e.span, res)))
725             }
726         };
727         let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
728                                                       Some(result)));
729
730         // Constructs an AST equivalent to:
731         //
732         //      match (&arg0, &arg1) {
733         //          (tmp0, tmp1) => body
734         //      }
735         //
736         // It was:
737         //
738         //      let tmp0 = &arg0;
739         //      let tmp1 = &arg1;
740         //      body
741         //
742         // Because of #11585 the new temporary lifetime rule, the enclosing
743         // statements for these temporaries become the let's themselves.
744         // If one or more of them are RefCell's, RefCell borrow() will also
745         // end there; they don't last long enough for body to use them. The
746         // match expression solves the scope problem.
747         //
748         // Note, it may also very well be transformed to:
749         //
750         //      match arg0 {
751         //          ref tmp0 => {
752         //              match arg1 => {
753         //                  ref tmp1 => body } } }
754         //
755         // But the nested match expression is proved to perform not as well
756         // as series of let's; the first approach does.
757         let pat = self.ecx.pat(self.fmtsp, ast::PatTup(pats));
758         let arm = self.ecx.arm(self.fmtsp, vec!(pat), body);
759         let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
760         self.ecx.expr_match(self.fmtsp, head, vec!(arm))
761     }
762
763     fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
764                   -> @ast::Expr {
765         let ty = match argno {
766             Exact(ref i) => self.arg_types.get(*i).get_ref(),
767             Named(ref s) => self.name_types.get(s)
768         };
769
770         let fmt_fn = match *ty {
771             Known(ref tyname) => {
772                 match tyname.as_slice() {
773                     ""  => "secret_show",
774                     "?" => "secret_poly",
775                     "b" => "secret_bool",
776                     "c" => "secret_char",
777                     "d" | "i" => "secret_signed",
778                     "e" => "secret_lower_exp",
779                     "E" => "secret_upper_exp",
780                     "f" => "secret_float",
781                     "o" => "secret_octal",
782                     "p" => "secret_pointer",
783                     "s" => "secret_string",
784                     "t" => "secret_binary",
785                     "u" => "secret_unsigned",
786                     "x" => "secret_lower_hex",
787                     "X" => "secret_upper_hex",
788                     _ => {
789                         self.ecx.span_err(sp, format!("unknown format trait `{}`",
790                                                       *tyname));
791                         "dummy"
792                     }
793                 }
794             }
795             String => {
796                 return self.ecx.expr_call_global(sp, vec!(
797                         self.ecx.ident_of("std"),
798                         self.ecx.ident_of("fmt"),
799                         self.ecx.ident_of("argumentstr")), vec!(arg))
800             }
801             Unsigned => {
802                 return self.ecx.expr_call_global(sp, vec!(
803                         self.ecx.ident_of("std"),
804                         self.ecx.ident_of("fmt"),
805                         self.ecx.ident_of("argumentuint")), vec!(arg))
806             }
807         };
808
809         let format_fn = self.ecx.path_global(sp, vec!(
810                 self.ecx.ident_of("std"),
811                 self.ecx.ident_of("fmt"),
812                 self.ecx.ident_of(fmt_fn)));
813         self.ecx.expr_call_global(sp, vec!(
814                 self.ecx.ident_of("std"),
815                 self.ecx.ident_of("fmt"),
816                 self.ecx.ident_of("argument")), vec!(self.ecx.expr_path(format_fn), arg))
817     }
818 }
819
820 pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span,
821                           tts: &[ast::TokenTree]) -> Box<base::MacResult> {
822
823     match parse_args(ecx, sp, false, tts) {
824         (invocation, Some((efmt, args, order, names))) => {
825             MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt,
826                                                       args, order, names))
827         }
828         (_, None) => MacExpr::new(ecx.expr_uint(sp, 2))
829     }
830 }
831
832 pub fn expand_format_args_method(ecx: &mut ExtCtxt, sp: Span,
833                                  tts: &[ast::TokenTree]) -> Box<base::MacResult> {
834
835     match parse_args(ecx, sp, true, tts) {
836         (invocation, Some((efmt, args, order, names))) => {
837             MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt,
838                                                       args, order, names))
839         }
840         (_, None) => MacExpr::new(ecx.expr_uint(sp, 2))
841     }
842 }
843
844 /// Take the various parts of `format_args!(extra, efmt, args...,
845 /// name=names...)` and construct the appropriate formatting
846 /// expression.
847 pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
848                                     invocation: Invocation,
849                                     efmt: @ast::Expr, args: Vec<@ast::Expr>,
850                                     name_ordering: Vec<StrBuf>,
851                                     names: HashMap<StrBuf, @ast::Expr>) -> @ast::Expr {
852     let arg_types = Vec::from_fn(args.len(), |_| None);
853     let mut cx = Context {
854         ecx: ecx,
855         args: args,
856         arg_types: arg_types,
857         names: names,
858         name_positions: HashMap::new(),
859         name_types: HashMap::new(),
860         name_ordering: name_ordering,
861         nest_level: 0,
862         next_arg: 0,
863         pieces: Vec::new(),
864         method_statics: Vec::new(),
865         fmtsp: sp,
866     };
867     cx.fmtsp = efmt.span;
868     let fmt = match expr_to_str(cx.ecx,
869                                 efmt,
870                                 "format argument must be a string literal.") {
871         Some((fmt, _)) => fmt,
872         None => return DummyResult::raw_expr(sp)
873     };
874
875     let mut parser = parse::Parser::new(fmt.get());
876     loop {
877         match parser.next() {
878             Some(piece) => {
879                 if parser.errors.len() > 0 { break }
880                 cx.verify_piece(&piece);
881                 let piece = cx.trans_piece(&piece);
882                 cx.pieces.push(piece);
883             }
884             None => break
885         }
886     }
887     match parser.errors.shift() {
888         Some(error) => {
889             cx.ecx.span_err(efmt.span,
890                             format_strbuf!("invalid format string: {}",
891                                            error).as_slice());
892             return DummyResult::raw_expr(sp);
893         }
894         None => {}
895     }
896
897     // Make sure that all arguments were used and all arguments have types.
898     for (i, ty) in cx.arg_types.iter().enumerate() {
899         if ty.is_none() {
900             cx.ecx.span_err(cx.args.get(i).span, "argument never used");
901         }
902     }
903     for (name, e) in cx.names.iter() {
904         if !cx.name_types.contains_key(name) {
905             cx.ecx.span_err(e.span, "named argument never used");
906         }
907     }
908
909     cx.to_expr(invocation)
910 }