diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 23bb6fd141a4ed22112dafd8655e705cc50ded19..0dbfb2c7be65470ee70d7a0f22d771bfd6f0071a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -886,6 +886,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +/// Limit types of a range (inclusive or exclusive) +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum RangeLimits { + /// Inclusive at the beginning, exclusive at the end + HalfOpen, + /// Inclusive at the beginning and end + Closed, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ExprKind { /// A `box x` expression. @@ -974,8 +983,8 @@ pub enum ExprKind { TupField(P, Spanned), /// An indexing operation (`foo[2]`) Index(P, P), - /// A range (`1..2`, `1..`, or `..2`) - Range(Option>, Option>), + /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`) + Range(Option>, Option>, RangeLimits), /// Variable reference, possibly containing `::` and/or type /// parameters, e.g. foo::bar::. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d75e8f796ae891143d18c56ccfe6c4eb5cf0d996..591c1295d66412746f56666c518b54af33b89441 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1273,9 +1273,10 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Index(el, er) => { ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er)) } - ExprKind::Range(e1, e2) => { + ExprKind::Range(e1, e2, lim) => { ExprKind::Range(e1.map(|x| folder.fold_expr(x)), - e2.map(|x| folder.fold_expr(x))) + e2.map(|x| folder.fold_expr(x)), + lim) } ExprKind::Path(qself, path) => { let qself = qself.map(|QSelf { ty, position }| { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b5d29a0d6dbaf11f3e335bd5f7d1f2e3f8baf574..8b563ef00f31e14aeb9410d3054f2a4c8ae06102 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -20,7 +20,7 @@ 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}; @@ -2054,9 +2054,10 @@ pub fn mk_index(&mut self, expr: P, idx: P) -> ast::ExprKind { pub fn mk_range(&mut self, start: Option>, - end: Option>) - -> ast::ExprKind { - ExprKind::Range(start, end) + end: Option>, + limits: RangeLimits) + -> ast::Expr_ { + ExprKind::Range(start, end, limits) } pub fn mk_field(&mut self, expr: P, ident: ast::SpannedIdent) -> ast::ExprKind { @@ -2894,7 +2895,7 @@ pub fn parse_assoc_expr_with(&mut self, 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)) @@ -2940,32 +2941,32 @@ pub fn parse_assoc_expr_with(&mut self, 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() { @@ -2981,8 +2982,8 @@ pub fn parse_assoc_expr_with(&mut self, 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| { @@ -3023,6 +3024,11 @@ pub fn parse_assoc_expr_with(&mut self, 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") } @@ -3054,18 +3060,19 @@ fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { } } - /// 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) -> PResult<'a, P> { - 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|{ @@ -3075,7 +3082,13 @@ fn parse_prefix_range_expr(&mut self, } 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 accbb54c629b243220c4bdb33caa5f39349af5b4..0c59c240bcdd81bedeb0d5a810a7427a6f29ec95 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -196,7 +196,7 @@ pub fn can_begin_expr(&self) -> bool { 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, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b4e08d65a0a8d7a228aeb0b39cedb1399325ed53..8d81787d922473c9d1f09b1e31fc146f183eb36e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2163,11 +2163,15 @@ fn print_expr_outer_attr_style(&mut self, try!(self.print_expr(&index)); try!(word(&mut self.s, "]")); } - ast::ExprKind::Range(ref start, ref end) => { + ast::ExprKing::Range(ref start, ref end, limits) => { if let &Some(ref e) = start { try!(self.print_expr(&e)); } - try!(word(&mut self.s, "..")); + if limits == ast::RangeLimits::HalfOpen { + try!(word(&mut self.s, "..")); + } else { + try!(word(&mut self.s, "...")); + } if let &Some(ref e) = end { try!(self.print_expr(&e)); } diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 6fb81bb6a768421d89397ac8d652125619f5ba27..df4eb1c9ed7d8053ac5382f817c502e42d4d608c 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -61,6 +61,8 @@ pub enum AssocOp { As, /// `..` range DotDot, + /// `...` range + DotDotDot, /// `:` Colon, } @@ -102,6 +104,7 @@ pub fn from_token(t: &Token) -> Option { Token::AndAnd => Some(LAnd), Token::OrOr => Some(LOr), Token::DotDot => Some(DotDot), + Token::DotDotDot => Some(DotDotDot), Token::Colon => Some(Colon), _ if t.is_keyword(keywords::As) => Some(As), _ => None @@ -147,7 +150,7 @@ pub fn precedence(&self) -> usize { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, LAnd => 6, LOr => 5, - DotDot => 4, + DotDot | DotDotDot => 4, Inplace => 3, Assign | AssignOp(_) => 2, } @@ -162,7 +165,7 @@ pub fn fixity(&self) -> Fixity { As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, - DotDot => Fixity::None + DotDot | DotDotDot => Fixity::None } } @@ -171,7 +174,8 @@ pub fn is_comparison(&self) -> bool { match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | - ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | Colon => false + ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | + DotDot | DotDotDot | Colon => false } } @@ -181,7 +185,7 @@ pub fn is_assign_like(&self) -> bool { Assign | AssignOp(_) | Inplace => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | - LOr | DotDot | Colon => false + LOr | DotDot | DotDotDot | Colon => false } } @@ -206,7 +210,7 @@ pub fn to_ast_binop(&self) -> Option { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None + Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f26610b8b8d14613ec1f237e168719f1840832e0..73ad488e55c931d1e6e4a87d695a76cc541a3e0b 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -763,7 +763,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } - ExprKind::Range(ref start, ref end) => { + ExprKind::Range(ref start, ref end, _) => { walk_list!(visitor, visit_expr, start); walk_list!(visitor, visit_expr, end); }