(index<- )        ./libstd/fmt/parse.rs

    git branch:    * master           c7553ea auto merge of #13609 : richo/rust/str-type-vim, r=alexcrichton
    modified:    Sat Apr 19 11:22:39 2014
   1  // Copyright 2013 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  //! Parsing of format strings
  12  //!
  13  //! These structures are used when parsing format strings for the compiler.
  14  //! Parsing does not happen at runtime: structures of `std::fmt::rt` are
  15  //! generated instead.
  16  
  17  use prelude::*;
  18  
  19  use char;
  20  use str;
  21  
  22  /// A piece is a portion of the format string which represents the next part
  23  /// to emit. These are emitted as a stream by the `Parser` class.
  24  #[deriving(Eq)]
  25  pub enum Piece<'a> {
  26      /// A literal string which should directly be emitted
  27      String(&'a str),
  28      /// A back-reference to whatever the current argument is. This is used
  29      /// inside of a method call to refer back to the original argument.
  30      CurrentArgument,
  31      /// This describes that formatting should process the next argument (as
  32      /// specified inside) for emission.
  33      Argument(Argument<'a>),
  34  }
  35  
  36  /// Representation of an argument specification.
  37  #[deriving(Eq)]
  38  pub struct Argument<'a> {
  39      /// Where to find this argument
  40      pub position: Position<'a>,
  41      /// How to format the argument
  42      pub format: FormatSpec<'a>,
  43      /// If not `None`, what method to invoke on the argument
  44      pub method: Option<~Method<'a>>
  45  }
  46  
  47  /// Specification for the formatting of an argument in the format string.
  48  #[deriving(Eq)]
  49  pub struct FormatSpec<'a> {
  50      /// Optionally specified character to fill alignment with
  51      pub fill: Option<char>,
  52      /// Optionally specified alignment
  53      pub align: Alignment,
  54      /// Packed version of various flags provided
  55      pub flags: uint,
  56      /// The integer precision to use
  57      pub precision: Count<'a>,
  58      /// The string width requested for the resulting format
  59      pub width: Count<'a>,
  60      /// The descriptor string representing the name of the format desired for
  61      /// this argument, this can be empty or any number of characters, although
  62      /// it is required to be one word.
  63      pub ty: &'a str
  64  }
  65  
  66  /// Enum describing where an argument for a format can be located.
  67  #[deriving(Eq)]
  68  pub enum Position<'a> {
  69      /// The argument will be in the next position. This is the default.
  70      ArgumentNext,
  71      /// The argument is located at a specific index.
  72      ArgumentIs(uint),
  73      /// The argument has a name.
  74      ArgumentNamed(&'a str),
  75  }
  76  
  77  /// Enum of alignments which are supported.
  78  #[deriving(Eq)]
  79  pub enum Alignment {
  80      /// The value will be aligned to the left.
  81      AlignLeft,
  82      /// The value will be aligned to the right.
  83      AlignRight,
  84      /// The value will take on a default alignment.
  85      AlignUnknown,
  86  }
  87  
  88  /// Various flags which can be applied to format strings. The meaning of these
  89  /// flags is defined by the formatters themselves.
  90  #[deriving(Eq)]
  91  pub enum Flag {
  92      /// A `+` will be used to denote positive numbers.
  93      FlagSignPlus,
  94      /// A `-` will be used to denote negative numbers. This is the default.
  95      FlagSignMinus,
  96      /// An alternate form will be used for the value. In the case of numbers,
  97      /// this means that the number will be prefixed with the supplied string.
  98      FlagAlternate,
  99      /// For numbers, this means that the number will be padded with zeroes,
 100      /// and the sign (`+` or `-`) will precede them.
 101      FlagSignAwareZeroPad,
 102  }
 103  
 104  /// A count is used for the precision and width parameters of an integer, and
 105  /// can reference either an argument or a literal integer.
 106  #[deriving(Eq)]
 107  pub enum Count<'a> {
 108      /// The count is specified explicitly.
 109      CountIs(uint),
 110      /// The count is specified by the argument with the given name.
 111      CountIsName(&'a str),
 112      /// The count is specified by the argument at the given index.
 113      CountIsParam(uint),
 114      /// The count is specified by the next parameter.
 115      CountIsNextParam,
 116      /// The count is implied and cannot be explicitly specified.
 117      CountImplied,
 118  }
 119  
 120  /// Enum describing all of the possible methods which the formatting language
 121  /// currently supports.
 122  #[deriving(Eq)]
 123  pub enum Method<'a> {
 124      /// A plural method selects on an integer over a list of either integer or
 125      /// keyword-defined clauses. The meaning of the keywords is defined by the
 126      /// current locale.
 127      ///
 128      /// An offset is optionally present at the beginning which is used to
 129      /// match against keywords, but it is not matched against the literal
 130      /// integers.
 131      ///
 132      /// The final element of this enum is the default "other" case which is
 133      /// always required to be specified.
 134      Plural(Option<uint>, Vec<PluralArm<'a>>, Vec<Piece<'a>>),
 135  
 136      /// A select method selects over a string. Each arm is a different string
 137      /// which can be selected for.
 138      ///
 139      /// As with `Plural`, a default "other" case is required as well.
 140      Select(Vec<SelectArm<'a>>, Vec<Piece<'a>>),
 141  }
 142  
 143  /// A selector for what pluralization a plural method should take
 144  #[deriving(Eq, TotalEq, Hash)]
 145  pub enum PluralSelector {
 146      /// One of the plural keywords should be used
 147      Keyword(PluralKeyword),
 148      /// A literal pluralization should be used
 149      Literal(uint),
 150  }
 151  
 152  /// Structure representing one "arm" of the `plural` function.
 153  #[deriving(Eq)]
 154  pub struct PluralArm<'a> {
 155      /// A selector can either be specified by a keyword or with an integer
 156      /// literal.
 157      pub selector: PluralSelector,
 158      /// Array of pieces which are the format of this arm
 159      pub result: Vec<Piece<'a>>,
 160  }
 161  
 162  /// Enum of the 5 CLDR plural keywords. There is one more, "other", but that
 163  /// is specially placed in the `Plural` variant of `Method`.
 164  ///
 165  /// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html
 166  #[deriving(Eq, TotalEq, Hash)]
 167  #[allow(missing_doc)]
 168  pub enum PluralKeyword {
 169      /// The plural form for zero objects.
 170      Zero,
 171      /// The plural form for one object.
 172      One,
 173      /// The plural form for two objects.
 174      Two,
 175      /// The plural form for few objects.
 176      Few,
 177      /// The plural form for many objects.
 178      Many,
 179  }
 180  
 181  /// Structure representing one "arm" of the `select` function.
 182  #[deriving(Eq)]
 183  pub struct SelectArm<'a> {
 184      /// String selector which guards this arm
 185      pub selector: &'a str,
 186      /// Array of pieces which are the format of this arm
 187      pub result: Vec<Piece<'a>>,
 188  }
 189  
 190  /// The parser structure for interpreting the input format string. This is
 191  /// modelled as an iterator over `Piece` structures to form a stream of tokens
 192  /// being output.
 193  ///
 194  /// This is a recursive-descent parser for the sake of simplicity, and if
 195  /// necessary there's probably lots of room for improvement performance-wise.
 196  pub struct Parser<'a> {
 197      input: &'a str,
 198      cur: str::CharOffsets<'a>,
 199      depth: uint,
 200      /// Error messages accumulated during parsing
 201      pub errors: Vec<~str>,
 202  }
 203  
 204  impl<'a> Iterator<Piece<'a>> for Parser<'a> {
 205      fn next(&mut self) -> Option<Piece<'a>> {
 206          match self.cur.clone().next() {
 207              Some((_, '#')) => { self.cur.next(); Some(CurrentArgument) }
 208              Some((_, '{')) => {
 209                  self.cur.next();
 210                  let ret = Some(Argument(self.argument()));
 211                  self.must_consume('}');
 212                  ret
 213              }
 214              Some((pos, '\\')) => {
 215                  self.cur.next();
 216                  self.escape(); // ensure it's a valid escape sequence
 217                  Some(String(self.string(pos + 1))) // skip the '\' character
 218              }
 219              Some((_, '}')) if self.depth == 0 => {
 220                  self.cur.next();
 221                  self.err("unmatched `}` found");
 222                  None
 223              }
 224              Some((_, '}')) | None => { None }
 225              Some((pos, _)) => {
 226                  Some(String(self.string(pos)))
 227              }
 228          }
 229      }
 230  }
 231  
 232  impl<'a> Parser<'a> {
 233      /// Creates a new parser for the given format string
 234      pub fn new<'a>(s&'a str) -> Parser<'a> {
 235          Parser {
 236              input: s,
 237              cur: s.char_indices(),
 238              depth: 0,
 239              errors: vec!(),
 240          }
 241      }
 242  
 243      /// Notifies of an error. The message doesn't actually need to be of type
 244      /// ~str, but I think it does when this eventually uses conditions so it
 245      /// might as well start using it now.
 246      fn err(&mut self, msg&str) {
 247          self.errors.push(msg.to_owned());
 248      }
 249  
 250      /// Optionally consumes the specified character. If the character is not at
 251      /// the current position, then the current iterator isn't moved and false is
 252      /// returned, otherwise the character is consumed and true is returned.
 253      fn consume(&mut self, cchar) -> bool {
 254          match self.cur.clone().next() {
 255              Some((_, maybe)) if c == maybe => {
 256                  self.cur.next();
 257                  true
 258              }
 259              Some(..) | None => false,
 260          }
 261      }
 262  
 263      /// Forces consumption of the specified character. If the character is not
 264      /// found, an error is emitted.
 265      fn must_consume(&mut self, cchar) {
 266          self.ws();
 267          match self.cur.clone().next() {
 268              Some((_, maybe)) if c == maybe => {
 269                  self.cur.next();
 270              }
 271              Some((_, other)) => {
 272                  self.err(
 273                      format!("expected `{}` but found `{}`", c, other));
 274              }
 275              None => {
 276                  self.err(
 277                      format!("expected `{}` but string was terminated", c));
 278              }
 279          }
 280      }
 281  
 282      /// Attempts to consume any amount of whitespace followed by a character
 283      fn wsconsume(&mut self, cchar) -> bool {
 284          self.ws(); self.consume(c)
 285      }
 286  
 287      /// Consumes all whitespace characters until the first non-whitespace
 288      /// character
 289      fn ws(&mut self) {
 290          loop {
 291              match self.cur.clone().next() {
 292                  Some((_, c)) if char::is_whitespace(c) => { self.cur.next(); }
 293                  Some(..) | None => { return }
 294              }
 295          }
 296      }
 297  
 298      /// Consumes an escape sequence, failing if there is not a valid character
 299      /// to be escaped.
 300      fn escape(&mut self) -> char {
 301          match self.cur.next() {
 302              Some((_, c @ '#')) | Some((_, c @ '{')) |
 303              Some((_, c @ '\\')) | Some((_, c @ '}')) => { c }
 304              Some((_, c)) => {
 305                  self.err(format!("invalid escape character `{}`", c));
 306                  c
 307              }
 308              None => {
 309                  self.err("expected an escape sequence, but format string was \
 310                             terminated");
 311                  ' '
 312              }
 313          }
 314      }
 315  
 316      /// Parses all of a string which is to be considered a "raw literal" in a
 317      /// format string. This is everything outside of the braces.
 318      fn string(&mut self, startuint) -> &'a str {
 319          loop {
 320              // we may not consume the character, so clone the iterator
 321              match self.cur.clone().next() {
 322                  Some((pos, '\\')) | Some((pos, '#')) |
 323                  Some((pos, '}')) | Some((pos, '{')) => {
 324                      return self.input.slice(start, pos);
 325                  }
 326                  Some(..) => { self.cur.next(); }
 327                  None => {
 328                      self.cur.next();
 329                      return self.input.slice(start, self.input.len());
 330                  }
 331              }
 332          }
 333      }
 334  
 335      /// Parses an Argument structure, or what's contained within braces inside
 336      /// the format string
 337      fn argument(&mut self) -> Argument<'a> {
 338          Argument {
 339              position: self.position(),
 340              format: self.format(),
 341              method: self.method(),
 342          }
 343      }
 344  
 345      /// Parses a positional argument for a format. This could either be an
 346      /// integer index of an argument, a named argument, or a blank string.
 347      fn position(&mut self) -> Position<'a> {
 348          match self.integer() {
 349              Some(i) => { ArgumentIs(i) }
 350              None => {
 351                  match self.cur.clone().next() {
 352                      Some((_, c)) if char::is_alphabetic(c) => {
 353                          ArgumentNamed(self.word())
 354                      }
 355                      _ => ArgumentNext
 356                  }
 357              }
 358          }
 359      }
 360  
 361      /// Parses a format specifier at the current position, returning all of the
 362      /// relevant information in the FormatSpec struct.
 363      fn format(&mut self) -> FormatSpec<'a> {
 364          let mut spec = FormatSpec {
 365              fill: None,
 366              align: AlignUnknown,
 367              flags: 0,
 368              precision: CountImplied,
 369              width: CountImplied,
 370              ty: self.input.slice(0, 0),
 371          };
 372          if !self.consume(':') { return spec }
 373  
 374          // fill character
 375          match self.cur.clone().next() {
 376              Some((_, c)) => {
 377                  match self.cur.clone().skip(1).next() {
 378                      Some((_, '>')) | Some((_, '<')) => {
 379                          spec.fill = Some(c);
 380                          self.cur.next();
 381                      }
 382                      Some(..) | None => {}
 383                  }
 384              }
 385              None => {}
 386          }
 387          // Alignment
 388          if self.consume('<') {
 389              spec.align = AlignLeft;
 390          } else if self.consume('>') {
 391              spec.align = AlignRight;
 392          }
 393          // Sign flags
 394          if self.consume('+') {
 395              spec.flags |= 1 << (FlagSignPlus as uint);
 396          } else if self.consume('-') {
 397              spec.flags |= 1 << (FlagSignMinus as uint);
 398          }
 399          // Alternate marker
 400          if self.consume('#') {
 401              spec.flags |= 1 << (FlagAlternate as uint);
 402          }
 403          // Width and precision
 404          let mut havewidth = false;
 405          if self.consume('0') {
 406              // small ambiguity with '0$' as a format string. In theory this is a
 407              // '0' flag and then an ill-formatted format string with just a '$'
 408              // and no count, but this is better if we instead interpret this as
 409              // no '0' flag and '0$' as the width instead.
 410              if self.consume('$') {
 411                  spec.width = CountIsParam(0);
 412                  havewidth = true;
 413              } else {
 414                  spec.flags |= 1 << (FlagSignAwareZeroPad as uint);
 415              }
 416          }
 417          if !havewidth {
 418              spec.width = self.count();
 419          }
 420          if self.consume('.') {
 421              if self.consume('*') {
 422                  spec.precision = CountIsNextParam;
 423              } else {
 424                  spec.precision = self.count();
 425              }
 426          }
 427          // Finally the actual format specifier
 428          if self.consume('?') {
 429              spec.ty = "?";
 430          } else {
 431              spec.ty = self.word();
 432          }
 433          return spec;
 434      }
 435  
 436      /// Parses a method to be applied to the previously specified argument and
 437      /// its format. The two current supported methods are 'plural' and 'select'
 438      fn method(&mut self) -> Option<~Method<'a>> {
 439          if !self.wsconsume(',') {
 440              return None;
 441          }
 442          self.ws();
 443          match self.word() {
 444              "select" => {
 445                  self.must_consume(',');
 446                  Some(self.select())
 447              }
 448              "plural" => {
 449                  self.must_consume(',');
 450                  Some(self.plural())
 451              }
 452              "" => {
 453                  self.err("expected method after comma");
 454                  return None;
 455              }
 456              method => {
 457                  self.err(format!("unknown method: `{}`", method));
 458                  return None;
 459              }
 460          }
 461      }
 462  
 463      /// Parses a 'select' statement (after the initial 'select' word)
 464      fn select(&mut self) -> ~Method<'a> {
 465          let mut other = None;
 466          let mut arms = vec!();
 467          // Consume arms one at a time
 468          loop {
 469              self.ws();
 470              let selector = self.word();
 471              if selector == "" {
 472                  self.err("cannot have an empty selector");
 473                  break
 474              }
 475              self.must_consume('{');
 476              self.depth += 1;
 477              let pieces = self.collect();
 478              self.depth -= 1;
 479              self.must_consume('}');
 480              if selector == "other" {
 481                  if !other.is_none() {
 482                      self.err("multiple `other` statements in `select");
 483                  }
 484                  other = Some(pieces);
 485              } else {
 486                  arms.push(SelectArm { selector: selector, result: pieces });
 487              }
 488              self.ws();
 489              match self.cur.clone().next() {
 490                  Some((_, '}')) => { break }
 491                  Some(..) | None => {}
 492              }
 493          }
 494          // The "other" selector must be present
 495          let other = match other {
 496              Some(arm) => { arm }
 497              None => {
 498                  self.err("`select` statement must provide an `other` case");
 499                  vec!()
 500              }
 501          };
 502          ~Select(arms, other)
 503      }
 504  
 505      /// Parses a 'plural' statement (after the initial 'plural' word)
 506      fn plural(&mut self) -> ~Method<'a> {
 507          let mut offset = None;
 508          let mut other = None;
 509          let mut arms = vec!();
 510  
 511          // First, attempt to parse the 'offset:' field. We know the set of
 512          // selector words which can appear in plural arms, and the only ones
 513          // which start with 'o' are "other" and "offset", hence look two
 514          // characters deep to see if we can consume the word "offset"
 515          self.ws();
 516          let mut it = self.cur.clone();
 517          match it.next() {
 518              Some((_, 'o')) => {
 519                  match it.next() {
 520                      Some((_, 'f')) => {
 521                          let word = self.word();
 522                          if word != "offset" {
 523                              self.err(format!("expected `offset`, found `{}`",
 524                                               word));
 525                          } else {
 526                              self.must_consume(':');
 527                              match self.integer() {
 528                                  Some(i) => { offset = Some(i); }
 529                                  None => {
 530                                      self.err("offset must be an integer");
 531                                  }
 532                              }
 533                          }
 534                      }
 535                      Some(..) | None => {}
 536                  }
 537              }
 538              Some(..) | None => {}
 539          }
 540  
 541          // Next, generate all the arms
 542          loop {
 543              let mut isother = false;
 544              let selector = if self.wsconsume('=') {
 545                  match self.integer() {
 546                      Some(i) => Literal(i),
 547                      None => {
 548                          self.err("plural `=` selectors must be followed by an \
 549                                    integer");
 550                          Literal(0)
 551                      }
 552                  }
 553              } else {
 554                  let word = self.word();
 555                  match word {
 556                      "other" => { isother = true; Keyword(Zero) }
 557                      "zero"  => Keyword(Zero),
 558                      "one"   => Keyword(One),
 559                      "two"   => Keyword(Two),
 560                      "few"   => Keyword(Few),
 561                      "many"  => Keyword(Many),
 562                      word    => {
 563                          self.err(format!("unexpected plural selector `{}`",
 564                                           word));
 565                          if word == "" {
 566                              break
 567                          } else {
 568                              Keyword(Zero)
 569                          }
 570                      }
 571                  }
 572              };
 573              self.must_consume('{');
 574              self.depth += 1;
 575              let pieces = self.collect();
 576              self.depth -= 1;
 577              self.must_consume('}');
 578              if isother {
 579                  if !other.is_none() {
 580                      self.err("multiple `other` statements in `select");
 581                  }
 582                  other = Some(pieces);
 583              } else {
 584                  arms.push(PluralArm { selector: selector, result: pieces });
 585              }
 586              self.ws();
 587              match self.cur.clone().next() {
 588                  Some((_, '}')) => { break }
 589                  Some(..) | None => {}
 590              }
 591          }
 592  
 593          let other = match other {
 594              Some(arm) => { arm }
 595              None => {
 596                  self.err("`plural` statement must provide an `other` case");
 597                  vec!()
 598              }
 599          };
 600          ~Plural(offset, arms, other)
 601      }
 602  
 603      /// Parses a Count parameter at the current position. This does not check
 604      /// for 'CountIsNextParam' because that is only used in precision, not
 605      /// width.
 606      fn count(&mut self) -> Count<'a> {
 607          match self.integer() {
 608              Some(i) => {
 609                  if self.consume('$') {
 610                      CountIsParam(i)
 611                  } else {
 612                      CountIs(i)
 613                  }
 614              }
 615              None => {
 616                  let tmp = self.cur.clone();
 617                  match self.word() {
 618                      word if word.len() > 0 && self.consume('$') => {
 619                          CountIsName(word)
 620                      }
 621                      _ => {
 622                          self.cur = tmp;
 623                          CountImplied
 624                      }
 625                  }
 626              }
 627          }
 628      }
 629  
 630      /// Parses a word starting at the current position. A word is considered to
 631      /// be an alphabetic character followed by any number of alphanumeric
 632      /// characters.
 633      fn word(&mut self) -> &'a str {
 634          let start = match self.cur.clone().next() {
 635              Some((pos, c)) if char::is_XID_start(c) => {
 636                  self.cur.next();
 637                  pos
 638              }
 639              Some(..) | None => { return self.input.slice(0, 0); }
 640          };
 641          let mut end;
 642          loop {
 643              match self.cur.clone().next() {
 644                  Some((_, c)) if char::is_XID_continue(c) => {
 645                      self.cur.next();
 646                  }
 647                  Some((pos, _)) => { end = pos; break }
 648                  None => { end = self.input.len(); break }
 649              }
 650          }
 651          self.input.slice(start, end)
 652      }
 653  
 654      /// Optionally parses an integer at the current position. This doesn't deal
 655      /// with overflow at all, it's just accumulating digits.
 656      fn integer(&mut self) -> Option<uint> {
 657          let mut cur = 0;
 658          let mut found = false;
 659          loop {
 660              match self.cur.clone().next() {
 661                  Some((_, c)) => {
 662                      match char::to_digit(c, 10) {
 663                          Some(i) => {
 664                              cur = cur * 10 + i;
 665                              found = true;
 666                              self.cur.next();
 667                          }
 668                          None => { break }
 669                      }
 670                  }
 671                  None => { break }
 672              }
 673          }
 674          if found {
 675              return Some(cur);
 676          } else {
 677              return None;
 678          }
 679      }
 680  }
 681  
 682  #[cfg(test)]
 683  mod tests {
 684      use super::*;
 685      use prelude::*;
 686  
 687      fn same(fmt: &'static str, p: &[Piece<'static>]) {
 688          let mut parser = Parser::new(fmt);
 689          assert!(p == parser.collect::<Vec<Piece<'static>>>().as_slice());
 690      }
 691  
 692      fn fmtdflt() -> FormatSpec<'static> {
 693          return FormatSpec {
 694              fill: None,
 695              align: AlignUnknown,
 696              flags: 0,
 697              precision: CountImplied,
 698              width: CountImplied,
 699              ty: "",
 700          }
 701      }
 702  
 703      fn musterr(s: &str) {
 704          let mut p = Parser::new(s);
 705          p.next();
 706          assert!(p.errors.len() != 0);
 707      }
 708  
 709      #[test]
 710      fn simple() {
 711          same("asdf", [String("asdf")]);
 712          same("a\\{b", [String("a"), String("{b")]);
 713          same("a\\#b", [String("a"), String("#b")]);
 714          same("a\\}b", [String("a"), String("}b")]);
 715          same("a\\}", [String("a"), String("}")]);
 716          same("\\}", [String("}")]);
 717      }
 718  
 719      #[test] fn invalid01() { musterr("{") }
 720      #[test] fn invalid02() { musterr("\\") }
 721      #[test] fn invalid03() { musterr("\\a") }
 722      #[test] fn invalid04() { musterr("{3a}") }
 723      #[test] fn invalid05() { musterr("{:|}") }
 724      #[test] fn invalid06() { musterr("{:>>>}") }
 725  
 726      #[test]
 727      fn format_nothing() {
 728          same("{}", [Argument(Argument {
 729              position: ArgumentNext,
 730              format: fmtdflt(),
 731              method: None,
 732          })]);
 733      }
 734      #[test]
 735      fn format_position() {
 736          same("{3}", [Argument(Argument {
 737              position: ArgumentIs(3),
 738              format: fmtdflt(),
 739              method: None,
 740          })]);
 741      }
 742      #[test]
 743      fn format_position_nothing_else() {
 744          same("{3:}", [Argument(Argument {
 745              position: ArgumentIs(3),
 746              format: fmtdflt(),
 747              method: None,
 748          })]);
 749      }
 750      #[test]
 751      fn format_type() {
 752          same("{3:a}", [Argument(Argument {
 753              position: ArgumentIs(3),
 754              format: FormatSpec {
 755                  fill: None,
 756                  align: AlignUnknown,
 757                  flags: 0,
 758                  precision: CountImplied,
 759                  width: CountImplied,
 760                  ty: "a",
 761              },
 762              method: None,
 763          })]);
 764      }
 765      #[test]
 766      fn format_align_fill() {
 767          same("{3:>}", [Argument(Argument {
 768              position: ArgumentIs(3),
 769              format: FormatSpec {
 770                  fill: None,
 771                  align: AlignRight,
 772                  flags: 0,
 773                  precision: CountImplied,
 774                  width: CountImplied,
 775                  ty: "",
 776              },
 777              method: None,
 778          })]);
 779          same("{3:0<}", [Argument(Argument {
 780              position: ArgumentIs(3),
 781              format: FormatSpec {
 782                  fill: Some('0'),
 783                  align: AlignLeft,
 784                  flags: 0,
 785                  precision: CountImplied,
 786                  width: CountImplied,
 787                  ty: "",
 788              },
 789              method: None,
 790          })]);
 791          same("{3:*<abcd}", [Argument(Argument {
 792              position: ArgumentIs(3),
 793              format: FormatSpec {
 794                  fill: Some('*'),
 795                  align: AlignLeft,
 796                  flags: 0,
 797                  precision: CountImplied,
 798                  width: CountImplied,
 799                  ty: "abcd",
 800              },
 801              method: None,
 802          })]);
 803      }
 804      #[test]
 805      fn format_counts() {
 806          same("{:10s}", [Argument(Argument {
 807              position: ArgumentNext,
 808              format: FormatSpec {
 809                  fill: None,
 810                  align: AlignUnknown,
 811                  flags: 0,
 812                  precision: CountImplied,
 813                  width: CountIs(10),
 814                  ty: "s",
 815              },
 816              method: None,
 817          })]);
 818          same("{:10$.10s}", [Argument(Argument {
 819              position: ArgumentNext,
 820              format: FormatSpec {
 821                  fill: None,
 822                  align: AlignUnknown,
 823                  flags: 0,
 824                  precision: CountIs(10),
 825                  width: CountIsParam(10),
 826                  ty: "s",
 827              },
 828              method: None,
 829          })]);
 830          same("{:.*s}", [Argument(Argument {
 831              position: ArgumentNext,
 832              format: FormatSpec {
 833                  fill: None,
 834                  align: AlignUnknown,
 835                  flags: 0,
 836                  precision: CountIsNextParam,
 837                  width: CountImplied,
 838                  ty: "s",
 839              },
 840              method: None,
 841          })]);
 842          same("{:.10$s}", [Argument(Argument {
 843              position: ArgumentNext,
 844              format: FormatSpec {
 845                  fill: None,
 846                  align: AlignUnknown,
 847                  flags: 0,
 848                  precision: CountIsParam(10),
 849                  width: CountImplied,
 850                  ty: "s",
 851              },
 852              method: None,
 853          })]);
 854          same("{:a$.b$s}", [Argument(Argument {
 855              position: ArgumentNext,
 856              format: FormatSpec {
 857                  fill: None,
 858                  align: AlignUnknown,
 859                  flags: 0,
 860                  precision: CountIsName("b"),
 861                  width: CountIsName("a"),
 862                  ty: "s",
 863              },
 864              method: None,
 865          })]);
 866      }
 867      #[test]
 868      fn format_flags() {
 869          same("{:-}", [Argument(Argument {
 870              position: ArgumentNext,
 871              format: FormatSpec {
 872                  fill: None,
 873                  align: AlignUnknown,
 874                  flags: (1 << FlagSignMinus as uint),
 875                  precision: CountImplied,
 876                  width: CountImplied,
 877                  ty: "",
 878              },
 879              method: None,
 880          })]);
 881          same("{:+#}", [Argument(Argument {
 882              position: ArgumentNext,
 883              format: FormatSpec {
 884                  fill: None,
 885                  align: AlignUnknown,
 886                  flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
 887                  precision: CountImplied,
 888                  width: CountImplied,
 889                  ty: "",
 890              },
 891              method: None,
 892          })]);
 893      }
 894      #[test]
 895      fn format_mixture() {
 896          same("abcd {3:a} efg", [String("abcd "), Argument(Argument {
 897              position: ArgumentIs(3),
 898              format: FormatSpec {
 899                  fill: None,
 900                  align: AlignUnknown,
 901                  flags: 0,
 902                  precision: CountImplied,
 903                  width: CountImplied,
 904                  ty: "a",
 905              },
 906              method: None,
 907          }), String(" efg")]);
 908      }
 909  
 910      #[test]
 911      fn select_simple() {
 912          same("{, select, other { haha } }", [Argument(Argument{
 913              position: ArgumentNext,
 914              format: fmtdflt(),
 915              method: Some(~Select(vec![], vec![String(" haha ")]))
 916          })]);
 917          same("{1, select, other { haha } }", [Argument(Argument{
 918              position: ArgumentIs(1),
 919              format: fmtdflt(),
 920              method: Some(~Select(vec![], vec![String(" haha ")]))
 921          })]);
 922          same("{1, select, other {#} }", [Argument(Argument{
 923              position: ArgumentIs(1),
 924              format: fmtdflt(),
 925              method: Some(~Select(vec![], vec![CurrentArgument]))
 926          })]);
 927          same("{1, select, other {{2, select, other {lol}}} }", [Argument(Argument{
 928              position: ArgumentIs(1),
 929              format: fmtdflt(),
 930              method: Some(~Select(vec![], vec![Argument(Argument{
 931                  position: ArgumentIs(2),
 932                  format: fmtdflt(),
 933                  method: Some(~Select(vec![], vec![String("lol")]))
 934              })])) // wat
 935          })]);
 936      }
 937  
 938      #[test]
 939      fn select_cases() {
 940          same("{1, select, a{1} b{2} c{3} other{4} }", [Argument(Argument{
 941              position: ArgumentIs(1),
 942              format: fmtdflt(),
 943              method: Some(~Select(vec![
 944                  SelectArm{ selector: "a", result: vec![String("1")] },
 945                  SelectArm{ selector: "b", result: vec![String("2")] },
 946                  SelectArm{ selector: "c", result: vec![String("3")] },
 947              ], vec![String("4")]))
 948          })]);
 949      }
 950  
 951      #[test] fn badselect01() { musterr("{select, }") }
 952      #[test] fn badselect02() { musterr("{1, select}") }
 953      #[test] fn badselect03() { musterr("{1, select, }") }
 954      #[test] fn badselect04() { musterr("{1, select, a {}}") }
 955      #[test] fn badselect05() { musterr("{1, select, other }}") }
 956      #[test] fn badselect06() { musterr("{1, select, other {}") }
 957      #[test] fn badselect07() { musterr("{select, other {}") }
 958      #[test] fn badselect08() { musterr("{1 select, other {}") }
 959      #[test] fn badselect09() { musterr("{:d select, other {}") }
 960      #[test] fn badselect10() { musterr("{1:d select, other {}") }
 961  
 962      #[test]
 963      fn plural_simple() {
 964          same("{, plural, other { haha } }", [Argument(Argument{
 965              position: ArgumentNext,
 966              format: fmtdflt(),
 967              method: Some(~Plural(None, vec![], vec![String(" haha ")]))
 968          })]);
 969          same("{:, plural, other { haha } }", [Argument(Argument{
 970              position: ArgumentNext,
 971              format: fmtdflt(),
 972              method: Some(~Plural(None, vec![], vec![String(" haha ")]))
 973          })]);
 974          same("{, plural, offset:1 =2{2} =3{3} many{yes} other{haha} }",
 975          [Argument(Argument{
 976              position: ArgumentNext,
 977              format: fmtdflt(),
 978              method: Some(~Plural(Some(1), vec![
 979                  PluralArm{ selector: Literal(2), result: vec![String("2")] },
 980                  PluralArm{ selector: Literal(3), result: vec![String("3")] },
 981                  PluralArm{ selector: Keyword(Many), result: vec![String("yes")] }
 982              ], vec![String("haha")]))
 983          })]);
 984      }
 985  }


