about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-03-06 07:16:41 +0000
committerbors <bors@rust-lang.org>2016-03-06 07:16:41 +0000
commit8484831d29392857d18f420e3fc69180306bf122 (patch)
treef6e519c31cf318e88ce8fae02b7ee8e2a0c43b73 /src/libsyntax/parse
parent45f0ce71c19d8da081714dc917f11a8cc02d15be (diff)
parent430b3e19606cf76288a383b89428107756d4aa61 (diff)
downloadrust-8484831d29392857d18f420e3fc69180306bf122.tar.gz
rust-8484831d29392857d18f420e3fc69180306bf122.zip
Auto merge of #30884 - durka:inclusive-ranges, r=aturon
This PR implements [RFC 1192](https://github.com/rust-lang/rfcs/blob/master/text/1192-inclusive-ranges.md), which is triple-dot syntax for inclusive range expressions. The new stuff is behind two feature gates (one for the syntax and one for the std::ops types). This replaces the deprecated functionality in std::iter. Along the way I simplified the desugaring for all ranges.

This is my first contribution to rust which changes more than one character outside of a test or comment, so please review carefully! Some of the individual commit messages have more of my notes. Also thanks for putting up with my dumb questions in #rust-internals.

- For implementing `std::ops::RangeInclusive`, I took @Stebalien's suggestion from https://github.com/rust-lang/rfcs/pull/1192#issuecomment-137864421. It seemed to me to make the implementation easier and increase type safety. If that stands, the RFC should be amended to avoid confusion.
- I also kind of like @glaebhoerl's [idea](https://github.com/rust-lang/rfcs/pull/1254#issuecomment-147815299), which is unified inclusive/exclusive range syntax something like `x>..=y`. We can experiment with this while everything is behind a feature gate.
- There are a couple of FIXMEs left (see the last commit). I didn't know what to do about `RangeArgument` and I haven't added `Index` impls yet. Those should be discussed/finished before merging.

cc @Gankro since you [complained](https://www.reddit.com/r/rust/comments/3xkfro/what_happened_to_inclusive_ranges/cy5j0yq)
cc #27777 #30877 rust-lang/rust#1192 rust-lang/rfcs#1254
relevant to #28237 (tracking issue)
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs85
-rw-r--r--src/libsyntax/parse/token.rs2
2 files changed, 50 insertions, 37 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e166a367219..d9714cc1e25 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -20,7 +20,7 @@ use ast::{BlockCheckMode, CaptureBy};
 use ast::{Constness, Crate, CrateConfig};
 use ast::{Decl, DeclKind};
 use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf};
-use ast::{Expr, ExprKind};
+use ast::{Expr, ExprKind, RangeLimits};
 use ast::{Field, FnDecl};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use ast::{Ident, ImplItem, Item, ItemKind};
@@ -2059,9 +2059,10 @@ impl<'a> Parser<'a> {
 
     pub fn mk_range(&mut self,
                     start: Option<P<Expr>>,
-                    end: Option<P<Expr>>)
+                    end: Option<P<Expr>>,
+                    limits: RangeLimits)
                     -> ast::ExprKind {
-        ExprKind::Range(start, end)
+        ExprKind::Range(start, end, limits)
     }
 
     pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind {
@@ -2899,7 +2900,7 @@ impl<'a> Parser<'a> {
                 LhsExpr::AttributesParsed(attrs) => Some(attrs),
                 _ => None,
             };
-            if self.token == token::DotDot {
+            if self.token == token::DotDot || self.token == token::DotDotDot {
                 return self.parse_prefix_range_expr(attrs);
             } else {
                 try!(self.parse_prefix_expr(attrs))
@@ -2945,32 +2946,32 @@ impl<'a> Parser<'a> {
                                    ExprKind::Type(lhs, rhs), None);
                 continue
             } else if op == AssocOp::DotDot {
-                    // If we didn’t have to handle `x..`, it would be pretty easy to generalise
-                    // it to the Fixity::None code.
-                    //
-                    // We have 2 alternatives here: `x..y` and `x..` The other two variants are
-                    // handled with `parse_prefix_range_expr` call above.
-                    let rhs = if self.is_at_start_of_range_notation_rhs() {
-                        let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
-                                                             LhsExpr::NotYetParsed);
-                        match rhs {
-                            Ok(e) => Some(e),
-                            Err(mut e) => {
-                                e.cancel();
-                                None
-                            }
+                // If we didn’t have to handle `x..`, it would be pretty easy to generalise
+                // it to the Fixity::None code.
+                //
+                // We have 2 alternatives here: `x..y` and `x..` The other two variants are
+                // handled with `parse_prefix_range_expr` call above.
+                let rhs = if self.is_at_start_of_range_notation_rhs() {
+                    let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
+                                                         LhsExpr::NotYetParsed);
+                    match rhs {
+                        Ok(e) => Some(e),
+                        Err(mut e) => {
+                            e.cancel();
+                            None
                         }
-                    } else {
-                        None
-                    };
-                    let (lhs_span, rhs_span) = (lhs_span, if let Some(ref x) = rhs {
-                        x.span
-                    } else {
-                        cur_op_span
-                    });
-                    let r = self.mk_range(Some(lhs), rhs);
-                    lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
-                    break
+                    }
+                } else {
+                    None
+                };
+                let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs {
+                    x.span
+                } else {
+                    cur_op_span
+                });
+                let r = self.mk_range(Some(lhs), rhs, RangeLimits::HalfOpen);
+                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
+                break
             }
 
             let rhs = try!(match op.fixity() {
@@ -2986,8 +2987,8 @@ impl<'a> Parser<'a> {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
                 }),
-                // We currently have no non-associative operators that are not handled above by
-                // the special cases. The code is here only for future convenience.
+                // the only operator handled here is `...` (the other non-associative operators are
+                // special-cased above)
                 Fixity::None => self.with_res(
                     restrictions - Restrictions::RESTRICTION_STMT_EXPR,
                     |this| {
@@ -3028,6 +3029,11 @@ impl<'a> Parser<'a> {
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
                     self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
                 }
+                AssocOp::DotDotDot => {
+                    let (lhs_span, rhs_span) = (lhs.span, rhs.span);
+                    let r = self.mk_range(Some(lhs), Some(rhs), RangeLimits::Closed);
+                    self.mk_expr(lhs_span.lo, rhs_span.hi, r, None)
+                }
                 AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
                     self.bug("As, Colon or DotDot branch reached")
                 }
@@ -3059,18 +3065,19 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse prefix-forms of range notation: `..expr` and `..`
+    /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr`
     fn parse_prefix_range_expr(&mut self,
                                already_parsed_attrs: Option<ThinAttributes>)
                                -> PResult<'a, P<Expr>> {
-        debug_assert!(self.token == token::DotDot);
+        debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot);
+        let tok = self.token.clone();
         let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
         let lo = self.span.lo;
         let mut hi = self.span.hi;
         self.bump();
         let opt_end = if self.is_at_start_of_range_notation_rhs() {
-            // RHS must be parsed with more associativity than DotDot.
-            let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1;
+            // RHS must be parsed with more associativity than the dots.
+            let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1;
             Some(try!(self.parse_assoc_expr_with(next_prec,
                                                  LhsExpr::NotYetParsed)
             .map(|x|{
@@ -3080,7 +3087,13 @@ impl<'a> Parser<'a> {
          } else {
             None
         };
-        let r = self.mk_range(None, opt_end);
+        let r = self.mk_range(None,
+                              opt_end,
+                              if tok == token::DotDot {
+                                  RangeLimits::HalfOpen
+                              } else {
+                                  RangeLimits::Closed
+                              });
         Ok(self.mk_expr(lo, hi, r, attrs))
     }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 6593b3ea532..294cbf35895 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -196,7 +196,7 @@ impl Token {
             BinOp(Or)                   => true, // in lambda syntax
             OrOr                        => true, // in lambda syntax
             AndAnd                      => true, // double borrow
-            DotDot                      => true, // range notation
+            DotDot | DotDotDot          => true, // range notation
             ModSep                      => true,
             Interpolated(NtExpr(..))    => true,
             Interpolated(NtIdent(..))   => true,