Fix prefix range expressions being not parsed

This commit is contained in:
Simonas Kazlauskas 2015-10-15 21:37:21 +03:00
parent 884b58913a
commit 58c299f81d
2 changed files with 77 additions and 74 deletions

View File

@ -2602,53 +2602,50 @@ impl<'a> Parser<'a> {
pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> {
let lo = self.span.lo;
let hi;
// Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr()
let ex;
match self.token {
token::Not => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
ex = self.mk_unary(UnNot, e);
}
token::BinOp(token::Minus) => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
ex = self.mk_unary(UnNeg, e);
}
token::BinOp(token::Star) => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
ex = self.mk_unary(UnDeref, e);
}
token::BinOp(token::And) | token::AndAnd => {
try!(self.expect_and());
let m = try!(self.parse_mutability());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
ex = ExprAddrOf(m, e);
}
token::Ident(..) if self.token.is_keyword(keywords::In) => {
try!(self.bump());
let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let blk = try!(self.parse_block());
let span = blk.span;
hi = span.hi;
let blk_expr = self.mk_expr(span.lo, span.hi, ExprBlock(blk));
self.span_warn(span, "in PLACE BLOCK syntax is deprecated and will be removed soon");
ex = ExprInPlace(place, blk_expr);
}
token::Ident(..) if self.token.is_keyword(keywords::Box) => {
try!(self.bump());
let subexpression = try!(self.parse_prefix_expr());
hi = subexpression.span.hi;
ex = ExprBox(subexpression);
}
_ => return self.parse_dot_or_call_expr()
}
let ex = match self.token {
token::Not => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
self.mk_unary(UnNot, e)
}
token::BinOp(token::Minus) => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
self.mk_unary(UnNeg, e)
}
token::BinOp(token::Star) => {
try!(self.bump());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
self.mk_unary(UnDeref, e)
}
token::BinOp(token::And) | token::AndAnd => {
try!(self.expect_and());
let m = try!(self.parse_mutability());
let e = try!(self.parse_prefix_expr());
hi = e.span.hi;
ExprAddrOf(m, e)
}
token::Ident(..) if self.token.is_keyword(keywords::In) => {
try!(self.bump());
let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let blk = try!(self.parse_block());
let span = blk.span;
hi = span.hi;
let blk_expr = self.mk_expr(span.lo, span.hi, ExprBlock(blk));
ExprInPlace(place, blk_expr)
}
token::Ident(..) if self.token.is_keyword(keywords::Box) => {
try!(self.bump());
let subexpression = try!(self.parse_prefix_expr());
hi = subexpression.span.hi;
ExprBox(subexpression)
}
_ => return self.parse_dot_or_call_expr()
};
return Ok(self.mk_expr(lo, hi, ex));
}
@ -2657,35 +2654,15 @@ impl<'a> Parser<'a> {
/// This parses an expression accounting for associativity and precedence of the operators in
/// the expression.
pub fn parse_assoc_expr(&mut self) -> PResult<P<Expr>> {
if self.token == token::DotDot {
// prefix-form of range notation `..expr` and `..`
// This has the precedence just higher than assignment expressions (much lower than
// other prefix expressions) to be consistent with the postfix-form `expr..`
// If it isnt clear yet, this is a hack of the worst kind (one that also probably
// cant be fixed anymore because stability guarantees).
let lo = self.span.lo;
let mut hi = self.span.hi;
try!(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;
let end = try!(self.parse_assoc_expr_with(next_prec, None));
hi = end.span.hi;
Some(end)
} else {
None
};
let r = self.mk_range(None, opt_end);
Ok(self.mk_expr(lo, hi, r))
} else {
self.parse_assoc_expr_with(0, None)
}
self.parse_assoc_expr_with(0, None)
}
/// Parse an associative expression with operators of at least `min_prec` precedence
pub fn parse_assoc_expr_with(&mut self, min_prec: usize, lhs: Option<P<Expr>>) -> PResult<P<Expr>> {
let mut lhs = if lhs.is_some() {
lhs.unwrap()
} else if self.token == token::DotDot {
return self.parse_prefix_range_expr();
} else {
try!(self.parse_prefix_expr())
};
@ -2710,13 +2687,10 @@ impl<'a> Parser<'a> {
continue
} else if op == AssocOp::DotDot {
// If we didnt have to handle `x..`, it would be pretty easy to generalise
// here by simply doing something along the lines of
//
// break_from_this_loop_after_setting_lhs = true;
// rhs = self.parse_assoc_expr_with(op.precedence() + 1, None);
// it to the Fixity::None code.
//
// We have 2 alternatives here: `x..y` and `x..` The other two variants are
// handled in `parse_assoc_expr`
// handled with `parse_prefix_range_expr` call above.
let rhs = if self.is_at_start_of_range_notation_rhs() {
self.parse_assoc_expr_with(op.precedence() + 1, None).ok()
} else {
@ -2800,6 +2774,26 @@ impl<'a> Parser<'a> {
}
}
/// Parse prefix-forms of range notation: `..expr` and `..`
fn parse_prefix_range_expr(&mut self) -> PResult<P<Expr>> {
debug_assert!(self.token == token::DotDot);
let lo = self.span.lo;
let mut hi = self.span.hi;
try!(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;
Some(try!(self.parse_assoc_expr_with(next_prec, None).map(|x|{
hi = x.span.hi;
x
})))
} else {
None
};
let r = self.mk_range(None, opt_end);
Ok(self.mk_expr(lo, hi, r))
}
fn is_at_start_of_range_notation_rhs(&self) -> bool {
if self.token.can_begin_expr() {
// parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.

View File

@ -1,3 +1,12 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use parse::token::{Token, BinOpToken, keywords};
use ast;