about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWang Xuerui <idontknw.wang@gmail.com>2016-05-17 01:02:42 +0800
committerWang Xuerui <idontknw.wang@gmail.com>2016-07-14 02:54:47 +0800
commit06b034ae8b418beab7d0767a9a8d29023558d701 (patch)
treedeeae34e65e8aef561d7d04b9873c134ca9b24bd
parent71949f3b0dfdacbddc0c012accefbb8e8ec759d4 (diff)
downloadrust-06b034ae8b418beab7d0767a9a8d29023558d701.tar.gz
rust-06b034ae8b418beab7d0767a9a8d29023558d701.zip
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.
-rw-r--r--src/libfmt_macros/lib.rs59
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/libsyntax_ext/format.rs29
3 files changed, 36 insertions, 54 deletions
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 983f92d9e19..e7d401f0929 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();
-
-        // 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
-                let i = self.curarg;
-                self.curarg += 1;
-                format.precision = CountIsParam(i);
-            }
-            _ => {}
-        }
+        let pos = self.position();
+        let format = self.format();
 
-        // 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 => {
+        // Resolve position after parsing format spec.
+        let pos = match pos {
+            Some(position) => position,
+            None => {
                 let i = self.curarg;
                 self.curarg += 1;
-                pos = ArgumentIs(i);
+                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<Position<'a>> {
         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 8daa16180a9..fc1d2236f3f 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 dc572e652c6..c0150e5ce1d 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<String, usize>,
 
-    /// 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(),