diff --git a/Makefile.in b/Makefile.in index d78176e569999..a9a41a073d033 100644 --- a/Makefile.in +++ b/Makefile.in @@ -297,7 +297,7 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \ LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \ - *.rs */*.rs */*/*.rs)) + *.rs */*.rs */*/*.rs */*/*/*.rs)) DRIVER_CRATE := $(S)src/driver/driver.rs diff --git a/doc/rust.md b/doc/rust.md index 2f5c310ec8328..1075a8d28808c 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1667,6 +1667,40 @@ Supported traits for `deriving` are: each constituent field of the type must also implement `ToStr` and will have `field.to_str()` invoked to build up the result. +#### Derived comparison options + +The `deriving` instances of `Eq`, `TotalEq`, `Ord`, `TotalOrd` all +support some options that allow control of their behaviour when used +on structs. These are specified as follows: + +~~~ +#[deriving(Eq(test_order(d, c), ignore(b)), + TotalEq(test_order(c)), + Ord(reverse(a, c)), + TotalOrd(reverse(a, c)))] +struct Options { + a: float, + b: int, + c: uint, + d: uint +} +~~~ + +* `test_order` prioritizes the fields listed, testing them first, in + the order in which they are listed. That is, the `Eq` instance for + `Options` will test `d`, and then `c`, and then the remaining fields + (subject to `ignore`). All four traits support this. +* `ignore` excludes the given field from the comparison, so `Options { + .., b: 1, ..}` and `Options {.., b: 2, .. }` are equal if the rest + of the fields are equal (that is, despite `b` being different). Only + `Eq` and `Ord` support `ignore`. +* `reverse` flips the ordering used for that field, so `Options { a: + 10.0, ... } < Options { a: 0.0, .. }`. Only `Ord` and `TotalOrd` + support `reverse`. + +Using an option not listed here is an error. These options are only +supported on normal structs, not on tuple-structs or enums. + # Statements and expressions Rust is _primarily_ an expression language. This means that most forms of diff --git a/src/libstd/borrow.rs b/src/libstd/borrow.rs index 9e3a3a28fe8ce..6c3d4c5f1fbea 100644 --- a/src/libstd/borrow.rs +++ b/src/libstd/borrow.rs @@ -58,3 +58,15 @@ impl<'self, T: Ord> Ord for &'self T { *(*self) > *(*other) } } + +#[cfg(not(test))] +impl<'self, T: TotalOrd> TotalOrd for &'self T { + #[inline] + fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl<'self, T: TotalEq> TotalEq for &'self T { + #[inline] + fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) } +} diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 43a632562b2b7..b66f89e83415e 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -153,7 +153,6 @@ pub fn cmp2( Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the lexical ordering on a type `(int, int)`. */ -// used in deriving code in libsyntax #[inline] pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { match o1 { diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index bd4dc69537cb1..57230b2fd247d 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -12,7 +12,7 @@ use ptr::to_unsafe_ptr; -#[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::*; pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; @@ -71,6 +71,29 @@ impl Ord for @mut T { fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) } } +#[cfg(not(test))] +impl TotalOrd for @T { + #[inline] + fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalOrd for @mut T { + #[inline] + fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @T { + #[inline] + fn equals(&self, other: &@T) -> bool { (**self).equals(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @mut T { + #[inline] + fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) } +} #[test] fn test() { let x = @3; diff --git a/src/libstd/owned.rs b/src/libstd/owned.rs index e7a6e38fdb088..424c4fd6b2f44 100644 --- a/src/libstd/owned.rs +++ b/src/libstd/owned.rs @@ -10,7 +10,7 @@ //! Operations on unique pointer types -#[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::*; #[cfg(not(test))] impl Eq for ~T { @@ -31,3 +31,15 @@ impl Ord for ~T { #[inline] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } + +#[cfg(not(test))] +impl TotalOrd for ~T { + #[inline] + fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for ~T { + #[inline] + fn equals(&self, other: &~T) -> bool { (**self).equals(*other) } +} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1dda2493da20a..a0a5cf4fe8e51 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -282,6 +282,10 @@ impl ExtCtxt { self.print_backtrace(); self.parse_sess.span_diagnostic.span_warn(sp, msg); } + pub fn span_note(&self, sp: span, msg: &str) { + self.print_backtrace(); + self.parse_sess.span_diagnostic.span_note(sp, msg); + } pub fn span_unimpl(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_unimpl(sp, msg); diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 02dcb2cdbc9eb..d4b5e80760b72 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -13,12 +13,16 @@ use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; +use ext::deriving::DerivingOptions; pub fn expand_deriving_clone(cx: @ExtCtxt, span: span, + options: DerivingOptions, mitem: @MetaItem, in_items: ~[@item]) -> ~[@item] { + options.unused_options_maybe_error(cx, span, "Clone"); + let trait_def = TraitDef { path: Path::new(~["std", "clone", "Clone"]), additional_bounds: ~[], @@ -41,9 +45,12 @@ pub fn expand_deriving_clone(cx: @ExtCtxt, pub fn expand_deriving_deep_clone(cx: @ExtCtxt, span: span, + options: DerivingOptions, mitem: @MetaItem, in_items: ~[@item]) -> ~[@item] { + options.unused_options_maybe_error(cx, span, "DeepClone"); + let trait_def = TraitDef { path: Path::new(~["std", "clone", "DeepClone"]), additional_bounds: ~[], diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index a7d9db59130f3..621ee1ce4fc6d 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -13,16 +13,24 @@ use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; +use ext::deriving::DerivingOptions; +use ext::deriving::cmp::CmpOptions; pub fn expand_deriving_eq(cx: @ExtCtxt, span: span, + options: DerivingOptions, mitem: @MetaItem, in_items: ~[@item]) -> ~[@item] { + let mut options = match CmpOptions::parse(cx, span, "Eq", options, true, false) { + Some(o) => o, + None => return in_items + }; + // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { cs_and(|cx, span, _, _| cx.expr_bool(span, false), - cx, span, substr) + cx, span, substr) } fn cs_ne(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { cs_or(|cx, span, _, _| cx.expr_bool(span, true), @@ -30,7 +38,7 @@ pub fn expand_deriving_eq(cx: @ExtCtxt, } macro_rules! md ( - ($name:expr, $f:ident) => { + ($name:expr, $f:ident) => {{ MethodDef { name: $name, generics: LifetimeBounds::empty(), @@ -38,9 +46,11 @@ pub fn expand_deriving_eq(cx: @ExtCtxt, args: ~[borrowed_self()], ret_ty: Literal(Path::new(~["bool"])), const_nonmatching: true, - combine_substructure: $f - }, - } + combine_substructure: |cx, span, substr| { + options.call_substructure(cx, span, substr, $f) + } + } + }} ); let trait_def = TraitDef { diff --git a/src/libsyntax/ext/deriving/cmp/mod.rs b/src/libsyntax/ext/deriving/cmp/mod.rs new file mode 100644 index 0000000000000..3b905ef649964 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/mod.rs @@ -0,0 +1,381 @@ +// Copyright 2013 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. + +use ast::{ident, expr}; +use codemap::span; +use ast; +use ext::base::ExtCtxt; +use ext::deriving::generic::*; +use ext::deriving::{DerivingOptions, NoOptions, Lit, List}; + +use std::vec; + +pub mod eq; +pub mod totaleq; +pub mod ord; +pub mod totalord; + +pub struct CmpOptions_ { + /// Ensure that we don't show errors several times. + shown_errors: bool, + test_order: ~[(ident, span)], + ignore: ~[(ident, span)], + reverse: ~[(ident, span)] +} +pub struct CmpOptions(Option); + +impl CmpOptions { + pub fn parse(cx: @ExtCtxt, _span: span, trait_name: &str, + options: DerivingOptions, + allow_ignore: bool, allow_reverse: bool) -> Option { + // Trait(