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