1 // Copyright 2013 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.
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.
11 pub use self::OrderingOp
::*;
13 use deriving
::generic
::*;
14 use deriving
::generic
::ty
::*;
16 use syntax
::ast
::{self, BinOpKind, Expr, MetaItem}
;
17 use syntax
::ext
::base
::{Annotatable, ExtCtxt}
;
18 use syntax
::ext
::build
::AstBuilder
;
19 use syntax
::parse
::token
::InternedString
;
23 pub fn expand_deriving_partial_ord(cx
: &mut ExtCtxt
,
27 push
: &mut FnMut(Annotatable
)) {
29 ($name
:expr
, $op
:expr
, $equal
:expr
) => { {
30 let inline
= cx
.meta_word(span
, InternedString
::new("inline"));
31 let attrs
= vec
![cx
.attribute(span
, inline
)];
34 generics
: LifetimeBounds
::empty(),
35 explicit_self
: borrowed_explicit_self(),
36 args
: vec
![borrowed_self()],
37 ret_ty
: Literal(path_local
!(bool
)),
40 unify_fieldless_variants
: true,
41 combine_substructure
: combine_substructure(Box
::new(|cx
, span
, substr
| {
42 cs_op($op
, $equal
, cx
, span
, substr
)
48 let ordering_ty
= Literal(path_std
!(cx
, core
::cmp
::Ordering
));
49 let ret_ty
= Literal(Path
::new_(pathvec_std
!(cx
, core
::option
::Option
),
51 vec
![Box
::new(ordering_ty
)],
54 let inline
= cx
.meta_word(span
, InternedString
::new("inline"));
55 let attrs
= vec
![cx
.attribute(span
, inline
)];
57 let partial_cmp_def
= MethodDef
{
59 generics
: LifetimeBounds
::empty(),
60 explicit_self
: borrowed_explicit_self(),
61 args
: vec
![borrowed_self()],
65 unify_fieldless_variants
: true,
66 combine_substructure
: combine_substructure(Box
::new(|cx
, span
, substr
| {
67 cs_partial_cmp(cx
, span
, substr
)
71 // avoid defining extra methods if we can
72 // c-like enums, enums without any fields and structs without fields
73 // can safely define only `partial_cmp`.
74 let methods
= if is_type_without_fields(item
) {
78 md
!("lt", true, false),
79 md
!("le", true, true),
80 md
!("gt", false, false),
81 md
!("ge", false, true)]
84 let trait_def
= TraitDef
{
87 path
: path_std
!(cx
, core
::cmp
::PartialOrd
),
88 additional_bounds
: vec
![],
89 generics
: LifetimeBounds
::empty(),
91 supports_unions
: false,
93 associated_types
: Vec
::new(),
95 trait_def
.expand(cx
, mitem
, item
, push
)
98 #[derive(Copy, Clone)]
107 pub fn some_ordering_collapsed(cx
: &mut ExtCtxt
,
110 self_arg_tags
: &[ast
::Ident
])
112 let lft
= cx
.expr_ident(span
, self_arg_tags
[0]);
113 let rgt
= cx
.expr_addr_of(span
, cx
.expr_ident(span
, self_arg_tags
[1]));
114 let op_str
= match op
{
115 PartialCmpOp
=> "partial_cmp",
121 cx
.expr_method_call(span
, lft
, cx
.ident_of(op_str
), vec
![rgt
])
124 pub fn cs_partial_cmp(cx
: &mut ExtCtxt
, span
: Span
, substr
: &Substructure
) -> P
<Expr
> {
125 let test_id
= cx
.ident_of("__cmp");
126 let ordering
= cx
.path_global(span
, cx
.std_path(&["cmp", "Ordering", "Equal"]));
127 let ordering_expr
= cx
.expr_path(ordering
.clone());
128 let equals_expr
= cx
.expr_some(span
, ordering_expr
);
130 let partial_cmp_path
= cx
.std_path(&["cmp", "PartialOrd", "partial_cmp"]);
134 // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) {
135 // ::std::option::Option::Some(::std::cmp::Ordering::Equal) =>
136 // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) {
137 // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => {
145 cs_fold(// foldr nests the if-elses correctly, leaving the first field
146 // as the outermost one, and the last as the innermost.
148 |cx
, span
, old
, self_f
, other_fs
| {
150 // Some(::std::cmp::Ordering::Equal) => old,
155 let other_f
= match (other_fs
.len(), other_fs
.get(0)) {
156 (1, Some(o_f
)) => o_f
,
157 _
=> cx
.span_bug(span
, "not exactly 2 arguments in `derive(PartialOrd)`"),
161 cx
.expr_addr_of(span
, self_f
),
162 cx
.expr_addr_of(span
, other_f
.clone()),
165 cx
.expr_call_global(span
, partial_cmp_path
.clone(), args
)
168 let eq_arm
= cx
.arm(span
,
169 vec
![cx
.pat_some(span
, cx
.pat_path(span
, ordering
.clone()))],
171 let neq_arm
= cx
.arm(span
,
172 vec
![cx
.pat_ident(span
, test_id
)],
173 cx
.expr_ident(span
, test_id
));
175 cx
.expr_match(span
, new
, vec
![eq_arm
, neq_arm
])
178 Box
::new(|cx
, span
, (self_args
, tag_tuple
), _non_self_args
| {
179 if self_args
.len() != 2 {
180 cx
.span_bug(span
, "not exactly 2 arguments in `derive(PartialOrd)`")
182 some_ordering_collapsed(cx
, span
, PartialCmpOp
, tag_tuple
)
190 /// Strict inequality.
191 fn cs_op(less
: bool
, equal
: bool
, cx
: &mut ExtCtxt
, span
: Span
, substr
: &Substructure
) -> P
<Expr
> {
192 let op
= if less { BinOpKind::Lt }
else { BinOpKind::Gt }
;
193 cs_fold(false, // need foldr,
194 |cx
, span
, subexpr
, self_f
, other_fs
| {
195 // build up a series of chain ||'s and &&'s from the inside
196 // out (hence foldr) to get lexical ordering, i.e. for op ==
200 // self.f1 < other.f1 || (!(other.f1 < self.f1) &&
201 // (self.f2 < other.f2 || (!(other.f2 < self.f2) &&
207 // The optimiser should remove the redundancy. We explicitly
208 // get use the binops to avoid auto-deref dereferencing too many
209 // layers of pointers, if the type includes pointers.
211 let other_f
= match (other_fs
.len(), other_fs
.get(0)) {
212 (1, Some(o_f
)) => o_f
,
213 _
=> cx
.span_bug(span
, "not exactly 2 arguments in `derive(PartialOrd)`"),
216 let cmp
= cx
.expr_binary(span
, op
, self_f
.clone(), other_f
.clone());
218 let not_cmp
= cx
.expr_unary(span
,
220 cx
.expr_binary(span
, op
, other_f
.clone(), self_f
));
222 let and
= cx
.expr_binary(span
, BinOpKind
::And
, not_cmp
, subexpr
);
223 cx
.expr_binary(span
, BinOpKind
::Or
, cmp
, and
)
225 cx
.expr_bool(span
, equal
),
226 Box
::new(|cx
, span
, (self_args
, tag_tuple
), _non_self_args
| {
227 if self_args
.len() != 2 {
228 cx
.span_bug(span
, "not exactly 2 arguments in `derive(PartialOrd)`")
230 let op
= match (less
, equal
) {
231 (true, true) => LeOp
,
232 (true, false) => LtOp
,
233 (false, true) => GeOp
,
234 (false, false) => GtOp
,
236 some_ordering_collapsed(cx
, span
, op
, tag_tuple
)