libsyntax: parse inclusive ranges
This commit is contained in:
parent
c5d58de665
commit
5daf13cae3
7 changed files with 81 additions and 50 deletions
|
@ -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>.
|
||||||
|
|
|
@ -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 }| {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue