Skip to content

Commit a128662

Browse files
committed
Fix precedence of '..' range notation and some grammar inconsistencies.
Fixes rust-lang#20811 and rust-lang#20241. Note: this changes the semantics of parse_more_binops() to parse binops with precedence >= min_prec. Previously, it would parse binops with precedence > min_prec.
1 parent 2e4cef4 commit a128662

File tree

5 files changed

+97
-41
lines changed

5 files changed

+97
-41
lines changed

src/doc/reference.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,15 +3134,15 @@ The precedence of Rust binary operators is ordered as follows, going from
31343134
strong to weak:
31353135

31363136
```{.text .precedence}
3137-
* / %
31383137
as
3138+
* / %
31393139
+ -
31403140
<< >>
31413141
&
31423142
^
31433143
|
3144-
< > <= >=
3145-
== !=
3144+
..
3145+
== != < > <= >=
31463146
&&
31473147
||
31483148
=

src/libsyntax/ast_util.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,24 +321,36 @@ pub fn struct_field_visibility(field: ast::StructField) -> Visibility {
321321
/// Maps a binary operator to its precedence
322322
pub fn operator_prec(op: ast::BinOp) -> uint {
323323
match op {
324+
// prefix expressions sit here with 13
324325
// 'as' sits here with 12
325326
BiMul | BiDiv | BiRem => 11u,
326327
BiAdd | BiSub => 10u,
327328
BiShl | BiShr => 9u,
328329
BiBitAnd => 8u,
329330
BiBitXor => 7u,
330331
BiBitOr => 6u,
332+
// '..' sits here with 5
331333
BiLt | BiLe | BiGe | BiGt | BiEq | BiNe => 3u,
332334
BiAnd => 2u,
333335
BiOr => 1u
334336
}
335337
}
336338

339+
/// Precedence of the prefix operators '!', '-', '&', '*', '~' etc.
340+
/// Does not include the prefix form of '..'
341+
#[allow(non_upper_case_globals)]
342+
pub static prefix_prec: uint = 13u;
343+
337344
/// Precedence of the `as` operator, which is a binary operator
338345
/// not appearing in the prior table.
339346
#[allow(non_upper_case_globals)]
340347
pub static as_prec: uint = 12u;
341348

349+
// Precedence of '..', which exists as a binary operator,
350+
// and as unary operators (prefix and postfix form)
351+
#[allow(non_upper_case_globals)]
352+
pub static range_prec: uint = 5u;
353+
342354
pub fn empty_generics() -> Generics {
343355
Generics {
344356
lifetimes: Vec::new(),

src/libsyntax/parse/parser.rs

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use ast::{ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
6262
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
6363
use ast::{Visibility, WhereClause};
6464
use ast;
65-
use ast_util::{self, as_prec, ident_to_path, operator_prec};
65+
use ast_util::{self, prefix_prec, as_prec, range_prec, ident_to_path, operator_prec};
6666
use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp};
6767
use diagnostic;
6868
use ext::tt::macro_parser;
@@ -93,7 +93,6 @@ bitflags! {
9393
const RESTRICTION_STMT_EXPR = 0b0001,
9494
const RESTRICTION_NO_BAR_OP = 0b0010,
9595
const RESTRICTION_NO_STRUCT_LITERAL = 0b0100,
96-
const RESTRICTION_NO_DOTS = 0b1000,
9796
}
9897
}
9998

@@ -2769,34 +2768,35 @@ impl<'a> Parser<'a> {
27692768
}
27702769

27712770
/// Parse a prefix-operator expr
2772-
pub fn parse_prefix_expr(&mut self) -> P<Expr> {
2771+
/// only operators with a precedence >= min_prec will be accepted
2772+
pub fn parse_prefix_expr(&mut self, min_prec: uint) -> P<Expr> {
27732773
let lo = self.span.lo;
27742774
let hi;
27752775

27762776
let ex;
27772777
match self.token {
27782778
token::Not => {
27792779
self.bump();
2780-
let e = self.parse_prefix_expr();
2780+
let e = self.parse_prefix_expr(prefix_prec);
27812781
hi = e.span.hi;
27822782
ex = self.mk_unary(UnNot, e);
27832783
}
27842784
token::BinOp(token::Minus) => {
27852785
self.bump();
2786-
let e = self.parse_prefix_expr();
2786+
let e = self.parse_prefix_expr(prefix_prec);
27872787
hi = e.span.hi;
27882788
ex = self.mk_unary(UnNeg, e);
27892789
}
27902790
token::BinOp(token::Star) => {
27912791
self.bump();
2792-
let e = self.parse_prefix_expr();
2792+
let e = self.parse_prefix_expr(prefix_prec);
27932793
hi = e.span.hi;
27942794
ex = self.mk_unary(UnDeref, e);
27952795
}
27962796
token::BinOp(token::And) | token::AndAnd => {
27972797
self.expect_and();
27982798
let m = self.parse_mutability();
2799-
let e = self.parse_prefix_expr();
2799+
let e = self.parse_prefix_expr(prefix_prec);
28002800
hi = e.span.hi;
28012801
ex = ExprAddrOf(m, e);
28022802
}
@@ -2810,14 +2810,14 @@ impl<'a> Parser<'a> {
28102810
_ => self.obsolete(last_span, ObsoleteSyntax::OwnedExpr)
28112811
}
28122812

2813-
let e = self.parse_prefix_expr();
2813+
let e = self.parse_prefix_expr(prefix_prec);
28142814
hi = e.span.hi;
28152815
ex = self.mk_unary(UnUniq, e);
28162816
}
2817-
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
2817+
token::DotDot if min_prec <= range_prec => {
28182818
// A range, closed above: `..expr`.
28192819
self.bump();
2820-
let e = self.parse_expr();
2820+
let e = self.parse_binops(range_prec + 1);
28212821
hi = e.span.hi;
28222822
ex = self.mk_range(None, Some(e));
28232823
}
@@ -2848,15 +2848,15 @@ impl<'a> Parser<'a> {
28482848
"perhaps you meant `box() (foo)` instead?");
28492849
self.abort_if_errors();
28502850
}
2851-
let subexpression = self.parse_prefix_expr();
2851+
let subexpression = self.parse_prefix_expr(prefix_prec);
28522852
hi = subexpression.span.hi;
28532853
ex = ExprBox(Some(place), subexpression);
28542854
return self.mk_expr(lo, hi, ex);
28552855
}
28562856
}
28572857

28582858
// Otherwise, we use the unique pointer default.
2859-
let subexpression = self.parse_prefix_expr();
2859+
let subexpression = self.parse_prefix_expr(prefix_prec);
28602860
hi = subexpression.span.hi;
28612861
// FIXME (pnkfelix): After working out kinks with box
28622862
// desugaring, should be `ExprBox(None, subexpression)`
@@ -2868,10 +2868,10 @@ impl<'a> Parser<'a> {
28682868
return self.mk_expr(lo, hi, ex);
28692869
}
28702870

2871-
/// Parse an expression of binops
2872-
pub fn parse_binops(&mut self) -> P<Expr> {
2873-
let prefix_expr = self.parse_prefix_expr();
2874-
self.parse_more_binops(prefix_expr, 0)
2871+
/// Parse an expression of binops of at least min_prec precedence
2872+
pub fn parse_binops(&mut self, min_prec: uint) -> P<Expr> {
2873+
let prefix_expr = self.parse_prefix_expr(min_prec);
2874+
self.parse_more_binops(prefix_expr, min_prec)
28752875
}
28762876

28772877
/// Parse an expression of binops of at least min_prec precedence
@@ -2894,10 +2894,9 @@ impl<'a> Parser<'a> {
28942894
self.check_no_chained_comparison(&*lhs, cur_op)
28952895
}
28962896
let cur_prec = operator_prec(cur_op);
2897-
if cur_prec > min_prec {
2897+
if cur_prec >= min_prec {
28982898
self.bump();
2899-
let expr = self.parse_prefix_expr();
2900-
let rhs = self.parse_more_binops(expr, cur_prec);
2899+
let rhs = self.parse_binops(cur_prec + 1);
29012900
let lhs_span = lhs.span;
29022901
let rhs_span = rhs.span;
29032902
let binary = self.mk_binary(cur_op, lhs, rhs);
@@ -2908,19 +2907,57 @@ impl<'a> Parser<'a> {
29082907
}
29092908
}
29102909
None => {
2911-
if as_prec > min_prec && self.eat_keyword(keywords::As) {
2910+
if as_prec >= min_prec && self.eat_keyword(keywords::As) {
29122911
let rhs = self.parse_ty();
29132912
let _as = self.mk_expr(lhs.span.lo,
29142913
rhs.span.hi,
29152914
ExprCast(lhs, rhs));
29162915
self.parse_more_binops(_as, min_prec)
2916+
} else if range_prec >= min_prec
2917+
&& match lhs.node { ExprRange(_, _) => false, _ => true }
2918+
&& self.eat(&token::DotDot) {
2919+
// '..' range notation, infix or postfix form
2920+
// Note that we intentionally reject other range expressions on the lhs.
2921+
// This makes '..1..2' invalid.
2922+
// This is necessary for consistency between the prefix and postfix forms.
2923+
let opt_rhs = if self.is_at_start_of_range_notation_rhs() {
2924+
Some(self.parse_binops(range_prec + 1))
2925+
} else {
2926+
None
2927+
};
2928+
let lo = lhs.span.lo;
2929+
let hi = self.span.hi;
2930+
let range = self.mk_range(Some(lhs), opt_rhs);
2931+
let bin = self.mk_expr(lo, hi, range);
2932+
self.parse_more_binops(bin, min_prec)
29172933
} else {
29182934
lhs
29192935
}
29202936
}
29212937
}
29222938
}
29232939

2940+
fn is_at_start_of_range_notation_rhs(&self) -> bool {
2941+
if self.token.can_begin_expr() {
2942+
// parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
2943+
if self.token == token::OpenDelim(token::Brace) {
2944+
return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
2945+
}
2946+
2947+
// `1..*i` is ambiguous between `1..(*i)` and `(1..)*(i)`.
2948+
// We pick the `1..(*i)` interpretation.
2949+
2950+
// `r==1..&&true` is ambiguous between `r==(1..(&&true))` and `(r==(1..))&&true`.
2951+
// We pick the latter interpretation.
2952+
match self.token.to_binop() {
2953+
Some(op) => operator_prec(op) > range_prec,
2954+
None => true
2955+
}
2956+
} else {
2957+
false
2958+
}
2959+
}
2960+
29242961
/// Produce an error if comparison operators are chained (RFC #558).
29252962
/// We only need to check lhs, not rhs, because all comparison ops
29262963
/// have same precedence and are left-associative
@@ -2944,7 +2981,7 @@ impl<'a> Parser<'a> {
29442981
/// actually, this seems to be the main entry point for
29452982
/// parsing an arbitrary expression.
29462983
pub fn parse_assign_expr(&mut self) -> P<Expr> {
2947-
let lhs = self.parse_binops();
2984+
let lhs = self.parse_binops(0);
29482985
self.parse_assign_expr_with(lhs)
29492986
}
29502987

@@ -2976,23 +3013,6 @@ impl<'a> Parser<'a> {
29763013
let assign_op = self.mk_assign_op(aop, lhs, rhs);
29773014
self.mk_expr(span.lo, rhs_span.hi, assign_op)
29783015
}
2979-
// A range expression, either `expr..expr` or `expr..`.
2980-
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
2981-
self.bump();
2982-
2983-
let opt_end = if self.token.can_begin_expr() {
2984-
let end = self.parse_expr_res(RESTRICTION_NO_DOTS);
2985-
Some(end)
2986-
} else {
2987-
None
2988-
};
2989-
2990-
let lo = lhs.span.lo;
2991-
let hi = self.span.hi;
2992-
let range = self.mk_range(Some(lhs), opt_end);
2993-
return self.mk_expr(lo, hi, range);
2994-
}
2995-
29963016
_ => {
29973017
lhs
29983018
}

src/test/compile-fail/range-3.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test range syntax - syntax errors.
12+
13+
pub fn main() {
14+
let r = 1..2..3;
15+
//~^ ERROR expected one of `.`, `;`, or an operator, found `..`
16+
}

src/test/run-pass/ranges-precedence.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,13 @@ fn main() {
4848
assert!(x == &a[3..]);
4949

5050
for _i in 2+4..10-3 {}
51+
52+
let i = 42;
53+
for _ in 1..i {}
54+
for _ in 1.. { break; }
55+
56+
if 1..2 == 1..2 {}
57+
if 1.. == 1.. {}
58+
if ..1 == ..1 {}
5159
}
5260

0 commit comments

Comments
 (0)