]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/format.rs
libsyntax: Fix errors arising from the automated `~[T]` conversion
[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 opt_vec;
18 use parse::token::InternedString;
19 use parse::token;
20 use rsparse = parse;
21
22 use std::fmt::parse;
23 use collections::{HashMap, HashSet};
24 use std::vec;
25 use std::vec_ng::Vec;
26
27 #[deriving(Eq)]
28 enum ArgumentType {
29     Known(~str),
30     Unsigned,
31     String,
32 }
33
34 enum Position {
35     Exact(uint),
36     Named(~str),
37 }
38
39 struct Context<'a> {
40     ecx: &'a mut ExtCtxt<'a>,
41     fmtsp: Span,
42
43     // Parsed argument expressions and the types that we've found so far for
44     // them.
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
50     // were declared in.
51     names: HashMap<~str, @ast::Expr>,
52     name_types: HashMap<~str, ArgumentType>,
53     name_ordering: Vec<~str>,
54
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> ,
59
60     // Updated as arguments are consumed or methods are entered
61     nest_level: uint,
62     next_arg: uint,
63 }
64
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!
67 /// expressions.
68 ///
69 /// If parsing succeeds, the second return value is:
70 ///
71 ///     Some((fmtstr, unnamed arguments, ordering of named arguments,
72 ///           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();
79
80     let mut p = rsparse::new_parser_from_tts(ecx.parse_sess(),
81                                              ecx.cfg(),
82                                              tts.iter()
83                                                 .map(|x| (*x).clone())
84                                                 .collect());
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: `,`");
89         return (extra, None);
90     }
91
92     if p.token == token::EOF {
93         ecx.span_err(sp, "requires at least a format string argument");
94         return (extra, None);
95     }
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);
102         }
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)) {
106             named = true;
107             let ident = match p.token {
108                 token::IDENT(i, _) => {
109                     p.bump();
110                     i
111                 }
112                 _ if named => {
113                     ecx.span_err(p.span,
114                                  "expected ident, positional arguments \
115                                  cannot follow named arguments");
116                     return (extra, None);
117                 }
118                 _ => {
119                     ecx.span_err(p.span,
120                                  format!("expected ident for named argument, but found `{}`",
121                                          p.this_token_to_str()));
122                     return (extra, None);
123                 }
124             };
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) {
130                 None => {}
131                 Some(prev) => {
132                     ecx.span_err(e.span, format!("duplicate argument named `{}`", name));
133                     ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
134                     continue
135                 }
136             }
137             order.push(name.to_str());
138             names.insert(name.to_str(), e);
139         } else {
140             args.push(p.parse_expr());
141         }
142     }
143     return (extra, Some((fmtstr, args, order, names)));
144 }
145
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
149     /// format strings.
150     fn verify_piece(&mut self, p: &parse::Piece) {
151         match *p {
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 \
157                                        reference back to");
158                 }
159             }
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);
165
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() {
172                             self.next_arg += 1;
173                         }
174                         Exact(i)
175                     }
176                     parse::ArgumentIs(i) => Exact(i),
177                     parse::ArgumentNamed(s) => Named(s.to_str()),
178                 };
179
180                 // and finally the method being applied
181                 match arg.method {
182                     None => {
183                         let ty = Known(arg.format.ty.to_str());
184                         self.verify_arg_type(pos, ty);
185                     }
186                     Some(ref method) => { self.verify_method(pos, *method); }
187                 }
188             }
189         }
190     }
191
192     fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
193         for piece in pieces.iter() {
194             self.verify_piece(piece);
195         }
196     }
197
198     fn verify_count(&mut self, c: parse::Count) {
199         match c {
200             parse::CountImplied | parse::CountIs(..) => {}
201             parse::CountIsParam(i) => {
202                 self.verify_arg_type(Exact(i), Unsigned);
203             }
204             parse::CountIsName(s) => {
205                 self.verify_arg_type(Named(s.to_str()), Unsigned);
206             }
207             parse::CountIsNextParam => {
208                 if self.check_positional_ok() {
209                     self.verify_arg_type(Exact(self.next_arg), Unsigned);
210                     self.next_arg += 1;
211                 }
212             }
213         }
214     }
215
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");
220             false
221         } else {
222             true
223         }
224     }
225
226     fn verify_method(&mut self, pos: Position, m: &parse::Method) {
227         self.nest_level += 1;
228         match *m {
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) {
234                         match arm.selector {
235                             parse::Keyword(name) => {
236                                 self.ecx.span_err(self.fmtsp,
237                                                   format!("duplicate selector \
238                                                            `{:?}`", name));
239                             }
240                             parse::Literal(idx) => {
241                                 self.ecx.span_err(self.fmtsp,
242                                                   format!("duplicate selector \
243                                                            `={}`", idx));
244                             }
245                         }
246                     }
247                     self.verify_pieces(arm.result);
248                 }
249                 self.verify_pieces(*default);
250             }
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 `{}`",
258                                                arm.selector));
259                     } else if arm.selector == "" {
260                         self.ecx.span_err(self.fmtsp,
261                                           "empty selector in `select`");
262                     }
263                     self.verify_pieces(arm.result);
264                 }
265                 self.verify_pieces(*default);
266             }
267         }
268         self.nest_level -= 1;
269     }
270
271     fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
272         match arg {
273             Exact(arg) => {
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);
278                     return;
279                 }
280                 {
281                     let arg_type = match self.arg_types.get(arg) {
282                         &None => None,
283                         &Some(ref x) => Some(x)
284                     };
285                     self.verify_same(self.args.get(arg).span, &ty, arg_type);
286                 }
287                 if self.arg_types.get(arg).is_none() {
288                     *self.arg_types.get_mut(arg) = Some(ty);
289                 }
290             }
291
292             Named(name) => {
293                 let span = match self.names.find(&name) {
294                     Some(e) => e.span,
295                     None => {
296                         let msg = format!("there is no argument named `{}`", name);
297                         self.ecx.span_err(self.fmtsp, msg);
298                         return;
299                     }
300                 };
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);
304                 }
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);
310                 }
311             }
312         }
313     }
314
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
319     /// have type `x`.
320     ///
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,
324                    sp: Span,
325                    ty: &ArgumentType,
326                    before: Option<&ArgumentType>) {
327         let cur = match before {
328             None => return,
329             Some(t) => t,
330         };
331         if *ty == *cur {
332             return
333         }
334         match (cur, ty) {
335             (&Known(ref cur), &Known(ref ty)) => {
336                 self.ecx.span_err(sp,
337                                   format!("argument redeclared with type `{}` when \
338                                            it was previously `{}`",
339                                           *ty,
340                                           *cur));
341             }
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",
346                                            *cur));
347             }
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 `{}`",
352                                            *ty));
353             }
354             (_, _) => {
355                 self.ecx.span_err(sp, "argument declared with multiple formats");
356             }
357         }
358     }
359
360     /// These attributes are applied to all statics that this syntax extension
361     /// will generate.
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,
367                                      InternedString::new(
368                                          "address_insignificant"));
369         let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
370
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"),
376                                                  vec!(dead_code));
377         let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
378         return vec!(unnamed, allow_dead_code);
379     }
380
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))
384     }
385
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))
389     }
390
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))
394     }
395
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)
402     }
403
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))
411     }
412
413     fn trans_count(&self, c: parse::Count) -> @ast::Expr {
414         let sp = self.fmtsp;
415         match c {
416             parse::CountIs(i) => {
417                 self.ecx.expr_call_global(sp, self.rtpath("CountIs"),
418                                           vec!(self.ecx.expr_uint(sp, i)))
419             }
420             parse::CountIsParam(i) => {
421                 self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
422                                           vec!(self.ecx.expr_uint(sp, i)))
423             }
424             parse::CountImplied => {
425                 let path = self.ecx.path_global(sp, self.rtpath("CountImplied"));
426                 self.ecx.expr_path(path)
427             }
428             parse::CountIsNextParam => {
429                 let path = self.ecx.path_global(sp, self.rtpath("CountIsNextParam"));
430                 self.ecx.expr_path(path)
431             }
432             parse::CountIsName(n) => {
433                 let i = match self.name_positions.find_equiv(&n) {
434                     Some(&i) => i,
435                     None => 0, // error already emitted elsewhere
436                 };
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)))
440             }
441         }
442     }
443
444     fn trans_method(&mut self, method: &parse::Method) -> @ast::Expr {
445         let sp = self.fmtsp;
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| {
451                             self.trans_piece(p)
452                         }).collect();
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"),
458                                                    selector),
459                                 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
460                                                    self.ecx.expr_vec_slice(sp, result))))
461                     }).collect();
462                 let default = default.iter().map(|p| {
463                         self.trans_piece(p)
464                     }).collect();
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)))
468             }
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() }
473                 };
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| {
477                                 self.trans_piece(p)
478                             }).collect();
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))
484                             }
485                             parse::Literal(i) => {
486                                 (self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
487                             }
488                         };
489                         let selector = self.ecx.expr_call_global(sp,
490                                                                  lr, vec!(selarg));
491                         self.ecx.expr_struct(sp, p, vec!(
492                                 self.ecx.field_imm(sp,
493                                                    self.ecx.ident_of("selector"),
494                                                    selector),
495                                 self.ecx.field_imm(sp, self.ecx.ident_of("result"),
496                                                    self.ecx.expr_vec_slice(sp, result))))
497                     }).collect();
498                 let default = default.iter().map(|p| {
499                         self.trans_piece(p)
500                     }).collect();
501                 self.ecx.expr_call_global(sp, self.rtpath("Plural"), vec!(
502                         offset,
503                         self.ecx.expr_vec_slice(sp, arms),
504                         self.ecx.expr_vec_slice(sp, default)))
505             }
506         };
507         let life = self.ecx.lifetime(sp, self.ecx.ident_of("static").name);
508         let ty = self.ecx.ty_path(self.ecx.path_all(
509                 sp,
510                 true,
511                 self.rtpath("Method"),
512                 opt_vec::with(life),
513                 Vec::new()
514                     ), None);
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)
521     }
522
523     /// Translate a `parse::Piece` to a static `rt::Piece`
524     fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
525         let sp = self.fmtsp;
526         match *piece {
527             parse::String(s) => {
528                 let s = token::intern_and_get_ident(s);
529                 self.ecx.expr_call_global(sp,
530                                           self.rtpath("String"),
531                                           vec!(
532                     self.ecx.expr_str(sp, s)
533                 ))
534             }
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))
538             }
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)
547                     }
548                     parse::ArgumentIs(i) => {
549                         self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
550                                                   vec!(self.ecx.expr_uint(sp, i)))
551                     }
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) {
556                             Some(&i) => i,
557                             None => 0, // error already emitted elsewhere
558                         };
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)))
562                     }
563                 };
564
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"))
571                     }
572                     parse::AlignRight => {
573                         self.ecx.path_global(sp, self.parsepath("AlignRight"))
574                     }
575                     parse::AlignUnknown => {
576                         self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
577                     }
578                 };
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)));
590
591                 // Translate the method (if any)
592                 let method = match arg.method {
593                     None => { self.none() }
594                     Some(ref m) => {
595                         let m = self.trans_method(*m);
596                         self.some(self.ecx.expr_addr_of(sp, m))
597                     }
598                 };
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))
605             }
606         }
607     }
608
609     /// Actually builds the expression which the iformat! block will be expanded
610     /// to
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();
617
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)));
623         }
624
625         // Next, build up the static array which will become our precompiled
626         // format "string"
627         let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
628         let piece_ty = self.ecx.ty_path(self.ecx.path_all(
629                 self.fmtsp,
630                 true, vec!(
631                     self.ecx.ident_of("std"),
632                     self.ecx.ident_of("fmt"),
633                     self.ecx.ident_of("rt"),
634                     self.ecx.ident_of("Piece")),
635                 opt_vec::with(
636                     self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static").name)),
637                 Vec::new()
638             ), None);
639         let ty = ast::TyFixedLengthVec(
640             piece_ty,
641             self.ecx.expr_uint(self.fmtsp, self.pieces.len())
642         );
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)));
650
651         // Right now there is a bug such that for the expression:
652         //      foo(bar(&1))
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
661             }
662
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)));
668         }
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
673             };
674
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)));
682         }
683
684         // Now create a vector containing all the arguments
685         let slicename = self.ecx.ident_of("__args_vec");
686         {
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));
691         }
692
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));
701
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(),
706            stmts: Vec::new(),
707            expr: Some(result),
708            id: ast::DUMMY_NODE_ID,
709            rules: ast::UnsafeBlock(ast::CompilerGenerated),
710            span: self.fmtsp,
711         }));
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,
718                                                       Some(result)));
719
720         // Constructs an AST equivalent to:
721         //
722         //      match (&arg0, &arg1) {
723         //          (tmp0, tmp1) => body
724         //      }
725         //
726         // It was:
727         //
728         //      let tmp0 = &arg0;
729         //      let tmp1 = &arg1;
730         //      body
731         //
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.
737         //
738         // Note, it may also very well be transformed to:
739         //
740         //      match arg0 {
741         //          ref tmp0 => {
742         //              match arg1 => {
743         //                  ref tmp1 => body } } }
744         //
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))
751     }
752
753     fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
754                   -> @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)
758         };
759
760         let fmt_fn = match *ty {
761             Known(ref tyname) => {
762                 match tyname.as_slice() {
763                     ""  => "secret_show",
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",
778                     _ => {
779                         self.ecx.span_err(sp, format!("unknown format trait `{}`",
780                                                       *tyname));
781                         "dummy"
782                     }
783                 }
784             }
785             String => {
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))
790             }
791             Unsigned => {
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))
796             }
797         };
798
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))
807     }
808 }
809
810 pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
811                    tts: &[ast::TokenTree]) -> base::MacResult {
812
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,
816                                                 order, names))
817         }
818         (_, None) => MRExpr(ecx.expr_uint(sp, 2))
819     }
820 }
821
822 /// Take the various parts of `format_args!(extra, efmt, args...,
823 /// name=names...)` and construct the appropriate formatting
824 /// expression.
825 pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
826                                     extra: @ast::Expr,
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 {
832         ecx: ecx,
833         args: args,
834         arg_types: arg_types,
835         names: names,
836         name_positions: HashMap::new(),
837         name_types: HashMap::new(),
838         name_ordering: name_ordering,
839         nest_level: 0,
840         next_arg: 0,
841         pieces: Vec::new(),
842         method_statics: Vec::new(),
843         fmtsp: sp,
844     };
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,
850                                 expr,
851                                 "format argument must be a string literal.") {
852         Some((fmt, _)) => fmt,
853         None => return MacResult::raw_dummy_expr(sp)
854     };
855
856     let mut parser = parse::Parser::new(fmt.get());
857     loop {
858         match parser.next() {
859             Some(piece) => {
860                 if parser.errors.len() > 0 { break }
861                 cx.verify_piece(&piece);
862                 let piece = cx.trans_piece(&piece);
863                 cx.pieces.push(piece);
864             }
865             None => break
866         }
867     }
868     match parser.errors.shift() {
869         Some(error) => {
870             cx.ecx.span_err(efmt.span, "invalid format string: " + error);
871             return MacResult::raw_dummy_expr(sp);
872         }
873         None => {}
874     }
875
876     // Make sure that all arguments were used and all arguments have types.
877     for (i, ty) in cx.arg_types.iter().enumerate() {
878         if ty.is_none() {
879             cx.ecx.span_err(cx.args.get(i).span, "argument never used");
880         }
881     }
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");
885         }
886     }
887
888     cx.to_expr(extra)
889 }