summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorOliver Schneider <git-no-reply-9879165716479413131@oli-obk.de>2017-01-10 22:13:53 +0100
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2017-01-19 10:13:32 +0100
commitc951341a78a9d3cc7c73130ca08cbc273af72082 (patch)
tree8f1fcf8edef8caa33ef15f5121e66d10981e00e4 /src/libsyntax
parent74c42ac173bee900979870ed986c760596d1fbdb (diff)
downloadrust-c951341a78a9d3cc7c73130ca08cbc273af72082.tar.gz
rust-c951341a78a9d3cc7c73130ca08cbc273af72082.zip
add exclusive range patterns under a feature gate
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs10
-rw-r--r--src/libsyntax/feature_gate.rs9
-rw-r--r--src/libsyntax/fold.rs14
-rw-r--r--src/libsyntax/parse/parser.rs43
-rw-r--r--src/libsyntax/print/pprust.rs9
-rw-r--r--src/libsyntax/visit.rs4
6 files changed, 67 insertions, 22 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 58487655ac1..d18215be3e6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -548,6 +548,12 @@ pub enum BindingMode {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum RangeEnd {
+    Included,
+    Excluded,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum PatKind {
     /// Represents a wildcard pattern (`_`)
     Wild,
@@ -583,8 +589,8 @@ pub enum PatKind {
     Ref(P<Pat>, Mutability),
     /// A literal
     Lit(P<Expr>),
-    /// A range pattern, e.g. `1...2`
-    Range(P<Expr>, P<Expr>),
+    /// A range pattern, e.g. `1...2` or `1..2`
+    Range(P<Expr>, P<Expr>, RangeEnd),
     /// `[a, b, ..i, y, z]` is represented as:
     ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`
     Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ba6e752d310..17b9fdf2e7c 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -26,7 +26,7 @@ use self::AttributeType::*;
 use self::AttributeGate::*;
 
 use abi::Abi;
-use ast::{self, NodeId, PatKind};
+use ast::{self, NodeId, PatKind, RangeEnd};
 use attr;
 use codemap::{CodeMap, Spanned};
 use syntax_pos::Span;
@@ -248,6 +248,9 @@ declare_features! (
     // a...b and ...b
     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
 
+    // X..Y patterns
+    (active, exclusive_range_pattern, "1.11.0", Some(37854)),
+
     // impl specialization (RFC 1210)
     (active, specialization, "1.7.0", Some(31844)),
 
@@ -1262,6 +1265,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     }
                 }
             }
+            PatKind::Range(_, _, RangeEnd::Excluded) => {
+                gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
+                                   "exclusive range pattern syntax is experimental");
+            }
             _ => {}
         }
         visit::walk_pat(self, pattern)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 2e5ce739fb3..bc8d13d800c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -112,6 +112,10 @@ pub trait Folder : Sized {
         e.map(|e| noop_fold_expr(e, self))
     }
 
+    fn fold_range_end(&mut self, re: RangeEnd) -> RangeEnd {
+        noop_fold_range_end(re, self)
+    }
+
     fn fold_opt_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
         noop_fold_opt_expr(e, self)
     }
@@ -1095,8 +1099,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
             }
             PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
             PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
-            PatKind::Range(e1, e2) => {
-                PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
+            PatKind::Range(e1, e2, end) => {
+                PatKind::Range(folder.fold_expr(e1),
+                               folder.fold_expr(e2),
+                               folder.fold_range_end(end))
             },
             PatKind::Slice(before, slice, after) => {
                 PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
@@ -1109,6 +1115,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
     })
 }
 
+pub fn noop_fold_range_end<T: Folder>(end: RangeEnd, _folder: &mut T) -> RangeEnd {
+    end
+}
+
 pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mut T) -> Expr {
     Expr {
         node: match node {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d1a683b0bd5..1ddfa16e622 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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};
@@ -3445,8 +3446,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)) {
@@ -3462,8 +3462,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 {
@@ -3578,6 +3577,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);
@@ -3627,11 +3642,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
@@ -3658,14 +3669,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() {
@@ -3699,7 +3715,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);
                         }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index baa3ebec854..2c513df88de 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -11,7 +11,7 @@
 pub use self::AnnNode::*;
 
 use abi::{self, Abi};
-use ast::{self, BlockCheckMode, PatKind};
+use ast::{self, BlockCheckMode, PatKind, RangeEnd};
 use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 use ast::Attribute;
 use util::parser::AssocOp;
@@ -2553,10 +2553,13 @@ impl<'a> State<'a> {
                 self.print_pat(&inner)?;
             }
             PatKind::Lit(ref e) => self.print_expr(&**e)?,
-            PatKind::Range(ref begin, ref end) => {
+            PatKind::Range(ref begin, ref end, ref end_kind) => {
                 self.print_expr(&begin)?;
                 space(&mut self.s)?;
-                word(&mut self.s, "...")?;
+                match *end_kind {
+                    RangeEnd::Included => word(&mut self.s, "...")?,
+                    RangeEnd::Excluded => word(&mut self.s, "..")?,
+                }
                 self.print_expr(&end)?;
             }
             PatKind::Slice(ref before, ref slice, ref after) => {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 1fcfce18948..bfab7a250c6 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -440,9 +440,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             walk_list!(visitor, visit_pat, optional_subpattern);
         }
         PatKind::Lit(ref expression) => visitor.visit_expr(expression),
-        PatKind::Range(ref lower_bound, ref upper_bound) => {
+        PatKind::Range(ref lower_bound, ref upper_bound, _) => {
             visitor.visit_expr(lower_bound);
-            visitor.visit_expr(upper_bound)
+            visitor.visit_expr(upper_bound);
         }
         PatKind::Wild => (),
         PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {