diff options
| author | bors <bors@rust-lang.org> | 2016-03-06 07:16:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-03-06 07:16:41 +0000 |
| commit | 8484831d29392857d18f420e3fc69180306bf122 (patch) | |
| tree | f6e519c31cf318e88ce8fae02b7ee8e2a0c43b73 /src/libsyntax/parse | |
| parent | 45f0ce71c19d8da081714dc917f11a8cc02d15be (diff) | |
| parent | 430b3e19606cf76288a383b89428107756d4aa61 (diff) | |
| download | rust-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.rs | 85 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 2 |
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, |
