(index<- )        ./libstd/unstable/extfmt.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  //! Support for fmt! expressions.
  12  //!
  13  //! The syntax is close to that of Posix format strings:
  14  //!
  15  //! ~~~~~~
  16  //! Format := '%' Parameter? Flag* Width? Precision? Type
  17  //! Parameter := [0-9]+ '$'
  18  //! Flag := [ 0#+-]
  19  //! Width := Parameter | [0-9]+
  20  //! Precision := '.' [0-9]+
  21  //! Type := [bcdfiostuxX?]
  22  //! ~~~~~~
  23  //!
  24  //! * Parameter is the 1-based argument to apply the format to. Currently not
  25  //! implemented.
  26  //! * Flag 0 causes leading zeros to be used for padding when converting
  27  //! numbers.
  28  //! * Flag # causes the conversion to be done in an *alternative* manner.
  29  //! Currently not implemented.
  30  //! * Flag + causes signed numbers to always be prepended with a sign
  31  //! character.
  32  //! * Flag - left justifies the result
  33  //! * Width specifies the minimum field width of the result. By default
  34  //! leading spaces are added.
  35  //! * Precision specifies the minimum number of digits for integral types
  36  //! and the minimum number
  37  //! of decimal places for float.
  38  //!
  39  //! The types currently supported are:
  40  //!
  41  //! * b - bool
  42  //! * c - char
  43  //! * d - int
  44  //! * f - float
  45  //! * i - int (same as d)
  46  //! * o - uint as octal
  47  //! * t - uint as binary
  48  //! * u - uint
  49  //! * x - uint as lower-case hexadecimal
  50  //! * X - uint as upper-case hexadecimal
  51  //! * s - str (any flavor)
  52  //! * ? - arbitrary type (does not use the to_str trait)
  53  
  54  /*
  55  Syntax Extension: fmt
  56  
  57  Format a string
  58  
  59  The 'fmt' extension is modeled on the posix printf system.
  60  
  61  A posix conversion ostensibly looks like this
  62  
  63  > %~[parameter]~[flags]~[width]~[.precision]~[length]type
  64  
  65  Given the different numeric type bestiary we have, we omit the 'length'
  66  parameter and support slightly different conversions for 'type'
  67  
  68  > %~[parameter]~[flags]~[width]~[.precision]type
  69  
  70  we also only support translating-to-rust a tiny subset of the possible
  71  combinations at the moment.
  72  
  73  Example:
  74  
  75  debug!("hello, %s!", "world");
  76  
  77  */
  78  
  79  use prelude::*;
  80  
  81  /*
  82   * We have a 'ct' (compile-time) module that parses format strings into a
  83   * sequence of conversions. From those conversions AST fragments are built
  84   * that call into properly-typed functions in the 'rt' (run-time) module.
  85   * Each of those run-time conversion functions accepts another conversion
  86   * description that specifies how to format its output.
  87   *
  88   * The building of the AST is currently done in a module inside the compiler,
  89   * but should migrate over here as the plugin interface is defined.
  90   */
  91  
  92  // Functions used by the fmt extension at compile time
  93  #[doc(hidden)]
  94  pub mod ct {
  95      use char;
  96      use container::Container;
  97      use prelude::*;
  98      use str;
  99  
 100      #[deriving(Eq)]
 101      pub enum Signedness { Signed, Unsigned, }
 102  
 103      #[deriving(Eq)]
 104      pub enum Caseness { CaseUpper, CaseLower, }
 105  
 106      #[deriving(Eq)]
 107      pub enum Ty {
 108          TyBool,
 109          TyStr,
 110          TyChar,
 111          TyInt(Signedness),
 112          TyBits,
 113          TyHex(Caseness),
 114          TyOctal,
 115          TyFloat,
 116          TyPointer,
 117          TyPoly,
 118      }
 119  
 120      #[deriving(Eq)]
 121      pub enum Flag {
 122          FlagLeftJustify,
 123          FlagLeftZeroPad,
 124          FlagSpaceForSign,
 125          FlagSignAlways,
 126          FlagAlternate,
 127      }
 128  
 129      #[deriving(Eq)]
 130      pub enum Count {
 131          CountIs(uint),
 132          CountIsParam(uint),
 133          CountIsNextParam,
 134          CountImplied,
 135      }
 136  
 137      #[deriving(Eq)]
 138      struct Parsed<T> {
 139          val: T,
 140          next: uint
 141      }
 142  
 143      impl<T> Parsed<T> {
 144          pub fn new(valT, nextuint) -> Parsed<T> {
 145              Parsed {val: val, next: next}
 146          }
 147      }
 148  
 149      // A formatted conversion from an expression to a string
 150      #[deriving(Eq)]
 151      pub struct Conv {
 152          param: Option<uint>,
 153          flags: ~[Flag],
 154          width: Count,
 155          precision: Count,
 156          ty: Ty
 157      }
 158  
 159      // A fragment of the output sequence
 160      #[deriving(Eq)]
 161      pub enum Piece {
 162          PieceString(~str),
 163          PieceConv(Conv),
 164      }
 165  
 166      pub type ErrorFn<'self> = &'self fn(&str) -> !;
 167  
 168      pub fn parse_fmt_string<'a>(s&str, errErrorFn<'a>) -> ~[Piece] {
 169          fn push_slice(ps&mut ~[Piece], s&str, fromuint, touint) {
 170              if to > from {
 171                  ps.push(PieceString(s.slice(from, to).to_owned()));
 172              }
 173          }
 174  
 175          let lim = s.len();
 176          let mut h = 0;
 177          let mut i = 0;
 178          let mut pieces = ~[];
 179  
 180          while i < lim {
 181              if s[i] == '%' as u8 {
 182                  i += 1;
 183  
 184                  if i >= lim {
 185                      err("unterminated conversion at end of string");
 186                  } else if s[i] == '%' as u8 {
 187                      push_slice(&mut pieces, s, h, i);
 188                      i += 1;
 189                  } else {
 190                      push_slice(&mut pieces, s, h, i - 1);
 191                      let Parsed {
 192                          val,
 193                          next
 194                      } = parse_conversion(s, i, lim, |s| err(s));
 195                      pieces.push(val);
 196                      i = next;
 197                  }
 198  
 199                  h = i;
 200              } else {
 201                  i += str::utf8_char_width(s[i]);
 202              }
 203          }
 204  
 205          push_slice(&mut pieces, s, h, i);
 206          pieces
 207      }
 208  
 209      pub fn peek_num(s&str, iuint, limuint) -> Option<Parsed<uint>> {
 210          let mut i = i;
 211          let mut accum = 0;
 212          let mut found = false;
 213  
 214          while i < lim {
 215              match char::to_digit(s[i] as char, 10) {
 216                  Some(x) => {
 217                      found = true;
 218                      accum *= 10;
 219                      accum += x;
 220                      i += 1;
 221                  }
 222                  None => break
 223              }
 224          }
 225  
 226          if found {
 227              Some(Parsed::new(accum, i))
 228          } else {
 229              None
 230          }
 231      }
 232  
 233      pub fn parse_conversion<'a>(s&str, iuint, limuint, errErrorFn<'a>)
 234                                  -> Parsed<Piece> {
 235          let param = parse_parameter(s, i, lim);
 236          // avoid copying ~[Flag] by destructuring
 237          let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
 238              param.next, lim);
 239          let width = parse_count(s, flags_next, lim);
 240          let prec = parse_precision(s, width.next, lim);
 241          let ty = parse_type(s, prec.next, lim, err);
 242  
 243          Parsed::new(PieceConv(Conv {
 244              param: param.val,
 245              flags: flags_val,
 246              width: width.val,
 247              precision: prec.val,
 248              ty: ty.val}), ty.next)
 249      }
 250  
 251      pub fn parse_parameter(s&str, iuint, limuint) ->
 252          Parsed<Option<uint>> {
 253          if i >= lim { return Parsed::new(None, i); }
 254  
 255          match peek_num(s, i, lim) {
 256              Some(num) if num.next < lim && s[num.next] == '$' as u8 =>
 257                  Parsed::new(Some(num.val), num.next + 1),
 258              _ => Parsed::new(None, i)
 259          }
 260      }
 261  
 262      pub fn parse_flags(s&str, iuint, limuint) -> Parsed<~[Flag]> {
 263          let mut i = i;
 264          let mut flags = ~[];
 265  
 266          while i < lim {
 267              let f = match s[i] as char {
 268                  '-' => FlagLeftJustify,
 269                  '0' => FlagLeftZeroPad,
 270                  ' ' => FlagSpaceForSign,
 271                  '+' => FlagSignAlways,
 272                  '#' => FlagAlternate,
 273                  _ => break
 274              };
 275  
 276              flags.push(f);
 277              i += 1;
 278          }
 279  
 280          Parsed::new(flags, i)
 281      }
 282  
 283      pub fn parse_count(s&str, iuint, limuint) -> Parsed<Count> {
 284          if i >= lim {
 285              Parsed::new(CountImplied, i)
 286          } else if s[i] == '*' as u8 {
 287              let param = parse_parameter(s, i + 1, lim);
 288              let j = param.next;
 289  
 290              match param.val {
 291                  None => Parsed::new(CountIsNextParam, j),
 292                  Some(n) => Parsed::new(CountIsParam(n), j)
 293              }
 294          } else {
 295              match peek_num(s, i, lim) {
 296                  None => Parsed::new(CountImplied, i),
 297                  Some(num) => Parsed::new(CountIs(num.val), num.next)
 298              }
 299          }
 300      }
 301  
 302      pub fn parse_precision(s&str, iuint, limuint) -> Parsed<Count> {
 303          if i < lim && s[i] == '.' as u8 {
 304              let count = parse_count(s, i + 1, lim);
 305  
 306              // If there were no digits specified, i.e. the precision
 307              // was ".", then the precision is 0
 308              match count.val {
 309                  CountImplied => Parsed::new(CountIs(0), count.next),
 310                  _ => count
 311              }
 312          } else {
 313              Parsed::new(CountImplied, i)
 314          }
 315      }
 316  
 317      pub fn parse_type<'a>(s&str, iuint, limuint, errErrorFn<'a>)
 318                            -> Parsed<Ty> {
 319          if i >= lim { err("missing type in conversion"); }
 320  
 321          // FIXME (#2249): Do we really want two signed types here?
 322          // How important is it to be printf compatible?
 323          let t = match s[i] as char {
 324              'b' => TyBool,
 325              's' => TyStr,
 326              'c' => TyChar,
 327              'd' | 'i' => TyInt(Signed),
 328              'u' => TyInt(Unsigned),
 329              'x' => TyHex(CaseLower),
 330              'X' => TyHex(CaseUpper),
 331              't' => TyBits,
 332              'o' => TyOctal,
 333              'f' => TyFloat,
 334              'p' => TyPointer,
 335              '?' => TyPoly,
 336              _ => err(format!("unknown type in conversion: {}", s.char_at(i)))
 337          };
 338  
 339          Parsed::new(t, i + 1)
 340      }
 341  
 342      #[cfg(test)]
 343      fn die(s: &str) -> ! { fail2!(s.to_owned()) }
 344  
 345      #[test]
 346      fn test_parse_count() {
 347          fn test(s: &str, count: Count, next: uint) -> bool {
 348              parse_count(s, 0, s.len()) == Parsed::new(count, next)
 349          }
 350  
 351          assert!(test("", CountImplied, 0));
 352          assert!(test("*", CountIsNextParam, 1));
 353          assert!(test("*1", CountIsNextParam, 1));
 354          assert!(test("*1$", CountIsParam(1), 3));
 355          assert!(test("123", CountIs(123), 3));
 356      }
 357  
 358      #[test]
 359      fn test_parse_flags() {
 360          fn pack(fs: &[Flag]) -> uint {
 361              fs.iter().fold(0, |p, &f| p | (1 << f as uint))
 362          }
 363  
 364          fn test(s: &str, flags: &[Flag], next: uint) {
 365              let f = parse_flags(s, 0, s.len());
 366              assert_eq!(pack(f.val), pack(flags));
 367              assert_eq!(f.next, next);
 368          }
 369  
 370          test("", [], 0);
 371          test("!#-+ 0", [], 0);
 372          test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3);
 373          test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2);
 374      }
 375  
 376      #[test]
 377      fn test_parse_fmt_string() {
 378          assert!(parse_fmt_string("foo %s bar", die) == ~[
 379              PieceString(~"foo "),
 380              PieceConv(Conv {
 381                  param: None,
 382                  flags: ~[],
 383                  width: CountImplied,
 384                  precision: CountImplied,
 385                  ty: TyStr,
 386              }),
 387              PieceString(~" bar")]);
 388  
 389          assert!(parse_fmt_string("%s", die) == ~[
 390              PieceConv(Conv {
 391                  param: None,
 392                  flags: ~[],
 393                  width: CountImplied,
 394                  precision: CountImplied,
 395                  ty: TyStr,
 396              })]);
 397  
 398          assert!(parse_fmt_string("%%%%", die) == ~[
 399              PieceString(~"%"), PieceString(~"%")]);
 400      }
 401  
 402      #[test]
 403      fn test_parse_parameter() {
 404          fn test(s: &str, param: Option<uint>, next: uint) -> bool {
 405              parse_parameter(s, 0, s.len()) == Parsed::new(param, next)
 406          }
 407  
 408          assert!(test("", None, 0));
 409          assert!(test("foo", None, 0));
 410          assert!(test("123", None, 0));
 411          assert!(test("123$", Some(123), 4));
 412      }
 413  
 414      #[test]
 415      fn test_parse_precision() {
 416          fn test(s: &str, count: Count, next: uint) -> bool {
 417              parse_precision(s, 0, s.len()) == Parsed::new(count, next)
 418          }
 419  
 420          assert!(test("", CountImplied, 0));
 421          assert!(test(".", CountIs(0), 1));
 422          assert!(test(".*", CountIsNextParam, 2));
 423          assert!(test(".*1", CountIsNextParam, 2));
 424          assert!(test(".*1$", CountIsParam(1), 4));
 425          assert!(test(".123", CountIs(123), 4));
 426      }
 427  
 428      #[test]
 429      fn test_parse_type() {
 430          fn test(s: &str, ty: Ty) -> bool {
 431              parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1)
 432          }
 433  
 434          assert!(test("b", TyBool));
 435          assert!(test("c", TyChar));
 436          assert!(test("d", TyInt(Signed)));
 437          assert!(test("f", TyFloat));
 438          assert!(test("i", TyInt(Signed)));
 439          assert!(test("o", TyOctal));
 440          assert!(test("s", TyStr));
 441          assert!(test("t", TyBits));
 442          assert!(test("x", TyHex(CaseLower)));
 443          assert!(test("X", TyHex(CaseUpper)));
 444          assert!(test("p", TyPointer));
 445          assert!(test("?", TyPoly));
 446      }
 447  
 448      #[test]
 449      #[should_fail]
 450      fn test_parse_type_missing() {
 451          parse_type("", 0, 0, die);
 452      }
 453  
 454      #[test]
 455      #[should_fail]
 456      fn test_parse_type_unknown() {
 457          parse_type("!", 0, 1, die);
 458      }
 459  
 460      #[test]
 461      fn test_peek_num() {
 462          let s1 = "";
 463          assert!(peek_num(s1, 0, s1.len()).is_none());
 464  
 465          let s2 = "foo";
 466          assert!(peek_num(s2, 0, s2.len()).is_none());
 467  
 468          let s3 = "123";
 469          assert_eq!(peek_num(s3, 0, s3.len()), Some(Parsed::new(123, 3)));
 470  
 471          let s4 = "123foo";
 472          assert_eq!(peek_num(s4, 0, s4.len()), Some(Parsed::new(123, 3)));
 473      }
 474  }
 475  
 476  // Functions used by the fmt extension at runtime. For now there are a lot of
 477  // decisions made a runtime. If it proves worthwhile then some of these
 478  // conditions can be evaluated at compile-time. For now though it's cleaner to
 479  // implement it this way, I think.
 480  #[doc(hidden)]
 481  #[allow(non_uppercase_statics)]
 482  pub mod rt {
 483      use f64;
 484      use str;
 485      use sys;
 486      use num;
 487      use vec;
 488      use option::{Some, None, Option};
 489  
 490      pub static flag_none : u32 = 0u32;
 491      pub static flag_left_justify   : u32 = 0b00000000000001u32;
 492      pub static flag_left_zero_pad  : u32 = 0b00000000000010u32;
 493      pub static flag_space_for_sign : u32 = 0b00000000000100u32;
 494      pub static flag_sign_always    : u32 = 0b00000000001000u32;
 495      pub static flag_alternate      : u32 = 0b00000000010000u32;
 496  
 497      pub enum Count { CountIs(uint), CountImplied, }
 498  
 499      pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }
 500  
 501      pub struct Conv {
 502          flags: u32,
 503          width: Count,
 504          precision: Count,
 505          ty: Ty,
 506      }
 507  
 508      pub fn conv_int(cvConv, iint, buf&mut ~str) {
 509          let radix = 10;
 510          let prec = get_int_precision(cv);
 511          let s : ~str = uint_to_str_prec(num::abs(i) as uint, radix, prec);
 512  
 513          let head = if i >= 0 {
 514              if have_flag(cv.flags, flag_sign_always) {
 515                  Some('+')
 516              } else if have_flag(cv.flags, flag_space_for_sign) {
 517                  Some(' ')
 518              } else {
 519                  None
 520              }
 521          } else { Some('-') };
 522          pad(cv, s, head, PadSigned, buf);
 523      }
 524      pub fn conv_uint(cvConv, uuint, buf&mut ~str) {
 525          let prec = get_int_precision(cv);
 526          let rs =
 527              match cv.ty {
 528                TyDefault => uint_to_str_prec(u, 10, prec),
 529                TyHexLower => uint_to_str_prec(u, 16, prec),
 530  
 531                // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
 532                // to_ascii_move and to_str_move to not do a unnecessary copy.
 533                TyHexUpper => {
 534                  let s = uint_to_str_prec(u, 16, prec);
 535                  s.to_ascii().to_upper().to_str_ascii()
 536                }
 537                TyBits => uint_to_str_prec(u, 2, prec),
 538                TyOctal => uint_to_str_prec(u, 8, prec)
 539              };
 540          pad(cv, rs, None, PadUnsigned, buf);
 541      }
 542      pub fn conv_bool(cvConv, bbool, buf&mut ~str) {
 543          let s = if b { "true" } else { "false" };
 544          // run the boolean conversion through the string conversion logic,
 545          // giving it the same rules for precision, etc.
 546          conv_str(cv, s, buf);
 547      }
 548      pub fn conv_char(cvConv, cchar, buf&mut ~str) {
 549          pad(cv, "", Some(c), PadNozero, buf);
 550      }
 551      pub fn conv_str(cvConv, s&str, buf&mut ~str) {
 552          // For strings, precision is the maximum characters
 553          // displayed
 554          let unpadded = match cv.precision {
 555              CountImplied => s,
 556              CountIs(max) => {
 557                  if (max as uint) < s.char_len() {
 558                      s.slice(0, max as uint)
 559                  } else {
 560                      s
 561                  }
 562              }
 563          };
 564          pad(cv, unpadded, None, PadNozero, buf);
 565      }
 566      pub fn conv_float(cvConv, ff64, buf&mut ~str) {
 567          let (to_str, digits) = match cv.precision {
 568                CountIs(c) => (f64::to_str_exact, c as uint),
 569                CountImplied => (f64::to_str_digits, 6u)
 570          };
 571          let s = to_str(f, digits);
 572          let head = if 0.0 <= f {
 573              if have_flag(cv.flags, flag_sign_always) {
 574                  Some('+')
 575              } else if have_flag(cv.flags, flag_space_for_sign) {
 576                  Some(' ')
 577              } else {
 578                  None
 579              }
 580          } else { None };
 581          pad(cv, s, head, PadFloat, buf);
 582      }
 583      pub fn conv_pointer<T>(cvConv, ptr*T, buf&mut ~str) {
 584          let s = ~"0x" + uint_to_str_prec(ptr as uint, 16, 1u);
 585          pad(cv, s, None, PadNozero, buf);
 586      }
 587      pub fn conv_poly<T>(cvConv, v&T, buf&mut ~str) {
 588          let s = sys::log_str(v);
 589          conv_str(cv, s, buf);
 590      }
 591  
 592      // Convert a uint to string with a minimum number of digits.  If precision
 593      // is 0 and num is 0 then the result is the empty string. Could move this
 594      // to uint: but it doesn't seem all that useful.
 595      pub fn uint_to_str_prec(numuint, radixuint, precuint) -> ~str {
 596          return if prec == 0u && num == 0u {
 597                  ~""
 598              } else {
 599                  let s = num.to_str_radix(radix);
 600                  let len = s.char_len();
 601                  if len < prec {
 602                      let diff = prec - len;
 603                      let pad = str::from_chars(vec::from_elem(diff, '0'));
 604                      pad + s
 605                  } else { s }
 606              };
 607      }
 608      pub fn get_int_precision(cvConv) -> uint {
 609          return match cv.precision {
 610                CountIs(c) => c as uint,
 611                CountImplied => 1u
 612              };
 613      }
 614  
 615      #[deriving(Eq)]
 616      pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
 617  
 618      pub fn pad(cvConv, s&str, headOption<char>, modePadMode,
 619                 buf&mut ~str) {
 620          let headsize = match head { Some(_) => 1, _ => 0 };
 621          let uwidth : uint = match cv.width {
 622              CountImplied => {
 623                  for &c in head.iter() {
 624                      buf.push_char(c);
 625                  }
 626                  return buf.push_str(s);
 627              }
 628              CountIs(width) => { width as uint }
 629          };
 630          let strlen = s.char_len() + headsize;
 631          if uwidth <= strlen {
 632              for &c in head.iter() {
 633                  buf.push_char(c);
 634              }
 635              return buf.push_str(s);
 636          }
 637          let mut padchar = ' ';
 638          let diff = uwidth - strlen;
 639          if have_flag(cv.flags, flag_left_justify) {
 640              for &c in head.iter() {
 641                  buf.push_char(c);
 642              }
 643              buf.push_str(s);
 644              do diff.times {
 645                  buf.push_char(padchar);
 646              }
 647              return;
 648          }
 649          let (might_zero_pad, signed) = match mode {
 650            PadNozero   => (false, true),
 651            PadSigned   => (true, true),
 652            PadFloat    => (true, true),
 653            PadUnsigned => (true, false)
 654          };
 655          fn have_precision(cvConv) -> bool {
 656              return match cv.precision { CountImplied => false, _ => true };
 657          }
 658          let zero_padding = {
 659              if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
 660                  (!have_precision(cv) || mode == PadFloat) {
 661                  padchar = '0';
 662                  true
 663              } else {
 664                  false
 665              }
 666          };
 667          let padstr = str::from_chars(vec::from_elem(diff, padchar));
 668          // This is completely heinous. If we have a signed value then
 669          // potentially rip apart the intermediate result and insert some
 670          // zeros. It may make sense to convert zero padding to a precision
 671          // instead.
 672  
 673          if signed && zero_padding {
 674              for &head in head.iter() {
 675                  if head == '+' || head == '-' || head == ' ' {
 676                      buf.push_char(head);
 677                      buf.push_str(padstr);
 678                      buf.push_str(s);
 679                      return;
 680                  }
 681              }
 682          }
 683          buf.push_str(padstr);
 684          for &c in head.iter() {
 685              buf.push_char(c);
 686          }
 687          buf.push_str(s);
 688      }
 689      #[inline]
 690      pub fn have_flag(flagsu32, fu32) -> bool {
 691          flags & f != 0
 692      }
 693  }
 694  
 695  // Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs
 696  #[cfg(test)]
 697  mod test {
 698      #[test]
 699      fn fmt_slice() {
 700          let s = "abc";
 701          let _s = format!("{}", s);
 702      }
 703  }

