Auto merge of #35712 - oli-obk:exclusive_range_patterns, r=nikomatsakis

exclusive range patterns

adds `..` patterns to the language under a feature gate (`exclusive_range_pattern`).

This allows turning

``` rust
match i {
    0...9 => {},
    10...19 => {},
    20...29 => {},
    _ => {}
}
```

into

``` rust
match i {
    0..10 => {},
    10..20 => {},
    20..30 => {},
    _ => {}
}
```
This commit is contained in:
bors 2017-01-25 02:17:33 +00:00
commit c0d0e68be4
25 changed files with 269 additions and 67 deletions

View file

@ -38,6 +38,7 @@ use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
use ast::{BinOpKind, UnOp};
use ast::RangeEnd;
use {ast, attr};
use codemap::{self, CodeMap, Spanned, spanned, respan};
use syntax_pos::{self, Span, Pos, BytePos, mk_sp};
@ -3329,8 +3330,7 @@ impl<'a> Parser<'a> {
}
if before_slice {
if self.check(&token::DotDot) {
self.bump();
if self.eat(&token::DotDot) {
if self.check(&token::Comma) ||
self.check(&token::CloseDelim(token::Bracket)) {
@ -3346,8 +3346,7 @@ impl<'a> Parser<'a> {
}
let subpat = self.parse_pat()?;
if before_slice && self.check(&token::DotDot) {
self.bump();
if before_slice && self.eat(&token::DotDot) {
slice = Some(subpat);
before_slice = false;
} else if before_slice {
@ -3462,6 +3461,22 @@ impl<'a> Parser<'a> {
}
}
// helper function to decide whether to parse as ident binding or to try to do
// something more complex like range patterns
fn parse_as_ident(&mut self) -> bool {
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => Some(false),
// ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the
// range pattern branch
token::DotDot => None,
_ => Some(true),
}).unwrap_or_else(|| self.look_ahead(2, |t| match *t {
token::Comma | token::CloseDelim(token::Bracket) => true,
_ => false,
}))
}
/// Parse a pattern.
pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
maybe_whole!(self, NtPat, |x| x);
@ -3511,11 +3526,7 @@ impl<'a> Parser<'a> {
let subpat = self.parse_pat()?;
pat = PatKind::Box(subpat);
} else if self.token.is_ident() && !self.token.is_any_keyword() &&
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => false,
_ => true,
}) {
self.parse_as_ident() {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve
@ -3542,14 +3553,19 @@ impl<'a> Parser<'a> {
let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
pat = PatKind::Mac(mac);
}
token::DotDotDot => {
token::DotDotDot | token::DotDot => {
let end_kind = match self.token {
token::DotDot => RangeEnd::Excluded,
token::DotDotDot => RangeEnd::Included,
_ => panic!("can only parse `..` or `...` for ranges (checked above)"),
};
// Parse range
let hi = self.prev_span.hi;
let begin =
self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
self.bump();
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end);
pat = PatKind::Range(begin, end, end_kind);
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
@ -3583,7 +3599,10 @@ impl<'a> Parser<'a> {
Ok(begin) => {
if self.eat(&token::DotDotDot) {
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end);
pat = PatKind::Range(begin, end, RangeEnd::Included);
} else if self.eat(&token::DotDot) {
let end = self.parse_pat_range_end()?;
pat = PatKind::Range(begin, end, RangeEnd::Excluded);
} else {
pat = PatKind::Lit(begin);
}