Skip to content

Commit 4ac8cef

Browse files
committed
---
yaml --- r: 33790 b: refs/heads/snap-stage3 c: e0876fd h: refs/heads/master v: v3
1 parent 40291dd commit 4ac8cef

File tree

4 files changed

+169
-41
lines changed

4 files changed

+169
-41
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 809bd3e5efa00a7a3f924bc3999568d67574e4e7
4+
refs/heads/snap-stage3: e0876fdfc1976f74526c486deb77523edbc216aa
55
refs/heads/try: d324a424d8f84b1eb049b12cf34182bda91b0024
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/libsyntax/ext/build.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,21 @@ fn mk_copy(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
157157
fn mk_managed(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
158158
mk_expr(cx, sp, ast::expr_unary(ast::box(ast::m_imm), e))
159159
}
160+
fn mk_pat(cx: ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat {
161+
@{ id: cx.next_id(), node: move pat, span: span }
162+
}
160163
fn mk_pat_ident(cx: ext_ctxt, span: span, ident: ast::ident) -> @ast::pat {
161-
let path = build::mk_raw_path(span, ~[ ident ]);
164+
let path = mk_raw_path(span, ~[ ident ]);
162165
let pat = ast::pat_ident(ast::bind_by_value, path, None);
163-
@{ id: cx.next_id(), node: move pat, span: span }
166+
mk_pat(cx, span, move pat)
167+
}
168+
fn mk_pat_enum(cx: ext_ctxt,
169+
span: span,
170+
path: @ast::path,
171+
+subpats: ~[@ast::pat])
172+
-> @ast::pat {
173+
let pat = ast::pat_enum(path, Some(move subpats));
174+
mk_pat(cx, span, move pat)
164175
}
165176
fn mk_bool(cx: ext_ctxt, span: span, value: bool) -> @ast::expr {
166177
let lit_expr = ast::expr_lit(@{ node: ast::lit_bool(value), span: span });

branches/snap-stage3/src/libsyntax/ext/deriving.rs

Lines changed: 140 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
/// The compiler code necessary to implement the #[deriving_eq] and
22
/// #[deriving_ord] extensions.
33
4-
use ast::{and, bind_by_value, binop, blk, default_blk, deref, enum_def, expr};
4+
use ast::{and, bind_by_ref, binop, blk, default_blk, deref, enum_def};
5+
use ast::{enum_variant_kind, expr};
56
use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit};
67
use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_};
78
use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item};
89
use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public};
9-
use ast::{pure_fn, re_anon, return_val, struct_def, sty_region, ty_path};
10-
use ast::{ty_rptr, unnamed_field};
10+
use ast::{pure_fn, re_anon, return_val, struct_def, struct_variant_kind};
11+
use ast::{sty_region, tuple_variant_kind, ty_path};
12+
use ast::{ty_rptr, unnamed_field, variant};
1113
use base::ext_ctxt;
1214
use codemap::span;
1315
use parse::token::special_idents::clownshoes_extensions;
@@ -174,6 +176,99 @@ fn create_derived_impl(cx: ext_ctxt,
174176
return create_impl_item(cx, span, move impl_item);
175177
}
176178

179+
fn create_enum_variant_pattern(cx: ext_ctxt,
180+
span: span,
181+
variant: &ast::variant,
182+
prefix: ~str)
183+
-> @ast::pat {
184+
let variant_ident = variant.node.name;
185+
match variant.node.kind {
186+
tuple_variant_kind(ref variant_args) => {
187+
if variant_args.len() == 0 {
188+
return build::mk_pat_ident(cx, span, variant_ident);
189+
}
190+
191+
let subpats = dvec::DVec();
192+
for variant_args.each |_variant_arg| {
193+
// Create the subidentifier.
194+
let index = subpats.len().to_str();
195+
let ident = cx.ident_of(prefix + index);
196+
197+
// Create the subpattern.
198+
let subpath = build::mk_raw_path(span, ~[ ident ]);
199+
let subpat = pat_ident(bind_by_ref(m_imm), subpath, None);
200+
let subpat = build::mk_pat(cx, span, move subpat);
201+
subpats.push(subpat);
202+
}
203+
204+
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
205+
let subpats = dvec::unwrap(move subpats);
206+
return build::mk_pat_enum(cx, span, matching_path, move subpats);
207+
}
208+
struct_variant_kind(*) => {
209+
cx.span_unimpl(span, ~"struct variants for `deriving`");
210+
}
211+
enum_variant_kind(*) => {
212+
cx.span_unimpl(span, ~"enum variants for `deriving`");
213+
}
214+
}
215+
}
216+
217+
fn call_substructure_method(cx: ext_ctxt,
218+
span: span,
219+
self_field: @expr,
220+
other_field_ref: @expr,
221+
method_ident: ident,
222+
junction: Junction,
223+
chain_expr: &mut Option<@expr>) {
224+
// Call the substructure method.
225+
let self_method = build::mk_access_(cx, span, self_field, method_ident);
226+
let self_call = build::mk_call_(cx,
227+
span,
228+
self_method,
229+
~[ other_field_ref ]);
230+
231+
// Connect to the outer expression if necessary.
232+
*chain_expr = match *chain_expr {
233+
None => Some(self_call),
234+
Some(copy old_outer_expr) => {
235+
let binop = junction.to_binop();
236+
let chain_expr = build::mk_binary(cx,
237+
span,
238+
binop,
239+
old_outer_expr,
240+
self_call);
241+
Some(chain_expr)
242+
}
243+
};
244+
}
245+
246+
fn finish_chain_expr(cx: ext_ctxt,
247+
span: span,
248+
chain_expr: Option<@expr>,
249+
junction: Junction)
250+
-> @expr {
251+
match chain_expr {
252+
None => {
253+
match junction {
254+
Conjunction => build::mk_bool(cx, span, true),
255+
Disjunction => build::mk_bool(cx, span, false),
256+
}
257+
}
258+
Some(ref outer_expr) => *outer_expr,
259+
}
260+
}
261+
262+
fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint {
263+
match variant.node.kind {
264+
tuple_variant_kind(args) => args.len(),
265+
struct_variant_kind(struct_def) => struct_def.fields.len(),
266+
enum_variant_kind(*) => {
267+
cx.span_bug(span, ~"variant_arg_count: enum variants deprecated")
268+
}
269+
}
270+
}
271+
177272
fn expand_deriving_struct_def(cx: ext_ctxt,
178273
span: span,
179274
struct_def: &struct_def,
@@ -209,8 +304,6 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
209304
let self_ident = cx.ident_of(~"self");
210305
let other_ident = cx.ident_of(~"__other");
211306

212-
let binop = junction.to_binop();
213-
214307
// Create the body of the method.
215308
let mut outer_expr = None;
216309
for struct_def.fields.each |struct_field| {
@@ -232,27 +325,13 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
232325
ident);
233326

234327
// Call the substructure method.
235-
let self_method = build::mk_access_(cx,
236-
span,
237-
self_field,
238-
method_ident);
239-
let self_call = build::mk_call_(cx,
240-
span,
241-
self_method,
242-
~[ other_field_ref ]);
243-
244-
// Connect to the outer expression if necessary.
245-
outer_expr = match outer_expr {
246-
None => Some(self_call),
247-
Some(old_outer_expr) => {
248-
let chain_expr = build::mk_binary(cx,
249-
span,
250-
binop,
251-
old_outer_expr,
252-
self_call);
253-
Some(chain_expr)
254-
}
255-
};
328+
call_substructure_method(cx,
329+
span,
330+
self_field,
331+
other_field_ref,
332+
method_ident,
333+
junction,
334+
&mut outer_expr);
256335
}
257336
unnamed_field => {
258337
cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
@@ -261,12 +340,7 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
261340
}
262341

