From e15f04324828924c21b715887a685154f2d6289b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Jan 2015 17:21:09 +1300 Subject: [PATCH 1/3] Show, String, Eq impls for Ranges --- src/libcore/ops.rs | 88 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 4debab91739..8d86252e051 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -65,6 +65,7 @@ use clone::Clone; use iter::{Step, Iterator,DoubleEndedIterator,ExactSizeIterator}; use marker::Sized; use option::Option::{self, Some, None}; +use fmt; /// The `Drop` trait is used to run some code when a value goes out of scope. This /// is sometimes called a 'destructor'. @@ -847,13 +848,27 @@ pub trait IndexMut { } /// An unbounded range. -#[derive(Copy)] +#[derive(Copy, PartialEq, Eq)] #[lang="full_range"] #[unstable = "API still in development"] pub struct FullRange; +#[unstable = "API still in development"] +impl fmt::Show for FullRange { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Show::fmt("..", fmt) + } +} + +#[unstable = "API still in development"] +impl fmt::String for FullRange { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::String::fmt("..", fmt) + } +} + /// A (half-open) range which is bounded at both ends. -#[derive(Copy)] +#[derive(Copy, PartialEq, Eq)] #[lang="range"] #[unstable = "API still in development"] pub struct Range { @@ -904,8 +919,29 @@ impl DoubleEndedIterator for Range { #[unstable = "API still in development"] impl ExactSizeIterator for Range {} +#[unstable = "API still in development"] +impl fmt::Show for Range { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}..{:?}", self.start, self.end) + } +} +#[cfg(stage0)] +#[unstable = "API still in development"] +impl fmt::String for Range { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}..{}", self.start, self.end) + } +} +#[cfg(not(stage0))] +#[unstable = "API still in development"] +impl fmt::String for Range { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}..{}", self.start, self.end) + } +} + /// A range which is only bounded below. -#[derive(Copy)] +#[derive(Copy, PartialEq, Eq)] #[lang="range_from"] #[unstable = "API still in development"] pub struct RangeFrom { @@ -926,8 +962,30 @@ impl Iterator for RangeFrom { } } +#[unstable = "API still in development"] +impl fmt::Show for RangeFrom { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}..", self.start) + } +} + +#[cfg(stage0)] +#[unstable = "API still in development"] +impl fmt::String for RangeFrom { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}..", self.start) + } +} +#[cfg(not(stage0))] +#[unstable = "API still in development"] +impl fmt::String for RangeFrom { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}..", self.start) + } +} + /// A range which is only bounded above. -#[derive(Copy)] +#[derive(Copy, PartialEq, Eq)] #[lang="range_to"] #[unstable = "API still in development"] pub struct RangeTo { @@ -935,6 +993,28 @@ pub struct RangeTo { pub end: Idx, } +#[unstable = "API still in development"] +impl fmt::Show for RangeTo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "..{:?}", self.end) + } +} + +#[cfg(stage0)] +#[unstable = "API still in development"] +impl fmt::String for RangeTo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "..{}", self.end) + } +} +#[cfg(not(stage0))] +#[unstable = "API still in development"] +impl fmt::String for RangeTo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "..{}", self.end) + } +} + /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. From 63a9bd5e0adc03652e10506055564077aa00eeaa Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 8 Jan 2015 08:30:33 +1300 Subject: [PATCH 2/3] Fix precedence for ranges. Technically this is a [breaking-change] but it probably shouldn't affect your code. Closes #20256 --- src/libsyntax/parse/parser.rs | 41 +++++++++++--------- src/test/run-pass/ranges-precedence.rs | 52 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 src/test/run-pass/ranges-precedence.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9c16dbb2c5c..d70f4e74b5f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2536,7 +2536,7 @@ impl<'a> Parser<'a> { } // expr[...] - // An index expression. + // Could be either an index expression or a slicing expression. token::OpenDelim(token::Bracket) => { let bracket_pos = self.span.lo; self.bump(); @@ -2576,22 +2576,6 @@ impl<'a> Parser<'a> { "use `&expr[]` to construct a slice of the whole of expr"); } } - - // A range expression, either `expr..expr` or `expr..`. - token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => { - self.bump(); - - let opt_end = if self.token.can_begin_expr() { - let end = self.parse_expr_res(RESTRICTION_NO_DOTS); - Some(end) - } else { - None - }; - - let hi = self.span.hi; - let range = self.mk_range(Some(e), opt_end); - return self.mk_expr(lo, hi, range); - } _ => return e } } @@ -2834,7 +2818,7 @@ impl<'a> Parser<'a> { token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => { // A range, closed above: `..expr`. self.bump(); - let e = self.parse_prefix_expr(); + let e = self.parse_expr(); hi = e.span.hi; ex = self.mk_range(None, Some(e)); } @@ -2901,6 +2885,7 @@ impl<'a> Parser<'a> { self.restrictions.contains(RESTRICTION_NO_BAR_OP) { return lhs; } + self.expected_tokens.push(TokenType::Operator); let cur_opt = self.token.to_binop(); @@ -2909,6 +2894,7 @@ impl<'a> Parser<'a> { let cur_prec = operator_prec(cur_op); if cur_prec > min_prec { self.bump(); + // TODO let expr = self.parse_prefix_expr(); let rhs = self.parse_more_binops(expr, cur_prec); let lhs_span = lhs.span; @@ -2970,6 +2956,25 @@ impl<'a> Parser<'a> { let assign_op = self.mk_assign_op(aop, lhs, rhs); self.mk_expr(span.lo, rhs_span.hi, assign_op) } + // TODO + // A range expression, either `expr..expr` or `expr..`. + token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => { + self.bump(); + + let opt_end = if self.token.can_begin_expr() { + // TODO only use of RES...DOT + let end = self.parse_expr_res(RESTRICTION_NO_DOTS); + Some(end) + } else { + None + }; + + let lo = lhs.span.lo; + let hi = self.span.hi; + let range = self.mk_range(Some(lhs), opt_end); + return self.mk_expr(lo, hi, range); + } + _ => { lhs } diff --git a/src/test/run-pass/ranges-precedence.rs b/src/test/run-pass/ranges-precedence.rs new file mode 100644 index 00000000000..ea72eb38865 --- /dev/null +++ b/src/test/run-pass/ranges-precedence.rs @@ -0,0 +1,52 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the precedence of ranges is correct + +#![feature(slicing_syntax)] + +struct Foo { + foo: uint, +} + +impl Foo { + fn bar(&self) -> uint { 5 } +} + +fn main() { + let x = 1+3..4+5; + assert!(x == (4..9)); + + let x = 1..4+5; + assert!(x == (1..9)); + + let x = 1+3..4; + assert!(x == (4..4)); + + let a = Foo { foo: 3 }; + let x = a.foo..a.bar(); + assert!(x == (3..5)); + + let x = 1+3..; + assert!(x == (4..)); + let x = ..1+3; + assert!(x == (..4)); + + let a = &[0i32, 1, 2, 3, 4, 5, 6]; + let x = &a[1+1..2+2]; + assert!(x == &a[2..4]); + let x = &a[..1+2]; + assert!(x == &a[..3]); + let x = &a[1+2..]; + assert!(x == &a[3..]); + + for _i in 2+4..10-3 {} +} + From 68a783a89f4c7e74d4c7e09bfac67283e054d4fc Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 8 Jan 2015 14:33:57 +1300 Subject: [PATCH 3/3] Remove String impls and fix for make tidy --- src/libcore/ops.rs | 51 -------------------------- src/libsyntax/parse/parser.rs | 3 -- src/test/run-pass/ranges-precedence.rs | 2 +- 3 files changed, 1 insertion(+), 55 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 8d86252e051..ab956587d82 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -860,13 +860,6 @@ impl fmt::Show for FullRange { } } -#[unstable = "API still in development"] -impl fmt::String for FullRange { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::String::fmt("..", fmt) - } -} - /// A (half-open) range which is bounded at both ends. #[derive(Copy, PartialEq, Eq)] #[lang="range"] @@ -925,20 +918,6 @@ impl fmt::Show for Range { write!(fmt, "{:?}..{:?}", self.start, self.end) } } -#[cfg(stage0)] -#[unstable = "API still in development"] -impl fmt::String for Range { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}..{}", self.start, self.end) - } -} -#[cfg(not(stage0))] -#[unstable = "API still in development"] -impl fmt::String for Range { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}..{}", self.start, self.end) - } -} /// A range which is only bounded below. #[derive(Copy, PartialEq, Eq)] @@ -969,21 +948,6 @@ impl fmt::Show for RangeFrom { } } -#[cfg(stage0)] -#[unstable = "API still in development"] -impl fmt::String for RangeFrom { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}..", self.start) - } -} -#[cfg(not(stage0))] -#[unstable = "API still in development"] -impl fmt::String for RangeFrom { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}..", self.start) - } -} - /// A range which is only bounded above. #[derive(Copy, PartialEq, Eq)] #[lang="range_to"] @@ -1000,21 +964,6 @@ impl fmt::Show for RangeTo { } } -#[cfg(stage0)] -#[unstable = "API still in development"] -impl fmt::String for RangeTo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..{}", self.end) - } -} -#[cfg(not(stage0))] -#[unstable = "API still in development"] -impl fmt::String for RangeTo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..{}", self.end) - } -} - /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d70f4e74b5f..ab4e39bd767 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2894,7 +2894,6 @@ impl<'a> Parser<'a> { let cur_prec = operator_prec(cur_op); if cur_prec > min_prec { self.bump(); - // TODO let expr = self.parse_prefix_expr(); let rhs = self.parse_more_binops(expr, cur_prec); let lhs_span = lhs.span; @@ -2956,13 +2955,11 @@ impl<'a> Parser<'a> { let assign_op = self.mk_assign_op(aop, lhs, rhs); self.mk_expr(span.lo, rhs_span.hi, assign_op) } - // TODO // A range expression, either `expr..expr` or `expr..`. token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => { self.bump(); let opt_end = if self.token.can_begin_expr() { - // TODO only use of RES...DOT let end = self.parse_expr_res(RESTRICTION_NO_DOTS); Some(end) } else { diff --git a/src/test/run-pass/ranges-precedence.rs b/src/test/run-pass/ranges-precedence.rs index ea72eb38865..f678eed8775 100644 --- a/src/test/run-pass/ranges-precedence.rs +++ b/src/test/run-pass/ranges-precedence.rs @@ -29,7 +29,7 @@ fn main() { let x = 1+3..4; assert!(x == (4..4)); - + let a = Foo { foo: 3 }; let x = a.foo..a.bar(); assert!(x == (3..5));