From 06b034ae8b418beab7d0767a9a8d29023558d701 Mon Sep 17 00:00:00 2001 From: Wang Xuerui Date: Tue, 17 May 2016 01:02:42 +0800 Subject: [PATCH] format: remove all implicit ref handling outside of libfmt_macros format: beautifully get rid of ArgumentNext and CountIsNextParam Now that CountIsNextParam and ArgumentNext are resolved during parse, the need for handling them outside of libfmt_macros is obviated. Note: *one* instance of implicit reference handling still remains, and that's for implementing `all_args_simple`. It's trivial enough though, so in this case it may be tolerable. --- src/libfmt_macros/lib.rs | 59 +++++++++++++------------------- src/librustc_typeck/check/mod.rs | 2 +- src/libsyntax_ext/format.rs | 29 +++++++--------- 3 files changed, 36 insertions(+), 54 deletions(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 983f92d9e19d..e7d401f0929f 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -80,8 +80,6 @@ pub struct FormatSpec<'a> { /// Enum describing where an argument for a format can be located. #[derive(Copy, Clone, PartialEq)] pub enum Position<'a> { - /// The argument will be in the next position. This is the default. - ArgumentNext, /// The argument is located at a specific index. ArgumentIs(usize), /// The argument has a name. @@ -127,8 +125,6 @@ pub enum Count<'a> { CountIsName(&'a str), /// The count is specified by the argument at the given index. CountIsParam(usize), - /// The count is specified by the next parameter. - CountIsNextParam, /// The count is implied and cannot be explicitly specified. CountImplied, } @@ -262,37 +258,18 @@ impl<'a> Parser<'a> { /// Parses an Argument structure, or what's contained within braces inside /// the format string fn argument(&mut self) -> Argument<'a> { - let mut pos = self.position(); - let mut format = self.format(); + let pos = self.position(); + let format = self.format(); - // Resolve CountIsNextParam's into absolute references. - // Current argument's position must be known so this is done after - // format parsing. - // Curiously, currently {:.*} for named arguments is implemented, - // and it consumes a positional arg slot just like a positional {:.*} - // does. The current behavior is reproduced to prevent any - // incompatibilities. - match format.precision { - CountIsNextParam => { - // eat the current implicit arg + // Resolve position after parsing format spec. + let pos = match pos { + Some(position) => position, + None => { let i = self.curarg; self.curarg += 1; - format.precision = CountIsParam(i); + ArgumentIs(i) } - _ => {} - } - - // Resolve ArgumentNext's into absolute references. - // This must come after count resolution because we may consume one - // more arg if precision is CountIsNextParam. - match pos { - ArgumentNext => { - let i = self.curarg; - self.curarg += 1; - pos = ArgumentIs(i); - } - _ => {} - } + }; Argument { position: pos, @@ -302,13 +279,19 @@ impl<'a> Parser<'a> { /// Parses a positional argument for a format. This could either be an /// integer index of an argument, a named argument, or a blank string. - fn position(&mut self) -> Position<'a> { + /// Returns `Some(parsed_position)` if the position is not implicitly + /// consuming a macro argument, `None` if it's the case. + fn position(&mut self) -> Option> { if let Some(i) = self.integer() { - ArgumentIs(i) + Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if c.is_alphabetic() => ArgumentNamed(self.word()), - _ => ArgumentNext, + Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())), + + // This is an `ArgumentNext`. + // Record the fact and do the resolution after parsing the + // format spec, to make things like `{:.*}` work. + _ => None, } } } @@ -375,7 +358,11 @@ impl<'a> Parser<'a> { } if self.consume('.') { if self.consume('*') { - spec.precision = CountIsNextParam; + // Resolve `CountIsNextParam`. + // We can do this immediately as `position` is resolved later. + let i = self.curarg; + self.curarg += 1; + spec.precision = CountIsParam(i); } else { spec.precision = self.count(); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8daa16180a90..fc1d2236f3fe 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -881,7 +881,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }, // `{:1}` and `{}` are not to be used - Position::ArgumentIs(_) | Position::ArgumentNext => { + Position::ArgumentIs(_) => { span_err!(ccx.tcx.sess, attr.span, E0231, "only named substitution \ parameters are allowed"); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index dc572e652c67..c0150e5ce1d9 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -68,8 +68,10 @@ struct Context<'a, 'b:'a> { name_positions: HashMap, - /// Updated as arguments are consumed - next_arg: usize, + /// Current position of the implicit positional arg pointer, as if it + /// still existed in this phase of processing. + /// Used only for `all_pieces_simple` tracking in `trans_piece`. + curarg: usize, } /// Parses the arguments from the given list of tokens, returning None @@ -159,11 +161,6 @@ impl<'a, 'b> Context<'a, 'b> { // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { - parse::ArgumentNext => { - let i = self.next_arg; - self.next_arg += 1; - Exact(i) - } parse::ArgumentIs(i) => Exact(i), parse::ArgumentNamed(s) => Named(s.to_string()), }; @@ -183,11 +180,6 @@ impl<'a, 'b> Context<'a, 'b> { parse::CountIsName(s) => { self.verify_arg_type(Named(s.to_string()), Unsigned); } - parse::CountIsNextParam => { - let next_arg = self.next_arg; - self.verify_arg_type(Exact(next_arg), Unsigned); - self.next_arg += 1; - } } } @@ -309,7 +301,6 @@ impl<'a, 'b> Context<'a, 'b> { count("Param", Some(self.ecx.expr_usize(sp, i))) } parse::CountImplied => count("Implied", None), - parse::CountIsNextParam => count("NextParam", None), parse::CountIsName(n) => { let i = match self.name_positions.get(n) { Some(&i) => i, @@ -355,8 +346,6 @@ impl<'a, 'b> Context<'a, 'b> { } }; match arg.position { - // These two have a direct mapping - parse::ArgumentNext => pos("Next", None), parse::ArgumentIs(i) => pos("At", Some(i)), // Named arguments are converted to positional arguments @@ -373,7 +362,13 @@ impl<'a, 'b> Context<'a, 'b> { }; let simple_arg = parse::Argument { - position: parse::ArgumentNext, + position: { + // We don't have ArgumentNext any more, so we have to + // track the current argument ourselves. + let i = self.curarg; + self.curarg += 1; + parse::ArgumentIs(i) + }, format: parse::FormatSpec { fill: arg.format.fill, align: parse::AlignUnknown, @@ -640,7 +635,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, name_positions: HashMap::new(), name_types: HashMap::new(), name_ordering: name_ordering, - next_arg: 0, + curarg: 0, literal: String::new(), pieces: Vec::new(), str_pieces: Vec::new(),