10
10
11
11
use core:: prelude:: * ;
12
12
13
+ use ast;
13
14
use ast:: { meta_item, item, expr} ;
14
15
use codemap:: span;
15
16
use ext:: base:: ExtCtxt ;
@@ -21,104 +22,105 @@ pub fn expand_deriving_ord(cx: @ExtCtxt,
21
22
mitem : @meta_item ,
22
23
in_items: ~[ @item] ) -> ~[ @item] {
23
24
macro_rules! md (
24
- ( $name: expr, $less : expr, $equal : expr) => {
25
+ ( $name: expr, $func : expr, $op : expr) => {
25
26
MethodDef {
26
27
name : $name,
27
28
generics : LifetimeBounds :: empty( ) ,
28
29
explicit_self : borrowed_explicit_self( ) ,
29
30
args : ~[ borrowed_self( ) ] ,
30
31
ret_ty : Literal ( Path :: new( ~[ "bool" ] ) ) ,
31
32
const_nonmatching : false ,
32
- combine_substructure : |cx, span, substr |
33
- cs_ord( $less, $equal, cx, span, substr)
33
+ combine_substructure : |cx, span, substr | $func( $op, cx, span, substr)
34
34
}
35
35
}
36
36
) ;
37
37
38
-
39
-
40
38
let trait_def = TraitDef {
41
39
path : Path :: new ( ~[ "std" , "cmp" , "Ord" ] ) ,
42
- // XXX: Ord doesn't imply Eq yet
43
- additional_bounds : ~[ Literal ( Path :: new ( ~[ "std" , "cmp" , "Eq" ] ) ) ] ,
40
+ additional_bounds : ~[ ] ,
44
41
generics : LifetimeBounds :: empty ( ) ,
45
42
methods : ~[
46
- md ! ( "lt" , true , false ) ,
47
- md ! ( "le" , true , true ) ,
48
- md ! ( "gt" , false , false ) ,
49
- md ! ( "ge" , false , true )
43
+ md ! ( "lt" , cs_strict , true ) ,
44
+ md ! ( "le" , cs_nonstrict , true ) , // inverse operation
45
+ md ! ( "gt" , cs_strict , false ) ,
46
+ md ! ( "ge" , cs_nonstrict , false )
50
47
]
51
48
} ;
52
49
trait_def. expand ( cx, span, mitem, in_items)
53
50
}
54
51
55
- /// `less`: is this `lt` or `le`? `equal`: is this `le` or `ge`?
56
- fn cs_ord ( less: bool, equal: bool ,
57
- cx: @ExtCtxt , span: span,
58
- substr: & Substructure ) -> @expr {
59
- let binop = if less {
60
- cx. ident_of ( "lt" )
61
- } else {
62
- cx. ident_of ( "gt" )
63
- } ;
64
- let base = cx. expr_bool ( span, equal) ;
65
-
52
+ /// Strict inequality.
53
+ fn cs_strict ( less: bool, cx: @ExtCtxt , span: span, substr: & Substructure ) -> @expr {
54
+ let op = if less { ast:: lt} else { ast:: gt} ;
66
55
cs_fold (
67
56
false , // need foldr,
68
57
|cx, span, subexpr, self_f, other_fs| {
69
58
/*
70
-
71
- build up a series of nested ifs from the inside out to get
72
- lexical ordering (hence foldr), i.e.
59
+ build up a series of chain ||'s and &&'s from the inside
60
+ out (hence foldr) to get lexical ordering, i.e. for op ==
61
+ `ast::lt`
73
62
74
63
```
75
- if self.f1 `binop` other.f1 {
76
- true
77
- } else if self.f1 == other.f1 {
78
- if self.f2 `binop` other.f2 {
79
- true
80
- } else if self.f2 == other.f2 {
81
- `equal`
82
- } else {
83
- false
84
- }
85
- } else {
86
- false
87
- }
64
+ self.f1 < other.f1 || (!(other.f1 < self.f1) &&
65
+ (self.f2 < other.f2 || (!(other.f2 < self.f2) &&
66
+ (false)
67
+ ))
68
+ )
88
69
```
89
70
90
- The inner "`equal`" case is only reached if the two
91
- items have all fields equal.
71
+ The optimiser should remove the redundancy. We explicitly
72
+ get use the binops to avoid auto-deref derefencing too many
73
+ layers of pointers, if the type includes pointers.
92
74
*/
93
- if other_fs. len ( ) != 1 {
94
- cx. span_bug ( span, "Not exactly 2 arguments in `deriving(Ord)`" ) ;
95
- }
75
+ let other_f = match other_fs {
76
+ [ o_f] => o_f,
77
+ _ => cx. span_bug ( span, "Not exactly 2 arguments in `deriving(Ord)`" )
78
+ } ;
79
+
80
+ let cmp = cx. expr_binary ( span, op,
81
+ cx. expr_deref ( span, self_f) ,
82
+ cx. expr_deref ( span, other_f) ) ;
96
83
97
- let cmp = cx. expr_method_call ( span,
98
- self_f , cx. ident_of ( "eq" ) , other_fs . to_owned ( ) ) ;
99
- let elseif = cx. expr_if ( span, cmp ,
100
- subexpr , Some ( cx. expr_bool ( span, false ) ) ) ;
84
+ let not_cmp = cx. expr_binary ( span, op ,
85
+ cx. expr_deref ( span , other_f ) ,
86
+ cx. expr_deref ( span, self_f ) ) ;
87
+ let not_cmp = cx. expr_unary ( span, ast :: not , not_cmp ) ;
101
88
102
- let cmp = cx. expr_method_call ( span,
103
- self_f, binop, other_fs. to_owned ( ) ) ;
104
- cx. expr_if ( span, cmp,
105
- cx. expr_bool ( span, true ) , Some ( elseif) )
89
+ let and = cx. expr_binary ( span, ast:: and,
90
+ not_cmp, subexpr) ;
91
+ cx. expr_binary ( span, ast:: or, cmp, and)
106
92
} ,
107
- base ,
93
+ cx . expr_bool ( span , false ) ,
108
94
|cx, span, args, _| {
109
95
// nonmatching enums, order by the order the variants are
110
96
// written
111
97
match args {
112
98
[ ( self_var, _, _) ,
113
99
( other_var, _, _) ] =>
114
100
cx. expr_bool ( span,
115
- if less {
116
- self_var < other_var
117
- } else {
118
- self_var > other_var
119
- } ) ,
101
+ if less {
102
+ self_var < other_var
103
+ } else {
104
+ self_var > other_var
105
+ } ) ,
120
106
_ => cx. span_bug ( span, "Not exactly 2 arguments in `deriving(Ord)`" )
121
107
}
122
108
} ,
123
109
cx, span, substr)
124
110
}
111
+
112
+ fn cs_nonstrict( less: bool, cx: @ExtCtxt , span: span, substr: & Substructure ) -> @expr {
113
+ // Example: ge becomes !(*self < *other), le becomes !(*self > *other)
114
+
115
+ let inverse_op = if less { ast:: gt} else { ast:: lt} ;
116
+ match substr. self_args {
117
+ [ self_, other] => {
118
+ let inverse_cmp = cx. expr_binary ( span, inverse_op,
119
+ cx. expr_deref ( span, self_) ,
120
+ cx. expr_deref ( span, other) ) ;
121
+
122
+ cx. expr_unary ( span, ast:: not, inverse_cmp)
123
+ }
124
+ _ => cx. span_bug ( span, "Not exactly 2 arguments in `deriving(Ord)`" )
125
+ }
126
+ }
0 commit comments