libstd/fmt/parse.rs:182:16-182:16 -struct- definition:
pub struct SelectArm<'a> {
    /// String selector which guards this arm
    pub selector: &'a str,
references:- 9
485:             } else {
486:                 arms.push(SelectArm { selector: selector, result: pieces });
487:             }


libstd/fmt/parse.rs:144:31-144:31 -enum- definition:
pub enum PluralSelector {
    /// One of the plural keywords should be used
    Keyword(PluralKeyword),
references:- 6
143: /// A selector for what pluralization a plural method should take
145: pub enum PluralSelector {
--
156:     /// literal.
157:     pub selector: PluralSelector,
158:     /// Array of pieces which are the format of this arm


libstd/fmt/parse.rs:195:78-195:78 -struct- definition:
/// necessary there's probably lots of room for improvement performance-wise.
pub struct Parser<'a> {
    input: &'a str,
references:- 4
204: impl<'a> Iterator<Piece<'a>> for Parser<'a> {
205:     fn next(&mut self) -> Option<Piece<'a>> {
--
233:     /// Creates a new parser for the given format string
234:     pub fn new<'a>(s: &'a str) -> Parser<'a> {
235:         Parser {
236:             input: s,


libstd/fmt/parse.rs:106:16-106:16 -enum- definition:
pub enum Count<'a> {
    /// The count is specified explicitly.
    CountIs(uint),
references:- 6
105: /// can reference either an argument or a literal integer.
107: pub enum Count<'a> {
--
605:     /// width.
606:     fn count(&mut self) -> Count<'a> {
607:         match self.integer() {


libstd/fmt/parse.rs:48:16-48:16 -struct- definition:
pub struct FormatSpec<'a> {
    /// Optionally specified character to fill alignment with
    pub fill: Option<char>,
references:- 10
47: /// Specification for the formatting of an argument in the format string.
49: pub struct FormatSpec<'a> {
--
362:     /// relevant information in the FormatSpec struct.
363:     fn format(&mut self) -> FormatSpec<'a> {
364:         let mut spec = FormatSpec {
365:             fill: None,


libstd/fmt/parse.rs:90:16-90:16 -enum- definition:
pub enum Flag {
    /// A `+` will be used to denote positive numbers.
    FlagSignPlus,
references:- 3
89: /// flags is defined by the formatters themselves.
91: pub enum Flag {


libstd/fmt/parse.rs:78:16-78:16 -enum- definition:
pub enum Alignment {
    /// The value will be aligned to the left.
    AlignLeft,
references:- 7
77: /// Enum of alignments which are supported.
79: pub enum Alignment {
libstd/fmt/mod.rs:
520:     /// Boolean indication of whether the output should be left-aligned
521:     pub align: parse::Alignment,
522:     /// Optionally specified integer width that the output should be
--
1056:                     padding: uint,
1057:                     default: parse::Alignment,
1058:                     f: |&mut Formatter| -> Result) -> Result {
libstd/fmt/rt.rs:
37:     pub fill: char,
38:     pub align: parse::Alignment,
39:     pub flags: uint,


libstd/fmt/parse.rs:67:16-67:16 -enum- definition:
pub enum Position<'a> {
    /// The argument will be in the next position. This is the default.
    ArgumentNext,
references:- 5
66: /// Enum describing where an argument for a format can be located.
68: pub enum Position<'a> {
--
346:     /// integer index of an argument, a named argument, or a blank string.
347:     fn position(&mut self) -> Position<'a> {
348:         match self.integer() {


libstd/fmt/parse.rs:153:16-153:16 -struct- definition:
pub struct PluralArm<'a> {
    /// A selector can either be specified by a keyword or with an integer
    /// literal.
references:- 9
152: /// Structure representing one "arm" of the `plural` function.
154: pub struct PluralArm<'a> {
--
583:             } else {
584:                 arms.push(PluralArm { selector: selector, result: pieces });
585:             }


libstd/fmt/parse.rs:122:16-122:16 -enum- definition:
pub enum Method<'a> {
    /// A plural method selects on an integer over a list of either integer or
    /// keyword-defined clauses. The meaning of the keywords is defined by the
references:- 7
505:     /// Parses a 'plural' statement (after the initial 'plural' word)
506:     fn plural(&mut self) -> ~Method<'a> {
507:         let mut offset = None;


libstd/fmt/parse.rs:167:22-167:22 -enum- definition:
pub enum PluralKeyword {
    /// The plural form for zero objects.
    Zero,
references:- 7
146:     /// One of the plural keywords should be used
147:     Keyword(PluralKeyword),
148:     /// A literal pluralization should be used
--
165: /// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html
libstd/fmt/rt.rs:
57: pub enum PluralSelector {
58:     Keyword(parse::PluralKeyword),
59:     Literal(uint),
libstd/fmt/parse.rs:
165: /// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html


libstd/fmt/parse.rs:24:16-24:16 -enum- definition:
pub enum Piece<'a> {
    /// A literal string which should directly be emitted
    String(&'a str),
references:- 9
133:     /// always required to be specified.
134:     Plural(Option<uint>, Vec<PluralArm<'a>>, Vec<Piece<'a>>),
--
158:     /// Array of pieces which are the format of this arm
159:     pub result: Vec<Piece<'a>>,
160: }
--
186:     /// Array of pieces which are the format of this arm
187:     pub result: Vec<Piece<'a>>,
188: }
--
204: impl<'a> Iterator<Piece<'a>> for Parser<'a> {
205:     fn next(&mut self) -> Option<Piece<'a>> {
206:         match self.cur.clone().next() {


libstd/fmt/parse.rs:37:16-37:16 -struct- definition:
pub struct Argument<'a> {
    /// Where to find this argument
    pub position: Position<'a>,
references:- 10
36: /// Representation of an argument specification.
38: pub struct Argument<'a> {
--
336:     /// the format string
337:     fn argument(&mut self) -> Argument<'a> {
338:         Argument {
339:             position: self.position(),