libstd/unstable/extfmt.rs:166:4-166:4 -ty- definition:
    pub type ErrorFn<'self> = &'self fn(&str) -> !;

references:-
233:     pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
317:     pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
168:     pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {


libstd/unstable/extfmt.rs:121:4-121:4 -enum- definition:
    pub enum Flag {
        FlagLeftJustify,
references:-
120:     #[deriving(Eq)]
120:     #[deriving(Eq)]
120:     #[deriving(Eq)]
153:         flags: ~[Flag],
262:     pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {


libstd/unstable/extfmt.rs:169:8-169:8 -fn- definition:
        fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
            if to > from {
references:-
190:                     push_slice(&mut pieces, s, h, i - 1);
205:         push_slice(&mut pieces, s, h, i);
187:                     push_slice(&mut pieces, s, h, i);


libstd/unstable/extfmt.rs:209:4-209:4 -fn- definition:
    pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> {
        let mut i = i;
references:-
295:             match peek_num(s, i, lim) {
255:         match peek_num(s, i, lim) {


libstd/unstable/extfmt.rs:302:4-302:4 -fn- definition:
    pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
        if i < lim && s[i] == '.' as u8 {
references:-
240:         let prec = parse_precision(s, width.next, lim);


libstd/unstable/extfmt.rs:262:4-262:4 -fn- definition:
    pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
        let mut i = i;
references:-
237:         let Parsed {val: flags_val, next: flags_next} = parse_flags(s,


libstd/unstable/extfmt.rs:616:4-616:4 -enum- definition:
    pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }

references:-
615:     #[deriving(Eq)]
615:     #[deriving(Eq)]
615:     #[deriving(Eq)]
618:     pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,


libstd/unstable/extfmt.rs:161:4-161:4 -enum- definition:
    pub enum Piece {
        PieceString(~str),
references:-
169:         fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
168:     pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
234:                                 -> Parsed<Piece> {
160:     #[deriving(Eq)]
160:     #[deriving(Eq)]
160:     #[deriving(Eq)]


libstd/unstable/extfmt.rs:151:4-151:4 -struct- definition:
    pub struct Conv {
        param: Option<uint>,
references:-
150:     #[deriving(Eq)]
150:     #[deriving(Eq)]
243:         Parsed::new(PieceConv(Conv {
150:     #[deriving(Eq)]
150:     #[deriving(Eq)]
163:         PieceConv(Conv),
150:     #[deriving(Eq)]
150:     #[deriving(Eq)]
150:     #[deriving(Eq)]


libstd/unstable/extfmt.rs:690:4-690:4 -fn- definition:
    pub fn have_flag(flags: u32, f: u32) -> bool {
        flags & f != 0
references:-
516:             } else if have_flag(cv.flags, flag_space_for_sign) {
514:             if have_flag(cv.flags, flag_sign_always) {
659:             if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
639:         if have_flag(cv.flags, flag_left_justify) {
575:             } else if have_flag(cv.flags, flag_space_for_sign) {
573:             if have_flag(cv.flags, flag_sign_always) {


libstd/unstable/extfmt.rs:618:4-618:4 -fn- definition:
    pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
               buf: &mut ~str) {
references:-
540:         pad(cv, rs, None, PadUnsigned, buf);
564:         pad(cv, unpadded, None, PadNozero, buf);
581:         pad(cv, s, head, PadFloat, buf);
522:         pad(cv, s, head, PadSigned, buf);
549:         pad(cv, "", Some(c), PadNozero, buf);
585:         pad(cv, s, None, PadNozero, buf);


libstd/unstable/extfmt.rs:317:4-317:4 -fn- definition:
    pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
                          -> Parsed<Ty> {
references:-
241:         let ty = parse_type(s, prec.next, lim, err);


libstd/unstable/extfmt.rs:233:4-233:4 -fn- definition:
    pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
                                -> Parsed<Piece> {
references:-
194:                     } = parse_conversion(s, i, lim, |s| err(s));


libstd/unstable/extfmt.rs:655:8-655:8 -fn- definition:
        fn have_precision(cv: Conv) -> bool {
            return match cv.precision { CountImplied => false, _ => true };
references:-
660:                 (!have_precision(cv) || mode == PadFloat) {


libstd/unstable/extfmt.rs:551:4-551:4 -fn- definition:
    pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
        // For strings, precision is the maximum characters
references:-
546:         conv_str(cv, s, buf);
589:         conv_str(cv, s, buf);


libstd/unstable/extfmt.rs:104:4-104:4 -enum- definition:
    pub enum Caseness { CaseUpper, CaseLower, }

references:-
103:     #[deriving(Eq)]
113:         TyHex(Caseness),
103:     #[deriving(Eq)]
103:     #[deriving(Eq)]


libstd/unstable/extfmt.rs:138:4-138:4 -struct- definition:
    struct Parsed<T> {
        val: T,
references:-
137:     #[deriving(Eq)]
144:         pub fn new(val: T, next: uint) -> Parsed<T> {
137:     #[deriving(Eq)]
143:     impl<T> Parsed<T> {
318:                           -> Parsed<Ty> {
137:     #[deriving(Eq)]
252:         Parsed<Option<uint>> {
137:     #[deriving(Eq)]
145:             Parsed {val: val, next: next}
237:         let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
302:     pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
137:     #[deriving(Eq)]
262:     pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
234:                                 -> Parsed<Piece> {
209:     pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> {
137:     #[deriving(Eq)]
283:     pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
137:     #[deriving(Eq)]
191:                     let Parsed {


libstd/unstable/extfmt.rs:251:4-251:4 -fn- definition:
    pub fn parse_parameter(s: &str, i: uint, lim: uint) ->
        Parsed<Option<uint>> {
references:-
235:         let param = parse_parameter(s, i, lim);
287:             let param = parse_parameter(s, i + 1, lim);


libstd/unstable/extfmt.rs:501:4-501:4 -struct- definition:
    pub struct Conv {
        flags: u32,
references:-
583:     pub fn conv_pointer<T>(cv: Conv, ptr: *T, buf: &mut ~str) {
524:     pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
542:     pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
551:     pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
508:     pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) {
655:         fn have_precision(cv: Conv) -> bool {
618:     pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
587:     pub fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
566:     pub fn conv_float(cv: Conv, f: f64, buf: &mut ~str) {
548:     pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
608:     pub fn get_int_precision(cv: Conv) -> uint {


libstd/unstable/extfmt.rs:130:4-130:4 -enum- definition:
    pub enum Count {
        CountIs(uint),
references:-
129:     #[deriving(Eq)]
129:     #[deriving(Eq)]
302:     pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
129:     #[deriving(Eq)]
154:         width: Count,
155:         precision: Count,
283:     pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {


libstd/unstable/extfmt.rs:499:4-499:4 -enum- definition:
    pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }

references:-
505:         ty: Ty,


libstd/unstable/extfmt.rs:608:4-608:4 -fn- definition:
    pub fn get_int_precision(cv: Conv) -> uint {
        return match cv.precision {
references:-
510:         let prec = get_int_precision(cv);
525:         let prec = get_int_precision(cv);


libstd/unstable/extfmt.rs:497:4-497:4 -enum- definition:
    pub enum Count { CountIs(uint), CountImplied, }

references:-
504:         precision: Count,
503:         width: Count,


libstd/unstable/extfmt.rs:101:4-101:4 -enum- definition:
    pub enum Signedness { Signed, Unsigned, }

references:-
111:         TyInt(Signedness),
100:     #[deriving(Eq)]
100:     #[deriving(Eq)]
100:     #[deriving(Eq)]


libstd/unstable/extfmt.rs:107:4-107:4 -enum- definition:
    pub enum Ty {
        TyBool,
references:-
156:         ty: Ty
106:     #[deriving(Eq)]
106:     #[deriving(Eq)]
106:     #[deriving(Eq)]
318:                           -> Parsed<Ty> {


libstd/unstable/extfmt.rs:283:4-283:4 -fn- definition:
    pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
        if i >= lim {
references:-
239:         let width = parse_count(s, flags_next, lim);
304:             let count = parse_count(s, i + 1, lim);


libstd/unstable/extfmt.rs:595:4-595:4 -fn- definition:
    pub fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str {
        return if prec == 0u && num == 0u {
references:-
511:         let s : ~str = uint_to_str_prec(num::abs(i) as uint, radix, prec);
584:         let s = ~"0x" + uint_to_str_prec(ptr as uint, 16, 1u);
537:               TyBits => uint_to_str_prec(u, 2, prec),
528:               TyDefault => uint_to_str_prec(u, 10, prec),
538:               TyOctal => uint_to_str_prec(u, 8, prec)
529:               TyHexLower => uint_to_str_prec(u, 16, prec),
534:                 let s = uint_to_str_prec(u, 16, prec);