Skip to content

Fix some grammar inconsistencies for the '..' range notation. #21374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3135,18 +3135,17 @@ The precedence of Rust binary operators is ordered as follows, going from
strong to weak:

```{.text .precedence}
* / %
as
* / %
+ -
<< >>
&
^
|
< > <= >=
== !=
== != < > <= >=
&&
||
=
= ..
```

Operators at the same precedence level are evaluated left-to-right. [Unary
Expand Down
3 changes: 1 addition & 2 deletions src/libsyntax/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,7 @@ pub fn operator_prec(op: ast::BinOp) -> usize {

/// Precedence of the `as` operator, which is a binary operator
/// not appearing in the prior table.
#[allow(non_upper_case_globals)]
pub static as_prec: usize = 12us;
pub const AS_PREC: usize = 12us;

pub fn empty_generics() -> Generics {
Generics {
Expand Down
54 changes: 37 additions & 17 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use ast::{UnnamedField, UnsafeBlock};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
use ast;
use ast_util::{self, as_prec, ident_to_path, operator_prec};
use ast_util::{self, AS_PREC, ident_to_path, operator_prec};
use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp};
use diagnostic;
use ext::tt::macro_parser;
Expand Down Expand Up @@ -93,7 +93,6 @@ bitflags! {
const RESTRICTION_STMT_EXPR = 0b0001,
const RESTRICTION_NO_BAR_OP = 0b0010,
const RESTRICTION_NO_STRUCT_LITERAL = 0b0100,
const RESTRICTION_NO_DOTS = 0b1000,
}
}

Expand Down Expand Up @@ -2775,13 +2774,6 @@ impl<'a> Parser<'a> {
hi = e.span.hi;
ex = ExprAddrOf(m, e);
}
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
// A range, closed above: `..expr`.
self.bump();
let e = self.parse_expr();
hi = e.span.hi;
ex = self.mk_range(None, Some(e));
}
token::Ident(_, _) => {
if !self.token.is_keyword(keywords::Box) {
return self.parse_dot_or_call_expr();
Expand Down Expand Up @@ -2855,10 +2847,10 @@ impl<'a> Parser<'a> {
self.check_no_chained_comparison(&*lhs, cur_op)
}
let cur_prec = operator_prec(cur_op);
if cur_prec > min_prec {
if cur_prec >= min_prec {
self.bump();
let expr = self.parse_prefix_expr();
let rhs = self.parse_more_binops(expr, cur_prec);
let rhs = self.parse_more_binops(expr, cur_prec + 1);
let lhs_span = lhs.span;
let rhs_span = rhs.span;
let binary = self.mk_binary(cur_op, lhs, rhs);
Expand All @@ -2869,7 +2861,7 @@ impl<'a> Parser<'a> {
}
}
None => {
if as_prec > min_prec && self.eat_keyword(keywords::As) {
if AS_PREC >= min_prec && self.eat_keyword(keywords::As) {
let rhs = self.parse_ty();
let _as = self.mk_expr(lhs.span.lo,
rhs.span.hi,
Expand Down Expand Up @@ -2905,8 +2897,24 @@ impl<'a> Parser<'a> {
/// actually, this seems to be the main entry point for
/// parsing an arbitrary expression.
pub fn parse_assign_expr(&mut self) -> P<Expr> {
let lhs = self.parse_binops();
self.parse_assign_expr_with(lhs)
match self.token {
token::DotDot => {
// prefix-form of range notation '..expr'
// This has the same precedence as assignment expressions
// (much lower than other prefix expressions) to be consistent
// with the postfix-form 'expr..'
let lo = self.span.lo;
self.bump();
let rhs = self.parse_binops();
let hi = rhs.span.hi;
let ex = self.mk_range(None, Some(rhs));
self.mk_expr(lo, hi, ex)
}
_ => {
let lhs = self.parse_binops();
self.parse_assign_expr_with(lhs)
}
}
}

pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> P<Expr> {
Expand Down Expand Up @@ -2938,11 +2946,11 @@ impl<'a> Parser<'a> {
self.mk_expr(span.lo, rhs_span.hi, assign_op)
}
// A range expression, either `expr..expr` or `expr..`.
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
token::DotDot => {
self.bump();

let opt_end = if self.token.can_begin_expr() {
let end = self.parse_expr_res(RESTRICTION_NO_DOTS);
let opt_end = if self.is_at_start_of_range_notation_rhs() {
let end = self.parse_binops();
Some(end)
} else {
None
Expand All @@ -2960,6 +2968,18 @@ impl<'a> Parser<'a> {
}
}

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..{})`.
if self.token == token::OpenDelim(token::Brace) {
return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
}
true
} else {
false
}
}

/// Parse an 'if' or 'if let' expression ('if' token already eaten)
pub fn parse_if_expr(&mut self) -> P<Expr> {
if self.token.is_keyword(keywords::Let) {
Expand Down
16 changes: 16 additions & 0 deletions src/test/compile-fail/range-3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2014 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.

// Test range syntax - syntax errors.

pub fn main() {
let r = 1..2..3;
//~^ ERROR expected one of `.`, `;`, or an operator, found `..`
}
16 changes: 16 additions & 0 deletions src/test/compile-fail/range-4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2014 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.

// Test range syntax - syntax errors.

pub fn main() {
let r = ..1..2;
//~^ ERROR expected one of `.`, `;`, or an operator, found `..`
}
7 changes: 7 additions & 0 deletions src/test/run-pass/ranges-precedence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,12 @@ fn main() {
assert!(x == &a[3..]);

for _i in 2+4..10-3 {}

let i = 42;
for _ in 1..i {}
for _ in 1.. { break; }

let x = [1]..[2];
assert!(x == (([1])..([2])));
}