about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDaniel Grunwald <daniel@danielgrunwald.de>2015-01-18 21:43:03 +0100
committerDaniel Grunwald <daniel@danielgrunwald.de>2015-01-22 19:55:15 +0100
commitdb013f9f45a3083ccc9dd79299f110ec62e29704 (patch)
tree7a716ac5c0f4082611d34561f5597f8b7c3e92f9 /src
parentb7930d93d9b57beaeabfeb43cf78fc8161ecd46c (diff)
downloadrust-db013f9f45a3083ccc9dd79299f110ec62e29704.tar.gz
rust-db013f9f45a3083ccc9dd79299f110ec62e29704.zip
Fix some grammar inconsistencies for the '..' range notation.
Grammar changes:
* allow 'for _ in 1..i {}' (fixes #20241)
* allow 'for _ in 1.. {}' as infinite loop
* prevent use of range notation in contexts where only operators of high
  precedence are expected (fixes #20811)

Parser code cleanup:
* remove RESTRICTION_NO_DOTS
* make AS_PREC const and follow naming convention
* make min_prec inclusive
Diffstat (limited to 'src')
-rw-r--r--src/doc/reference.md7
-rw-r--r--src/libsyntax/ast_util.rs3
-rw-r--r--src/libsyntax/parse/parser.rs54
-rw-r--r--src/test/compile-fail/range-3.rs16
-rw-r--r--src/test/compile-fail/range-4.rs16
-rw-r--r--src/test/run-pass/ranges-precedence.rs7
6 files changed, 80 insertions, 23 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 9ec4708eb2f..768293cba79 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -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
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 892b3c1e7f2..cf0aac5bf4a 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -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 {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fc02cb4acb8..e59dbe52b76 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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;
@@ -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,
     }
 }
 
@@ -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();
@@ -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);
@@ -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,
@@ -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> {
@@ -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
@@ -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) {
diff --git a/src/test/compile-fail/range-3.rs b/src/test/compile-fail/range-3.rs
new file mode 100644
index 00000000000..fe79165236f
--- /dev/null
+++ b/src/test/compile-fail/range-3.rs
@@ -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 `..`
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/range-4.rs b/src/test/compile-fail/range-4.rs
new file mode 100644
index 00000000000..bbd6ae289cc
--- /dev/null
+++ b/src/test/compile-fail/range-4.rs
@@ -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 `..`
+}
\ No newline at end of file
diff --git a/src/test/run-pass/ranges-precedence.rs b/src/test/run-pass/ranges-precedence.rs
index f678eed8775..c947220f1f8 100644
--- a/src/test/run-pass/ranges-precedence.rs
+++ b/src/test/run-pass/ranges-precedence.rs
@@ -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])));
 }