diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ba5d34bfdb411..480cbfe0060a5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -100,6 +100,9 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { syntax_expanders.insert(~"deriving_eq", item_decorator( ext::deriving::expand_deriving_eq)); + syntax_expanders.insert(~"deriving_iter_bytes", + item_decorator( + ext::deriving::expand_deriving_iter_bytes)); // Quasi-quoting expanders syntax_expanders.insert(~"quote_tokens", diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 856cc0884ac14..cc93fd2ae9020 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -39,6 +39,12 @@ fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::path { rp: None, types: ~[]}; return p; } +fn mk_raw_path_(sp: span, + idents: ~[ast::ident], + +types: ~[@ast::Ty]) + -> @ast::path { + @{ span: sp, global: false, idents: idents, rp: None, types: move types } +} fn mk_path(cx: ext_ctxt, sp: span, idents: ~[ast::ident]) -> @ast::expr { mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents))) @@ -136,6 +142,18 @@ fn mk_block(cx: ext_ctxt, sp: span, span: sp }; mk_expr(cx, sp, ast::expr_block(blk)) } +fn mk_block_(cx: ext_ctxt, sp: span, +stmts: ~[@ast::stmt]) -> ast::blk { + { + node: { + view_items: ~[], + stmts: move stmts, + expr: None, + id: cx.next_id(), + rules: ast::default_blk + }, + span: sp + } +} fn mk_simple_block(cx: ext_ctxt, span: span, expr: @ast::expr) -> ast::blk { let block = { view_items: ~[], @@ -152,13 +170,65 @@ fn mk_copy(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { fn mk_managed(cx: ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { mk_expr(cx, sp, ast::expr_unary(ast::box(ast::m_imm), e)) } +fn mk_pat(cx: ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat { + @{ id: cx.next_id(), node: move pat, span: span } +} fn mk_pat_ident(cx: ext_ctxt, span: span, ident: ast::ident) -> @ast::pat { - let path = build::mk_raw_path(span, ~[ ident ]); + let path = mk_raw_path(span, ~[ ident ]); let pat = ast::pat_ident(ast::bind_by_value, path, None); - @{ id: cx.next_id(), node: move pat, span: span } + mk_pat(cx, span, move pat) +} +fn mk_pat_enum(cx: ext_ctxt, + span: span, + path: @ast::path, + +subpats: ~[@ast::pat]) + -> @ast::pat { + let pat = ast::pat_enum(path, Some(move subpats)); + mk_pat(cx, span, move pat) } fn mk_bool(cx: ext_ctxt, span: span, value: bool) -> @ast::expr { let lit_expr = ast::expr_lit(@{ node: ast::lit_bool(value), span: span }); build::mk_expr(cx, span, move lit_expr) } +fn mk_stmt(cx: ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt { + let stmt_ = ast::stmt_semi(expr, cx.next_id()); + @{ node: move stmt_, span: span } +} +fn mk_ty_path(cx: ext_ctxt, + span: span, + idents: ~[ ast::ident ]) + -> @ast::Ty { + let ty = build::mk_raw_path(span, idents); + let ty = ast::ty_path(ty, cx.next_id()); + let ty = @{ id: cx.next_id(), node: move ty, span: span }; + ty +} +fn mk_simple_ty_path(cx: ext_ctxt, + span: span, + ident: ast::ident) + -> @ast::Ty { + mk_ty_path(cx, span, ~[ ident ]) +} +fn mk_arg(cx: ext_ctxt, + span: span, + ident: ast::ident, + ty: @ast::Ty) + -> ast::arg { + let arg_pat = mk_pat_ident(cx, span, ident); + { + mode: ast::infer(cx.next_id()), + ty: ty, + pat: arg_pat, + id: cx.next_id() + } +} +fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl { + { inputs: move inputs, output: output, cf: ast::return_val } +} +fn mk_ty_param(cx: ext_ctxt, + ident: ast::ident, + bounds: @~[ast::ty_param_bound]) + -> ast::ty_param { + { ident: ident, id: cx.next_id(), bounds: bounds } +} diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index 735f2cf9ae1fa..4a92086963ec6 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -1,13 +1,13 @@ /// The compiler code necessary to implement the #[deriving_eq] and -/// #[deriving_ord] extensions. - -use ast::{and, bind_by_value, binop, blk, default_blk, deref, enum_def, expr}; -use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit}; -use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_}; -use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item}; -use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public}; -use ast::{pure_fn, re_anon, return_val, struct_def, sty_region, ty_path}; -use ast::{ty_rptr, unnamed_field}; +/// #[deriving_iter_bytes] extensions. + +use ast::{Ty, and, bind_by_ref, binop, deref, enum_def, enum_variant_kind}; +use ast::{expr, expr_match, ident, item, item_, item_class, item_enum}; +use ast::{item_impl, m_imm, meta_item, method, named_field, or, pat}; +use ast::{pat_ident, pat_wild, public, pure_fn, re_anon, stmt, struct_def}; +use ast::{struct_variant_kind, sty_by_ref, sty_region, tuple_variant_kind}; +use ast::{ty_nil, ty_param, ty_param_bound, ty_path, ty_rptr, unnamed_field}; +use ast::{variant}; use base::ext_ctxt; use codemap::span; use parse::token::special_idents::clownshoes_extensions; @@ -26,28 +26,68 @@ impl Junction { } } +type ExpandDerivingStructDefFn = &fn(ext_ctxt, + span, + x: &struct_def, + ident, + +y: ~[ty_param]) + -> @item; +type ExpandDerivingEnumDefFn = &fn(ext_ctxt, + span, + x: &enum_def, + ident, + +y: ~[ty_param]) + -> @item; + pub fn expand_deriving_eq(cx: ext_ctxt, span: span, _mitem: meta_item, in_items: ~[@item]) -> ~[@item] { + expand_deriving(cx, + span, + in_items, + expand_deriving_eq_struct_def, + expand_deriving_eq_enum_def) +} + +pub fn expand_deriving_iter_bytes(cx: ext_ctxt, + span: span, + _mitem: meta_item, + in_items: ~[@item]) + -> ~[@item] { + expand_deriving(cx, + span, + in_items, + expand_deriving_iter_bytes_struct_def, + expand_deriving_iter_bytes_enum_def) +} + +fn expand_deriving(cx: ext_ctxt, + span: span, + in_items: ~[@item], + expand_deriving_struct_def: ExpandDerivingStructDefFn, + expand_deriving_enum_def: ExpandDerivingEnumDefFn) + -> ~[@item] { let result = dvec::DVec(); for in_items.each |item| { result.push(copy *item); match item.node { - item_class(struct_def, _) => { + item_class(struct_def, copy ty_params) => { result.push(expand_deriving_struct_def(cx, span, struct_def, - item.ident)); + item.ident, + move ty_params)); } - item_enum(ref enum_definition, _) => { + item_enum(ref enum_definition, copy ty_params) => { result.push(expand_deriving_enum_def(cx, span, enum_definition, - item.ident)); + item.ident, + move ty_params)); } - _ => result.push(copy *item) // XXX: Don't copy. + _ => () } } dvec::unwrap(move result) @@ -59,40 +99,32 @@ fn create_impl_item(cx: ext_ctxt, span: span, +item: item_) -> @item { attrs: ~[], id: cx.next_id(), node: move item, - vis: ast::public, + vis: public, span: span, } } /// Creates a method from the given expression, the signature of which /// conforms to the `eq` or `ne` method. -fn create_method(cx: ext_ctxt, - span: span, - method_ident: ident, - type_ident: ident, - body: @expr) - -> @method { +fn create_eq_method(cx: ext_ctxt, + span: span, + method_ident: ident, + type_ident: ident, + ty_params: &[ty_param], + body: @expr) + -> @method { // Create the type of the `other` parameter. - let arg_path_type = build::mk_raw_path(span, ~[ type_ident ]); - let arg_path_type = ty_path(arg_path_type, cx.next_id()); - let arg_path_type = @{ - id: cx.next_id(), - node: move arg_path_type, - span: span - }; + let arg_path_type = create_self_type_with_params(cx, + span, + type_ident, + ty_params); let arg_region = @{ id: cx.next_id(), node: re_anon }; let arg_type = ty_rptr(arg_region, { ty: arg_path_type, mutbl: m_imm }); let arg_type = @{ id: cx.next_id(), node: move arg_type, span: span }; // Create the `other` parameter. let other_ident = cx.ident_of(~"__other"); - let arg_pat = build::mk_pat_ident(cx, span, other_ident); - let arg = { - mode: infer(cx.next_id()), - ty: arg_type, - pat: arg_pat, - id: cx.next_id() - }; + let arg = build::mk_arg(cx, span, other_ident, arg_type); // Create the type of the return value. let bool_ident = cx.ident_of(~"bool"); @@ -105,11 +137,7 @@ fn create_method(cx: ext_ctxt, }; // Create the function declaration. - let fn_decl = { - inputs: ~[ move arg ], - output: output_type, - cf: return_val - }; + let fn_decl = build::mk_fn_decl(~[ move arg ], output_type); // Create the body block. let body_block = build::mk_simple_block(cx, span, body); @@ -131,86 +159,389 @@ fn create_method(cx: ext_ctxt, }; } +fn create_self_type_with_params(cx: ext_ctxt, + span: span, + type_ident: ident, + ty_params: &[ty_param]) + -> @Ty { + // Create the type parameters on the `self` path. + let self_ty_params = dvec::DVec(); + for ty_params.each |ty_param| { + let self_ty_param = build::mk_simple_ty_path(cx, + span, + ty_param.ident); + self_ty_params.push(move self_ty_param); + } + let self_ty_params = dvec::unwrap(move self_ty_params); + + // Create the type of `self`. + let self_type = build::mk_raw_path_(span, + ~[ type_ident ], + move self_ty_params); + let self_type = ty_path(self_type, cx.next_id()); + @{ id: cx.next_id(), node: move self_type, span: span } +} + fn create_derived_impl(cx: ext_ctxt, span: span, type_ident: ident, - eq_method: @method, - ne_method: @method) + +ty_params: ~[ty_param], + methods: &[@method], + trait_path: &[ident]) -> @item { - // Create the reference to the `core::cmp::Eq` trait. - let core_ident = cx.ident_of(~"core"); - let cmp_ident = cx.ident_of(~"cmp"); - let eq_ident = cx.ident_of(~"Eq"); - let core_cmp_eq_idents = ~[ - move core_ident, - move cmp_ident, - move eq_ident - ]; - let core_cmp_eq_path = { + // Create the type parameters. + let impl_ty_params = dvec::DVec(); + for ty_params.each |ty_param| { + let bound = build::mk_ty_path(cx, span, trait_path.map(|x| *x)); + let bounds = @~[ ty_param_bound(bound) ]; + let impl_ty_param = build::mk_ty_param(cx, ty_param.ident, bounds); + impl_ty_params.push(move impl_ty_param); + } + let impl_ty_params = dvec::unwrap(move impl_ty_params); + + // Create the reference to the trait. + let trait_path = { span: span, global: false, - idents: move core_cmp_eq_idents, + idents: trait_path.map(|x| *x), rp: None, types: ~[] }; - let core_cmp_eq_path = @move core_cmp_eq_path; + let trait_path = @move trait_path; let trait_ref = { - path: core_cmp_eq_path, + path: trait_path, ref_id: cx.next_id(), impl_id: cx.next_id(), }; let trait_ref = @move trait_ref; // Create the type of `self`. - let self_type = build::mk_raw_path(span, ~[ type_ident ]); - let self_type = ty_path(self_type, cx.next_id()); - let self_type = @{ id: cx.next_id(), node: move self_type, span: span }; + let self_type = create_self_type_with_params(cx, + span, + type_ident, + ty_params); // Create the impl item. - let impl_item = item_impl(~[], + let impl_item = item_impl(move impl_ty_params, Some(trait_ref), self_type, - ~[ eq_method, ne_method ]); + methods.map(|x| *x)); return create_impl_item(cx, span, move impl_item); } -fn expand_deriving_struct_def(cx: ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident) - -> @item { +fn create_derived_eq_impl(cx: ext_ctxt, + span: span, + type_ident: ident, + +ty_params: ~[ty_param], + eq_method: @method, + ne_method: @method) + -> @item { + let methods = [ eq_method, ne_method ]; + let trait_path = [ + cx.ident_of(~"core"), + cx.ident_of(~"cmp"), + cx.ident_of(~"Eq") + ]; + create_derived_impl(cx, span, type_ident, ty_params, methods, trait_path) +} + +fn create_derived_iter_bytes_impl(cx: ext_ctxt, + span: span, + type_ident: ident, + +ty_params: ~[ty_param], + method: @method) + -> @item { + let methods = [ method ]; + let trait_path = [ + cx.ident_of(~"core"), + cx.ident_of(~"to_bytes"), + cx.ident_of(~"IterBytes") + ]; + create_derived_impl(cx, span, type_ident, ty_params, methods, trait_path) +} + +// Creates a method from the given set of statements conforming to the +// signature of the `iter_bytes` method. +fn create_iter_bytes_method(cx: ext_ctxt, + span: span, + +statements: ~[@stmt]) + -> @method { + // Create the `lsb0` parameter. + let bool_ident = cx.ident_of(~"bool"); + let lsb0_arg_type = build::mk_simple_ty_path(cx, span, bool_ident); + let lsb0_ident = cx.ident_of(~"__lsb0"); + let lsb0_arg = build::mk_arg(cx, span, lsb0_ident, lsb0_arg_type); + + // Create the `f` parameter. + let core_ident = cx.ident_of(~"core"); + let to_bytes_ident = cx.ident_of(~"to_bytes"); + let cb_ident = cx.ident_of(~"Cb"); + let core_to_bytes_cb_ident = ~[ core_ident, to_bytes_ident, cb_ident ]; + let f_arg_type = build::mk_ty_path(cx, span, core_to_bytes_cb_ident); + let f_ident = cx.ident_of(~"__f"); + let f_arg = build::mk_arg(cx, span, f_ident, f_arg_type); + + // Create the type of the return value. + let output_type = @{ id: cx.next_id(), node: ty_nil, span: span }; + + // Create the function declaration. + let inputs = ~[ move lsb0_arg, move f_arg ]; + let fn_decl = build::mk_fn_decl(move inputs, output_type); + + // Create the body block. + let body_block = build::mk_block_(cx, span, move statements); + + // Create the method. + let self_ty = { node: sty_by_ref, span: span }; + let method_ident = cx.ident_of(~"iter_bytes"); + return @{ + ident: method_ident, + attrs: ~[], + tps: ~[], + self_ty: self_ty, + purity: pure_fn, + decl: move fn_decl, + body: move body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn create_enum_variant_pattern(cx: ext_ctxt, + span: span, + variant: &variant, + prefix: ~str) + -> @pat { + let variant_ident = variant.node.name; + match variant.node.kind { + tuple_variant_kind(ref variant_args) => { + if variant_args.len() == 0 { + return build::mk_pat_ident(cx, span, variant_ident); + } + + let subpats = dvec::DVec(); + for variant_args.each |_variant_arg| { + // Create the subidentifier. + let index = subpats.len().to_str(); + let ident = cx.ident_of(prefix + index); + + // Create the subpattern. + let subpath = build::mk_raw_path(span, ~[ ident ]); + let subpat = pat_ident(bind_by_ref(m_imm), subpath, None); + let subpat = build::mk_pat(cx, span, move subpat); + subpats.push(subpat); + } + + let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); + let subpats = dvec::unwrap(move subpats); + return build::mk_pat_enum(cx, span, matching_path, move subpats); + } + struct_variant_kind(*) => { + cx.span_unimpl(span, ~"struct variants for `deriving`"); + } + enum_variant_kind(*) => { + cx.span_unimpl(span, ~"enum variants for `deriving`"); + } + } +} + +fn call_substructure_eq_method(cx: ext_ctxt, + span: span, + self_field: @expr, + other_field_ref: @expr, + method_ident: ident, + junction: Junction, + chain_expr: &mut Option<@expr>) { + // Call the substructure method. + let self_method = build::mk_access_(cx, span, self_field, method_ident); + let self_call = build::mk_call_(cx, + span, + self_method, + ~[ other_field_ref ]); + + // Connect to the outer expression if necessary. + *chain_expr = match *chain_expr { + None => Some(self_call), + Some(copy old_outer_expr) => { + let binop = junction.to_binop(); + let chain_expr = build::mk_binary(cx, + span, + binop, + old_outer_expr, + self_call); + Some(chain_expr) + } + }; +} + +fn finish_eq_chain_expr(cx: ext_ctxt, + span: span, + chain_expr: Option<@expr>, + junction: Junction) + -> @expr { + match chain_expr { + None => { + match junction { + Conjunction => build::mk_bool(cx, span, true), + Disjunction => build::mk_bool(cx, span, false), + } + } + Some(ref outer_expr) => *outer_expr, + } +} + +fn call_substructure_iter_bytes_method(cx: ext_ctxt, + span: span, + self_field: @expr) + -> @stmt { + // Gather up the parameters we want to chain along. + let lsb0_ident = cx.ident_of(~"__lsb0"); + let f_ident = cx.ident_of(~"__f"); + let lsb0_expr = build::mk_path(cx, span, ~[ lsb0_ident ]); + let f_expr = build::mk_path(cx, span, ~[ f_ident ]); + + // Call the substructure method. + let iter_bytes_ident = cx.ident_of(~"iter_bytes"); + let self_method = build::mk_access_(cx, + span, + self_field, + iter_bytes_ident); + let self_call = build::mk_call_(cx, + span, + self_method, + ~[ lsb0_expr, f_expr ]); + + // Create a statement out of this expression. + build::mk_stmt(cx, span, self_call) +} + +fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint { + match variant.node.kind { + tuple_variant_kind(args) => args.len(), + struct_variant_kind(struct_def) => struct_def.fields.len(), + enum_variant_kind(*) => { + cx.span_bug(span, ~"variant_arg_count: enum variants deprecated") + } + } +} + +fn expand_deriving_eq_struct_def(cx: ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + +ty_params: ~[ty_param]) + -> @item { // Create the methods. let eq_ident = cx.ident_of(~"eq"); let ne_ident = cx.ident_of(~"ne"); - let eq_method = expand_deriving_struct_method(cx, - span, - struct_def, - eq_ident, - type_ident, - Conjunction); - let ne_method = expand_deriving_struct_method(cx, - span, - struct_def, - ne_ident, - type_ident, - Disjunction); + let eq_method = expand_deriving_eq_struct_method(cx, + span, + struct_def, + eq_ident, + type_ident, + ty_params, + Conjunction); + let ne_method = expand_deriving_eq_struct_method(cx, + span, + struct_def, + ne_ident, + type_ident, + ty_params, + Disjunction); // Create the implementation. - return create_derived_impl(cx, span, type_ident, eq_method, ne_method); + return create_derived_eq_impl(cx, + span, + type_ident, + move ty_params, + eq_method, + ne_method); } -fn expand_deriving_struct_method(cx: ext_ctxt, - span: span, - struct_def: &struct_def, - method_ident: ident, - type_ident: ident, - junction: Junction) - -> @method { +fn expand_deriving_eq_enum_def(cx: ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + +ty_params: ~[ty_param]) + -> @item { + // Create the methods. + let eq_ident = cx.ident_of(~"eq"); + let ne_ident = cx.ident_of(~"ne"); + let eq_method = expand_deriving_eq_enum_method(cx, + span, + enum_definition, + eq_ident, + type_ident, + ty_params, + Conjunction); + let ne_method = expand_deriving_eq_enum_method(cx, + span, + enum_definition, + ne_ident, + type_ident, + ty_params, + Disjunction); + + // Create the implementation. + return create_derived_eq_impl(cx, + span, + type_ident, + move ty_params, + eq_method, + ne_method); +} + +fn expand_deriving_iter_bytes_struct_def(cx: ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + +ty_params: ~[ty_param]) + -> @item { + // Create the method. + let method = expand_deriving_iter_bytes_struct_method(cx, + span, + struct_def); + + // Create the implementation. + return create_derived_iter_bytes_impl(cx, + span, + type_ident, + move ty_params, + method); +} + +fn expand_deriving_iter_bytes_enum_def(cx: ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + +ty_params: ~[ty_param]) + -> @item { + // Create the method. + let method = expand_deriving_iter_bytes_enum_method(cx, + span, + enum_definition); + + // Create the implementation. + return create_derived_iter_bytes_impl(cx, + span, + type_ident, + move ty_params, + method); +} + +fn expand_deriving_eq_struct_method(cx: ext_ctxt, + span: span, + struct_def: &struct_def, + method_ident: ident, + type_ident: ident, + ty_params: &[ty_param], + junction: Junction) + -> @method { let self_ident = cx.ident_of(~"self"); let other_ident = cx.ident_of(~"__other"); - let binop = junction.to_binop(); - // Create the body of the method. let mut outer_expr = None; for struct_def.fields.each |struct_field| { @@ -232,27 +563,13 @@ fn expand_deriving_struct_method(cx: ext_ctxt, ident); // Call the substructure method. - let self_method = build::mk_access_(cx, - span, - self_field, - method_ident); - let self_call = build::mk_call_(cx, - span, - self_method, - ~[ other_field_ref ]); - - // Connect to the outer expression if necessary. - outer_expr = match outer_expr { - None => Some(self_call), - Some(old_outer_expr) => { - let chain_expr = build::mk_binary(cx, - span, - binop, - old_outer_expr, - self_call); - Some(chain_expr) - } - }; + call_substructure_eq_method(cx, + span, + self_field, + other_field_ref, + method_ident, + junction, + &mut outer_expr); } unnamed_field => { cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`"); @@ -261,52 +578,61 @@ fn expand_deriving_struct_method(cx: ext_ctxt, } // Create the method itself. - let body; - match outer_expr { - None => cx.span_unimpl(span, ~"empty structs with `deriving_eq`"), - Some(outer_expr) => body = outer_expr, - } - - return create_method(cx, span, method_ident, type_ident, body); + let body = finish_eq_chain_expr(cx, span, outer_expr, junction); + return create_eq_method(cx, + span, + method_ident, + type_ident, + ty_params, + body); } -fn expand_deriving_enum_def(cx: ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident) - -> @item { - // Create the methods. - let eq_ident = cx.ident_of(~"eq"); - let ne_ident = cx.ident_of(~"ne"); - let eq_method = expand_deriving_enum_method(cx, - span, - enum_definition, - eq_ident, - type_ident, - Conjunction); - let ne_method = expand_deriving_enum_method(cx, - span, - enum_definition, - ne_ident, - type_ident, - Disjunction); +fn expand_deriving_iter_bytes_struct_method(cx: ext_ctxt, + span: span, + struct_def: &struct_def) + -> @method { + let self_ident = cx.ident_of(~"self"); - // Create the implementation. - return create_derived_impl(cx, span, type_ident, eq_method, ne_method); + // Create the body of the method. + let statements = dvec::DVec(); + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + // Create the accessor for this field. + let self_field = build::mk_access(cx, + span, + ~[ self_ident ], + ident); + + // Call the substructure method. + let stmt = call_substructure_iter_bytes_method(cx, + span, + self_field); + statements.push(stmt); + } + unnamed_field => { + cx.span_unimpl(span, + ~"unnamed fields with `deriving_iter_bytes`"); + } + } + } + + // Create the method itself. + let statements = dvec::unwrap(move statements); + return create_iter_bytes_method(cx, span, move statements); } -fn expand_deriving_enum_method(cx: ext_ctxt, - span: span, - enum_definition: &enum_def, - method_ident: ident, - type_ident: ident, - junction: Junction) - -> @method { +fn expand_deriving_eq_enum_method(cx: ext_ctxt, + span: span, + enum_definition: &enum_def, + method_ident: ident, + type_ident: ident, + ty_params: &[ty_param], + junction: Junction) + -> @method { let self_ident = cx.ident_of(~"self"); let other_ident = cx.ident_of(~"__other"); - let _binop = junction.to_binop(); - let is_eq; match junction { Conjunction => is_eq = true, @@ -317,13 +643,40 @@ fn expand_deriving_enum_method(cx: ext_ctxt, let self_arms = dvec::DVec(); for enum_definition.variants.each |self_variant| { let other_arms = dvec::DVec(); - let self_variant_ident = self_variant.node.name; // Create the matching pattern. - let matching_pat = build::mk_pat_ident(cx, span, self_variant_ident); + let matching_pat = create_enum_variant_pattern(cx, + span, + self_variant, + ~"__other"); // Create the matching pattern body. - let matching_body_expr = build::mk_bool(cx, span, is_eq); + let mut matching_body_expr = None; + for uint::range(0, variant_arg_count(cx, span, self_variant)) |i| { + // Create the expression for the other field. + let other_field_ident = cx.ident_of(~"__other" + i.to_str()); + let other_field = build::mk_path(cx, + span, + ~[ other_field_ident ]); + + // Create the expression for this field. + let self_field_ident = cx.ident_of(~"__self" + i.to_str()); + let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); + + // Call the substructure method. + call_substructure_eq_method(cx, + span, + self_field, + other_field, + method_ident, + junction, + &mut matching_body_expr); + } + + let matching_body_expr = finish_eq_chain_expr(cx, + span, + matching_body_expr, + junction); let matching_body_block = build::mk_simple_block(cx, span, matching_body_expr); @@ -358,7 +711,10 @@ fn expand_deriving_enum_method(cx: ext_ctxt, other_arms.push(move nonmatching_arm); // Create the self pattern. - let self_pat = build::mk_pat_ident(cx, span, self_variant_ident); + let self_pat = create_enum_variant_pattern(cx, + span, + self_variant, + ~"__self"); // Create the self pattern body. let other_expr = build::mk_path(cx, span, ~[ other_ident ]); @@ -389,6 +745,73 @@ fn expand_deriving_enum_method(cx: ext_ctxt, let self_match_expr = build::mk_expr(cx, span, move self_match_expr); // Create the method. - return create_method(cx, span, method_ident, type_ident, self_match_expr); + return create_eq_method(cx, + span, + method_ident, + type_ident, + ty_params, + self_match_expr); +} + +fn expand_deriving_iter_bytes_enum_method(cx: ext_ctxt, + span: span, + enum_definition: &enum_def) + -> @method { + // Create the arms of the match in the method body. + let arms = dvec::DVec(); + for enum_definition.variants.eachi |i, variant| { + // Create the matching pattern. + let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); + + // Determine the discriminant. We will feed this value to the byte + // iteration function. + let discriminant; + match variant.node.disr_expr { + Some(copy disr_expr) => discriminant = disr_expr, + None => discriminant = build::mk_uint(cx, span, i), + } + + // Feed the discriminant to the byte iteration function. + let stmts = dvec::DVec(); + let discrim_stmt = call_substructure_iter_bytes_method(cx, + span, + discriminant); + stmts.push(discrim_stmt); + + // Feed each argument in this variant to the byte iteration function + // as well. + for uint::range(0, variant_arg_count(cx, span, variant)) |j| { + // Create the expression for this field. + let field_ident = cx.ident_of(~"__self" + j.to_str()); + let field = build::mk_path(cx, span, ~[ field_ident ]); + + // Call the substructure method. + let stmt = call_substructure_iter_bytes_method(cx, span, field); + stmts.push(stmt); + } + + // Create the pattern body. + let stmts = dvec::unwrap(move stmts); + let match_body_block = build::mk_block_(cx, span, move stmts); + + // Create the arm. + let arm = { + pats: ~[ pat ], + guard: None, + body: move match_body_block + }; + arms.push(move arm); + } + + // Create the method body. + let self_ident = cx.ident_of(~"self"); + let self_expr = build::mk_path(cx, span, ~[ self_ident ]); + let arms = dvec::unwrap(move arms); + let self_match_expr = expr_match(self_expr, move arms); + let self_match_expr = build::mk_expr(cx, span, move self_match_expr); + let self_match_stmt = build::mk_stmt(cx, span, self_match_expr); + + // Create the method. + return create_iter_bytes_method(cx, span, ~[ self_match_stmt ]); } diff --git a/src/test/run-pass/deriving-via-extension-enum.rs b/src/test/run-pass/deriving-via-extension-enum.rs new file mode 100644 index 0000000000000..ed231d427fb47 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-enum.rs @@ -0,0 +1,15 @@ +#[deriving_eq] +enum Foo { + Bar(int, int), + Baz(float, float) +} + +fn main() { + let a = Bar(1, 2); + let b = Bar(1, 2); + assert a == b; + assert !(a != b); + assert a.eq(&b); + assert !a.ne(&b); +} + diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs new file mode 100644 index 0000000000000..c6023bfcbb226 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs @@ -0,0 +1,16 @@ +#[deriving_iter_bytes] +enum Foo { + Bar(int, char), + Baz(char, int) +} + +#[deriving_iter_bytes] +enum A { + B, + C, + D, + E +} + +fn main(){} + diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs new file mode 100644 index 0000000000000..f5116b4e0e816 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs @@ -0,0 +1,10 @@ +#[deriving_iter_bytes] +struct Foo { + x: int, + y: int, + z: int +} + +fn main() {} + + diff --git a/src/test/run-pass/deriving-via-extension-type-params.rs b/src/test/run-pass/deriving-via-extension-type-params.rs new file mode 100644 index 0000000000000..74ecac67f499e --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-type-params.rs @@ -0,0 +1,17 @@ +#[deriving_eq] +#[deriving_iter_bytes] +struct Foo { + x: int, + y: T, + z: int +} + +fn main() { + let a = Foo { x: 1, y: 2.0, z: 3 }; + let b = Foo { x: 1, y: 2.0, z: 3 }; + assert a == b; + assert !(a != b); + assert a.eq(&b); + assert !a.ne(&b); +} +