263342
// Create the method itself.
264-
let body;
265-
match outer_expr {
266-
None => cx.span_unimpl(span, ~"empty structs with `deriving_eq`"),
267-
Some(outer_expr) => body = outer_expr,
268-
}
269-
343+
let body = finish_chain_expr(cx, span, outer_expr, junction);
270344
return create_method(cx, span, method_ident, type_ident, body);
271345
}
272346

@@ -305,8 +379,6 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
305379
let self_ident = cx.ident_of(~"self");
306380
let other_ident = cx.ident_of(~"__other");
307381

308-
let _binop = junction.to_binop();
309-
310382
let is_eq;
311383
match junction {
312384
Conjunction => is_eq = true,
@@ -317,13 +389,40 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
317389
let self_arms = dvec::DVec();
318390
for enum_definition.variants.each |self_variant| {
319391
let other_arms = dvec::DVec();
320-
let self_variant_ident = self_variant.node.name;
321392

322393
// Create the matching pattern.
323-
let matching_pat = build::mk_pat_ident(cx, span, self_variant_ident);
394+
let matching_pat = create_enum_variant_pattern(cx,
395+
span,
396+
self_variant,
397+
~"__other");
324398

325399
// Create the matching pattern body.
326-
let matching_body_expr = build::mk_bool(cx, span, is_eq);
400+
let mut matching_body_expr = None;
401+
for uint::range(0, variant_arg_count(cx, span, self_variant)) |i| {
402+
// Create the expression for the other field.
403+
let other_field_ident = cx.ident_of(~"__other" + i.to_str());
404+
let other_field = build::mk_path(cx,
405+
span,
406+
~[ other_field_ident ]);
407+
408+
// Create the expression for this field.
409+
let self_field_ident = cx.ident_of(~"__self" + i.to_str());
410+
let self_field = build::mk_path(cx, span, ~[ self_field_ident ]);
411+
412+
// Call the substructure method.
413+
call_substructure_method(cx,
414+
span,
415+
self_field,
416+
other_field,
417+
method_ident,
418+
junction,
419+
&mut matching_body_expr);
420+
}
421+
422+
let matching_body_expr = finish_chain_expr(cx,
423+
span,
424+
matching_body_expr,
425+
junction);
327426
let matching_body_block = build::mk_simple_block(cx,
328427
span,
329428
matching_body_expr);
@@ -358,7 +457,10 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
358457
other_arms.push(move nonmatching_arm);
359458

360459
// Create the self pattern.
361-
let self_pat = build::mk_pat_ident(cx, span, self_variant_ident);
460+
let self_pat = create_enum_variant_pattern(cx,
461+
span,
462+
self_variant,
463+
~"__self");
362464

363465
// Create the self pattern body.
364466
let other_expr = build::mk_path(cx, span, ~[ other_ident ]);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[deriving_eq]
2+
enum Foo {
3+
Bar(int, int),
4+
Baz(float, float)
5+
}
6+
7+
fn main() {
8+
let a = Bar(1, 2);
9+
let b = Bar(1, 2);
10+
assert a == b;
11+
assert !(a != b);
12+
assert a.eq(&b);
13+
assert !a.ne(&b);
14+
}
15+

0 commit comments

Comments
 (0)