(index<- )        ./libsyntax/ext/format.rs

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


libsyntax/ext/format.rs:30:1-30:1 -enum- definition:
enum Position {
    Exact(uint),
    Named(StrBuf),
references:- 3
740:     fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
741:                   -> @ast::Expr {


libsyntax/ext/format.rs:811:16-811:16 -fn- definition:
/// expression.
pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
                                    extra: @ast::Expr,
references:- 2
libsyntax/ext/deriving/show.rs:
137:     // phew, not our responsibility any more!
138:     format::expand_preparsed_format_args(cx, span,
139:                                          format_closure,
libsyntax/ext/format.rs:
801:         (extra, Some((efmt, args, order, names))) => {
802:             MacExpr::new(expand_preparsed_format_args(ecx, sp, extra, efmt, args,
803:                                                 order, names))


libsyntax/ext/format.rs:24:16-24:16 -enum- definition:
enum ArgumentType {
    Known(StrBuf),
    Unsigned,
references:- 8
25: enum ArgumentType {
--
322:                    ty: &ArgumentType,
323:                    before: Option<&ArgumentType>) {
324:         let cur = match before {


libsyntax/ext/format.rs:35:1-35:1 -struct- definition:
struct Context<'a, 'b> {
    ecx: &'a mut ExtCtxt<'b>,
    fmtsp: Span,
references:- 2
143: impl<'a, 'b> Context<'a, 'b> {
144:     /// Verifies one piece of a parse string. All errors are not emitted as
--
817:     let arg_types = Vec::from_fn(args.len(), |_| None);
818:     let mut cx = Context {
819:         ecx: ecx,