1
Fork 0

libsyntax: parse inclusive ranges

This commit is contained in:
Alex Burka 2016-01-13 01:23:31 -05:00
parent c5d58de665
commit 5daf13cae3
7 changed files with 81 additions and 50 deletions

View file

@ -886,6 +886,15 @@ impl fmt::Debug for Expr {
} }
} }
/// 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)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum ExprKind { pub enum ExprKind {
/// A `box x` expression. /// A `box x` expression.
@ -974,8 +983,8 @@ pub enum ExprKind {
TupField(P<Expr>, Spanned<usize>), TupField(P<Expr>, Spanned<usize>),
/// An indexing operation (`foo[2]`) /// An indexing operation (`foo[2]`)
Index(P<Expr>, P<Expr>), Index(P<Expr>, P<Expr>),
/// A range (`1..2`, `1..`, or `..2`) /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
Range(Option<P<Expr>>, Option<P<Expr>>), Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
/// Variable reference, possibly containing `::` and/or type /// Variable reference, possibly containing `::` and/or type
/// parameters, e.g. foo::bar::<baz>. /// parameters, e.g. foo::bar::<baz>.

View file

@ -1273,9 +1273,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
ExprKind::Index(el, er) => { ExprKind::Index(el, er) => {
ExprKind::Index(folder.fold_expr(el), folder.fold_expr(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)), 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) => { ExprKind::Path(qself, path) => {
let qself = qself.map(|QSelf { ty, position }| { let qself = qself.map(|QSelf { ty, position }| {

View file

@ -20,7 +20,7 @@ use ast::{BlockCheckMode, CaptureBy};
use ast::{Constness, Crate, CrateConfig}; use ast::{Constness, Crate, CrateConfig};
use ast::{Decl, DeclKind}; use ast::{Decl, DeclKind};
use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, ExprKind}; use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl}; use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
use ast::{Ident, ImplItem, Item, ItemKind}; use ast::{Ident, ImplItem, Item, ItemKind};
@ -2054,9 +2054,10 @@ impl<'a> Parser<'a> {
pub fn mk_range(&mut self, pub fn mk_range(&mut self,
start: Option<P<Expr>>, start: Option<P<Expr>>,
end: Option<P<Expr>>) end: Option<P<Expr>>,
-> ast::ExprKind { limits: RangeLimits)
ExprKind::Range(start, end) -> ast::Expr_ {
ExprKind::Range(start, end, limits)
} }
pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind { pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind {
@ -2894,7 +2895,7 @@ impl<'a> Parser<'a> {
LhsExpr::AttributesParsed(attrs) => Some(attrs), LhsExpr::AttributesParsed(attrs) => Some(attrs),
_ => None, _ => None,
}; };
if self.token == token::DotDot { if self.token == token::DotDot || self.token == token::DotDotDot {
return self.parse_prefix_range_expr(attrs); return self.parse_prefix_range_expr(attrs);
} else { } else {
try!(self.parse_prefix_expr(attrs)) try!(self.parse_prefix_expr(attrs))
@ -2958,12 +2959,12 @@ impl<'a> Parser<'a> {
} else { } else {
None None
}; };
let (lhs_span, rhs_span) = (lhs_span, if let Some(ref x) = rhs { let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs {
x.span x.span
} else { } else {
cur_op_span cur_op_span
}); });
let r = self.mk_range(Some(lhs), rhs); let r = self.mk_range(Some(lhs), rhs, RangeLimits::HalfOpen);
lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None); lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
break break
} }
@ -2981,8 +2982,8 @@ impl<'a> Parser<'a> {
this.parse_assoc_expr_with(op.precedence() + 1, this.parse_assoc_expr_with(op.precedence() + 1,
LhsExpr::NotYetParsed) LhsExpr::NotYetParsed)
}), }),
// We currently have no non-associative operators that are not handled above by // the only operator handled here is `...` (the other non-associative operators are
// the special cases. The code is here only for future convenience. // special-cased above)
Fixity::None => self.with_res( Fixity::None => self.with_res(
restrictions - Restrictions::RESTRICTION_STMT_EXPR, restrictions - Restrictions::RESTRICTION_STMT_EXPR,
|this| { |this| {
@ -3023,6 +3024,11 @@ impl<'a> Parser<'a> {
let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); 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) 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 => { AssocOp::As | AssocOp::Colon | AssocOp::DotDot => {
self.bug("As, Colon or DotDot branch reached") self.bug("As, Colon or DotDot branch reached")
} }
@ -3054,18 +3060,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, fn parse_prefix_range_expr(&mut self,
already_parsed_attrs: Option<ThinAttributes>) already_parsed_attrs: Option<ThinAttributes>)
-> PResult<'a, P<Expr>> { -> 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 attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
let lo = self.span.lo; let lo = self.span.lo;
let mut hi = self.span.hi; let mut hi = self.span.hi;
self.bump(); self.bump();
let opt_end = if self.is_at_start_of_range_notation_rhs() { let opt_end = if self.is_at_start_of_range_notation_rhs() {
// RHS must be parsed with more associativity than DotDot. // RHS must be parsed with more associativity than the dots.
let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1; let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1;
Some(try!(self.parse_assoc_expr_with(next_prec, Some(try!(self.parse_assoc_expr_with(next_prec,
LhsExpr::NotYetParsed) LhsExpr::NotYetParsed)
.map(|x|{ .map(|x|{
@ -3075,7 +3082,13 @@ impl<'a> Parser<'a> {
} else { } else {
None 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)) Ok(self.mk_expr(lo, hi, r, attrs))
} }

View file

@ -196,7 +196,7 @@ impl Token {
BinOp(Or) => true, // in lambda syntax BinOp(Or) => true, // in lambda syntax
OrOr => true, // in lambda syntax OrOr => true, // in lambda syntax
AndAnd => true, // double borrow AndAnd => true, // double borrow
DotDot => true, // range notation DotDot | DotDotDot => true, // range notation
ModSep => true, ModSep => true,
Interpolated(NtExpr(..)) => true, Interpolated(NtExpr(..)) => true,
Interpolated(NtIdent(..)) => true, Interpolated(NtIdent(..)) => true,

View file

@ -2163,11 +2163,15 @@ impl<'a> State<'a> {
try!(self.print_expr(&index)); try!(self.print_expr(&index));
try!(word(&mut self.s, "]")); 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 { if let &Some(ref e) = start {
try!(self.print_expr(&e)); try!(self.print_expr(&e));
} }
if limits == ast::RangeLimits::HalfOpen {
try!(word(&mut self.s, "..")); try!(word(&mut self.s, ".."));
} else {
try!(word(&mut self.s, "..."));
}
if let &Some(ref e) = end { if let &Some(ref e) = end {
try!(self.print_expr(&e)); try!(self.print_expr(&e));
} }

View file

@ -61,6 +61,8 @@ pub enum AssocOp {
As, As,
/// `..` range /// `..` range
DotDot, DotDot,
/// `...` range
DotDotDot,
/// `:` /// `:`
Colon, Colon,
} }
@ -102,6 +104,7 @@ impl AssocOp {
Token::AndAnd => Some(LAnd), Token::AndAnd => Some(LAnd),
Token::OrOr => Some(LOr), Token::OrOr => Some(LOr),
Token::DotDot => Some(DotDot), Token::DotDot => Some(DotDot),
Token::DotDotDot => Some(DotDotDot),
Token::Colon => Some(Colon), Token::Colon => Some(Colon),
_ if t.is_keyword(keywords::As) => Some(As), _ if t.is_keyword(keywords::As) => Some(As),
_ => None _ => None
@ -147,7 +150,7 @@ impl AssocOp {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
LAnd => 6, LAnd => 6,
LOr => 5, LOr => 5,
DotDot => 4, DotDot | DotDotDot => 4,
Inplace => 3, Inplace => 3,
Assign | AssignOp(_) => 2, Assign | AssignOp(_) => 2,
} }
@ -162,7 +165,7 @@ impl AssocOp {
As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
LAnd | LOr | Colon => Fixity::Left, LAnd | LOr | Colon => Fixity::Left,
DotDot => Fixity::None DotDot | DotDotDot => Fixity::None
} }
} }
@ -171,7 +174,8 @@ impl AssocOp {
match *self { match *self {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | 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 @@ impl AssocOp {
Assign | AssignOp(_) | Inplace => true, Assign | AssignOp(_) | Inplace => true,
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
LOr | DotDot | Colon => false LOr | DotDot | DotDotDot | Colon => false
} }
} }
@ -206,7 +210,7 @@ impl AssocOp {
BitOr => Some(BinOpKind::BitOr), BitOr => Some(BinOpKind::BitOr),
LAnd => Some(BinOpKind::And), LAnd => Some(BinOpKind::And),
LOr => Some(BinOpKind::Or), LOr => Some(BinOpKind::Or),
Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None
} }
} }
} }

View file

@ -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(main_expression);
visitor.visit_expr(index_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, start);
walk_list!(visitor, visit_expr, end); walk_list!(visitor, visit_expr, end);
} }