diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 652bc541a1f..447ca71dc6b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -153,13 +153,13 @@ pub fn syntax_expander_table() -> SyntaxEnv { ext::deriving::expand_meta_deriving))); syntax_expanders.insert(@~"deriving_eq", @SE(ItemDecorator( - ext::deriving::expand_deriving_eq))); + ext::deriving::eq::expand_deriving_eq))); syntax_expanders.insert(@~"deriving_iter_bytes", @SE(ItemDecorator( - ext::deriving::expand_deriving_iter_bytes))); + ext::deriving::iter_bytes::expand_deriving_iter_bytes))); syntax_expanders.insert(@~"deriving_clone", @SE(ItemDecorator( - ext::deriving::expand_deriving_clone))); + ext::deriving::clone::expand_deriving_clone))); // Quasi-quoting expanders syntax_expanders.insert(@~"quote_tokens", diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs new file mode 100644 index 00000000000..072cd0f6c39 --- /dev/null +++ b/src/libsyntax/ext/deriving/clone.rs @@ -0,0 +1,289 @@ +// Copyright 2012-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 core::prelude::*; + +use ast; +use ast::{TraitTyParamBound, Ty, and, bind_by_ref, binop, deref, enum_def}; +use ast::{enum_variant_kind, expr, expr_match, ident, impure_fn, item, item_}; +use ast::{item_enum, item_impl, item_struct, Generics}; +use ast::{m_imm, meta_item, method}; +use ast::{named_field, or, pat, pat_ident, pat_wild, public, pure_fn}; +use ast::{stmt, struct_def, struct_variant_kind}; +use ast::{sty_by_ref, sty_region, tuple_variant_kind, ty_nil, TyParam}; +use ast::{TyParamBound, ty_path, ty_rptr, unnamed_field, variant}; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; + +use core::uint; + +pub fn expand_deriving_clone(cx: @ext_ctxt, + span: span, + _: @meta_item, + in_items: ~[@item]) + -> ~[@item] { + expand_deriving(cx, + span, + in_items, + expand_deriving_clone_struct_def, + expand_deriving_clone_enum_def) +} + +fn create_derived_clone_impl(cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + method: @method) + -> @item { + let methods = [ method ]; + let trait_path = [ + cx.ident_of(~"core"), + cx.ident_of(~"clone"), + cx.ident_of(~"Clone"), + ]; + create_derived_impl(cx, span, type_ident, generics, methods, trait_path) +} +// Creates a method from the given expression conforming to the signature of +// the `clone` method. +fn create_clone_method(cx: @ext_ctxt, + span: span, + +type_ident: ast::ident, + generics: &Generics, + expr: @ast::expr) + -> @method { + // Create the type parameters of the return value. + let mut output_ty_params = ~[]; + for generics.ty_params.each |ty_param| { + let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]); + output_ty_params.push(path); + } + + // Create the type of the return value. + let output_type_path = build::mk_raw_path_(span, + ~[ type_ident ], + output_ty_params); + let output_type = ast::ty_path(output_type_path, cx.next_id()); + let output_type = @ast::Ty { + id: cx.next_id(), + node: output_type, + span: span + }; + + // Create the function declaration. + let fn_decl = build::mk_fn_decl(~[], output_type); + + // Create the body block. + let body_block = build::mk_simple_block(cx, span, expr); + + // Create the self type and method identifier. + let self_ty = spanned { node: sty_region(None, m_imm), span: span }; + let method_ident = cx.ident_of(~"clone"); + + // Create the method. + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public, + } +} + +fn call_substructure_clone_method(cx: @ext_ctxt, + span: span, + self_field: @expr) + -> @expr { + // Call the substructure method. + let clone_ident = cx.ident_of(~"clone"); + let self_method = build::mk_access_(cx, span, self_field, clone_ident); + build::mk_call_(cx, span, self_method, ~[]) +} + +fn expand_deriving_clone_struct_def(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @item { + // Create the method. + let method = if !is_struct_tuple(struct_def) { + expand_deriving_clone_struct_method(cx, + span, + struct_def, + type_ident, + generics) + } else { + expand_deriving_clone_tuple_struct_method(cx, + span, + struct_def, + type_ident, + generics) + }; + + // Create the implementation. + create_derived_clone_impl(cx, span, type_ident, generics, method) +} + +fn expand_deriving_clone_enum_def(cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics) + -> @item { + // Create the method. + let method = expand_deriving_clone_enum_method(cx, + span, + enum_definition, + type_ident, + generics); + + // Create the implementation. + create_derived_clone_impl(cx, span, type_ident, generics, method) +} + +fn expand_deriving_clone_struct_method(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @method { + let self_ident = cx.ident_of(~"self"); + + // Create the new fields. + let mut fields = ~[]; + 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 call = call_substructure_clone_method(cx, + span, + self_field); + + let field = build::Field { ident: ident, ex: call }; + fields.push(field); + } + unnamed_field => { + cx.span_bug(span, + ~"unnamed fields in \ + expand_deriving_clone_struct_method"); + } + } + } + + // Create the struct literal. + let struct_literal = build::mk_struct_e(cx, + span, + ~[ type_ident ], + fields); + create_clone_method(cx, span, type_ident, generics, struct_literal) +} + +fn expand_deriving_clone_tuple_struct_method(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @method { + // Create the pattern for the match. + let matching_path = build::mk_raw_path(span, ~[ type_ident ]); + let field_count = struct_def.fields.len(); + let subpats = create_subpatterns(cx, span, ~"__self", field_count); + let pat = build::mk_pat_enum(cx, span, matching_path, subpats); + + // Create the new fields. + let mut subcalls = ~[]; + for uint::range(0, struct_def.fields.len()) |i| { + // Create the expression for this field. + let field_ident = cx.ident_of(~"__self" + i.to_str()); + let field = build::mk_path(cx, span, ~[ field_ident ]); + + // Call the substructure method. + let subcall = call_substructure_clone_method(cx, span, field); + subcalls.push(subcall); + } + + // Create the call to the struct constructor. + let call = build::mk_call(cx, span, ~[ type_ident ], subcalls); + + // Create the pattern body. + let match_body_block = build::mk_simple_block(cx, span, call); + + // Create the arm. + let arm = ast::arm { + pats: ~[ pat ], + guard: None, + body: match_body_block + }; + + // Create the method body. + let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]); + + // Create the method. + create_clone_method(cx, span, type_ident, generics, self_match_expr) +} + +fn expand_deriving_clone_enum_method(cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics) + -> @method { + // Create the arms of the match in the method body. + let arms = do enum_definition.variants.map |variant| { + // Create the matching pattern. + let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); + + // Iterate over the variant arguments, creating the subcalls. + let mut subcalls = ~[]; + 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 subcall = call_substructure_clone_method(cx, span, field); + subcalls.push(subcall); + } + + // Create the call to the enum variant (if necessary). + let call = if subcalls.len() > 0 { + build::mk_call(cx, span, ~[ variant.node.name ], subcalls) + } else { + build::mk_path(cx, span, ~[ variant.node.name ]) + }; + + // Create the pattern body. + let match_body_block = build::mk_simple_block(cx, span, call); + + // Create the arm. + ast::arm { pats: ~[ pat ], guard: None, body: match_body_block } + }; + + // Create the method body. + let self_match_expr = expand_enum_or_struct_match(cx, span, arms); + + // Create the method. + create_clone_method(cx, span, type_ident, generics, self_match_expr) +} diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs new file mode 100644 index 00000000000..6213eeca134 --- /dev/null +++ b/src/libsyntax/ext/deriving/eq.rs @@ -0,0 +1,498 @@ +// Copyright 2012-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 core::prelude::*; + +use ast; +use ast::{TraitTyParamBound, Ty, and, bind_by_ref, binop, deref, enum_def}; +use ast::{enum_variant_kind, expr, expr_match, ident, impure_fn, item, item_}; +use ast::{item_enum, item_impl, item_struct, Generics}; +use ast::{m_imm, meta_item, method}; +use ast::{named_field, or, pat, pat_ident, pat_wild, public, pure_fn}; +use ast::{stmt, struct_def, struct_variant_kind}; +use ast::{sty_by_ref, sty_region, tuple_variant_kind, ty_nil, TyParam}; +use ast::{TyParamBound, ty_path, ty_rptr, unnamed_field, variant}; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; + +use core::uint; + +enum Junction { + Conjunction, + Disjunction, +} + +pub impl Junction { + fn to_binop(self) -> binop { + match self { + Conjunction => and, + Disjunction => or, + } + } +} + +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) +} + +/// Creates a method from the given expression, the signature of which +/// conforms to the `eq` or `ne` method. +fn create_eq_method(cx: @ext_ctxt, + span: span, + method_ident: ident, + type_ident: ident, + generics: &Generics, + body: @expr) + -> @method { + // Create the type of the `other` parameter. + let arg_path_type = create_self_type_with_params(cx, + span, + type_ident, + generics); + let arg_type = ty_rptr( + None, + ast::mt { ty: arg_path_type, mutbl: m_imm } + ); + let arg_type = @ast::Ty { + id: cx.next_id(), + node: arg_type, + span: span, + }; + + // Create the `other` parameter. + let other_ident = cx.ident_of(~"__other"); + 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"); + let output_type = build::mk_raw_path(span, ~[ bool_ident ]); + let output_type = ty_path(output_type, cx.next_id()); + let output_type = @ast::Ty { + id: cx.next_id(), + node: output_type, + span: span, + }; + + // Create the function declaration. + let fn_decl = build::mk_fn_decl(~[ arg ], output_type); + + // Create the body block. + let body_block = build::mk_simple_block(cx, span, body); + + // Create the method. + let self_ty = spanned { node: sty_region(None, m_imm), span: span }; + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn create_derived_eq_impl(cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + 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, generics, methods, trait_path) +} + +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 expand_deriving_eq_struct_def(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @item { + // Create the methods. + let eq_ident = cx.ident_of(~"eq"); + let ne_ident = cx.ident_of(~"ne"); + + let derive_struct_fn = if is_struct_tuple(struct_def) { + expand_deriving_eq_struct_tuple_method + } else { + expand_deriving_eq_struct_method + }; + + let eq_method = derive_struct_fn(cx, + span, + struct_def, + eq_ident, + type_ident, + generics, + Conjunction); + let ne_method = derive_struct_fn(cx, + span, + struct_def, + ne_ident, + type_ident, + generics, + Disjunction); + + // Create the implementation. + return create_derived_eq_impl(cx, + span, + type_ident, + generics, + eq_method, + ne_method); +} + +fn expand_deriving_eq_enum_def(cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics) + -> @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, + generics, + Conjunction); + let ne_method = expand_deriving_eq_enum_method(cx, + span, + enum_definition, + ne_ident, + type_ident, + generics, + Disjunction); + + // Create the implementation. + return create_derived_eq_impl(cx, + span, + type_ident, + generics, + eq_method, + ne_method); +} + +fn expand_deriving_eq_struct_method(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + method_ident: ident, + type_ident: ident, + generics: &Generics, + junction: Junction) + -> @method { + let self_ident = cx.ident_of(~"self"); + let other_ident = cx.ident_of(~"__other"); + + // Create the body of the method. + let mut outer_expr = None; + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + // Create the accessor for the other field. + let other_field = build::mk_access(cx, + span, + ~[ other_ident ], + ident); + let other_field_ref = build::mk_addr_of(cx, + span, + other_field); + + // Create the accessor for this field. + let self_field = build::mk_access(cx, + span, + ~[ self_ident ], + ident); + + // Call the substructure method. + 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`"); + } + } + } + + // Create the method itself. + let body = finish_eq_chain_expr(cx, span, outer_expr, junction); + return create_eq_method(cx, + span, + method_ident, + type_ident, + generics, + body); +} + +fn expand_deriving_eq_enum_method(cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + method_ident: ident, + type_ident: ident, + generics: &Generics, + junction: Junction) + -> @method { + let self_ident = cx.ident_of(~"self"); + let other_ident = cx.ident_of(~"__other"); + + let is_eq; + match junction { + Conjunction => is_eq = true, + Disjunction => is_eq = false, + } + + // Create the arms of the self match in the method body. + let mut self_arms = ~[]; + for enum_definition.variants.each |self_variant| { + let mut other_arms = ~[]; + + // Create the matching pattern. + let matching_pat = create_enum_variant_pattern(cx, + span, + self_variant, + ~"__other"); + + // Create the matching pattern body. + 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); + + // Create the matching arm. + let matching_arm = ast::arm { + pats: ~[ matching_pat ], + guard: None, + body: matching_body_block + }; + other_arms.push(matching_arm); + + // Maybe generate a non-matching case. If there is only one + // variant then there will always be a match. + if enum_definition.variants.len() > 1 { + // Create the nonmatching pattern. + let nonmatching_pat = @ast::pat { + id: cx.next_id(), + node: pat_wild, + span: span + }; + + // Create the nonmatching pattern body. + let nonmatching_expr = build::mk_bool(cx, span, !is_eq); + let nonmatching_body_block = + build::mk_simple_block(cx, + span, + nonmatching_expr); + + // Create the nonmatching arm. + let nonmatching_arm = ast::arm { + pats: ~[ nonmatching_pat ], + guard: None, + body: nonmatching_body_block, + }; + other_arms.push(nonmatching_arm); + } + + // Create the self pattern. + 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 ]); + let other_expr = build::mk_unary(cx, span, deref, other_expr); + let other_match_expr = expr_match(other_expr, other_arms); + let other_match_expr = build::mk_expr(cx, + span, + other_match_expr); + let other_match_body_block = build::mk_simple_block(cx, + span, + other_match_expr); + + // Create the self arm. + let self_arm = ast::arm { + pats: ~[ self_pat ], + guard: None, + body: other_match_body_block, + }; + self_arms.push(self_arm); + } + + // Create the method body. + let self_expr = build::mk_path(cx, span, ~[ self_ident ]); + let self_expr = build::mk_unary(cx, span, deref, self_expr); + let self_match_expr = expr_match(self_expr, self_arms); + let self_match_expr = build::mk_expr(cx, span, self_match_expr); + + // Create the method. + return create_eq_method(cx, + span, + method_ident, + type_ident, + generics, + self_match_expr); +} + +fn expand_deriving_eq_struct_tuple_method(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + method_ident: ident, + type_ident: ident, + generics: &Generics, + junction: Junction) + -> @method { + let self_str = ~"self"; + let other_str = ~"__other"; + let type_path = build::mk_raw_path(span, ~[type_ident]); + let fields = copy struct_def.fields; + + // Create comparison expression, comparing each of the fields + let mut match_body = None; + for fields.eachi |i, _| { + let other_field_ident = cx.ident_of(other_str + i.to_str()); + let other_field = build::mk_path(cx, span, ~[ other_field_ident ]); + + let self_field_ident = cx.ident_of(self_str + i.to_str()); + let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); + + call_substructure_eq_method(cx, span, self_field, other_field, + method_ident, junction, &mut match_body); + } + let match_body = finish_eq_chain_expr(cx, span, match_body, junction); + + // Create arm for the '__other' match, containing the comparison expr + let other_subpats = create_subpatterns(cx, span, other_str, fields.len()); + let other_arm = ast::arm { + pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ], + guard: None, + body: build::mk_simple_block(cx, span, match_body), + }; + + // Create the match on '__other' + let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]); + let other_expr = build::mk_unary(cx, span, deref, other_expr); + let other_match_expr = expr_match(other_expr, ~[other_arm]); + let other_match_expr = build::mk_expr(cx, span, other_match_expr); + + // Create arm for the 'self' match, which contains the '__other' match + let self_subpats = create_subpatterns(cx, span, self_str, fields.len()); + let self_arm = ast::arm { + pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)], + guard: None, + body: build::mk_simple_block(cx, span, other_match_expr), + }; + + // Create the match on 'self' + let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]); + let self_expr = build::mk_unary(cx, span, deref, self_expr); + let self_match_expr = expr_match(self_expr, ~[self_arm]); + let self_match_expr = build::mk_expr(cx, span, self_match_expr); + + create_eq_method(cx, span, method_ident, + type_ident, generics, self_match_expr) +} diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs new file mode 100644 index 00000000000..613e9c295eb --- /dev/null +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -0,0 +1,256 @@ +// Copyright 2012-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 core::prelude::*; + +use ast; +use ast::{TraitTyParamBound, Ty, and, bind_by_ref, binop, deref, enum_def}; +use ast::{enum_variant_kind, expr, expr_match, ident, impure_fn, item, item_}; +use ast::{item_enum, item_impl, item_struct, Generics}; +use ast::{m_imm, meta_item, method}; +use ast::{named_field, or, pat, pat_ident, pat_wild, public, pure_fn}; +use ast::{stmt, struct_def, struct_variant_kind}; +use ast::{sty_by_ref, sty_region, tuple_variant_kind, ty_nil, TyParam}; +use ast::{TyParamBound, ty_path, ty_rptr, unnamed_field, variant}; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; + +use core::uint; + +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 create_derived_iter_bytes_impl(cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + 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, generics, 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 = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; + + // Create the function declaration. + let inputs = ~[ lsb0_arg, f_arg ]; + let fn_decl = build::mk_fn_decl(inputs, output_type); + + // Create the body block. + let body_block = build::mk_block_(cx, span, statements); + + // Create the method. + let self_ty = spanned { node: sty_region(None, m_imm), span: span }; + let method_ident = cx.ident_of(~"iter_bytes"); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +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 expand_deriving_iter_bytes_struct_def(cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @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, + generics, + method); +} + +fn expand_deriving_iter_bytes_enum_def(cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics) + -> @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, + generics, + method); +} + +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 body of the method. + let mut statements = ~[]; + 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. + return create_iter_bytes_method(cx, span, statements); +} + +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 = do enum_definition.variants.mapi |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 mut stmts = ~[]; + 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 match_body_block = build::mk_block_(cx, span, stmts); + + // Create the arm. + ast::arm { + pats: ~[ pat ], + guard: None, + body: match_body_block, + } + }; + + // Create the method body. + let self_match_expr = expand_enum_or_struct_match(cx, span, arms); + let self_match_stmt = build::mk_stmt(cx, span, self_match_expr); + + // Create the method. + create_iter_bytes_method(cx, span, ~[ self_match_stmt ]) +} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index a6165e50c85..63bb4389999 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -26,24 +26,13 @@ use ext::base::ext_ctxt; use ext::build; use codemap::{span, spanned}; use parse::token::special_idents::clownshoes_extensions; -use ast_util; use opt_vec; use core::uint; -enum Junction { - Conjunction, - Disjunction, -} - -pub impl Junction { - fn to_binop(self) -> binop { - match self { - Conjunction => and, - Disjunction => or, - } - } -} +pub mod clone; +pub mod eq; +pub mod iter_bytes; type ExpandDerivingStructDefFn = &'self fn(@ext_ctxt, span, @@ -79,11 +68,11 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, meta_list(tname, _) | meta_word(tname) => { match *tname { - ~"Clone" => expand_deriving_clone(cx, + ~"Clone" => clone::expand_deriving_clone(cx, titem.span, titem, in_items), - ~"Eq" => expand_deriving_eq(cx, titem.span, + ~"Eq" => eq::expand_deriving_eq(cx, titem.span, titem, in_items), - ~"IterBytes" => expand_deriving_iter_bytes(cx, + ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx, titem.span, titem, in_items), tname => { cx.span_err(titem.span, fmt!("unknown \ @@ -98,43 +87,7 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, } } -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) -} - -pub fn expand_deriving_clone(cx: @ext_ctxt, - span: span, - _: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - expand_deriving(cx, - span, - in_items, - expand_deriving_clone_struct_def, - expand_deriving_clone_enum_def) -} - -fn expand_deriving(cx: @ext_ctxt, +pub fn expand_deriving(cx: @ext_ctxt, span: span, in_items: ~[@item], expand_deriving_struct_def: ExpandDerivingStructDefFn, @@ -175,68 +128,7 @@ fn create_impl_item(cx: @ext_ctxt, span: span, +item: item_) -> @item { } } -/// Creates a method from the given expression, the signature of which -/// conforms to the `eq` or `ne` method. -fn create_eq_method(cx: @ext_ctxt, - span: span, - method_ident: ident, - type_ident: ident, - generics: &Generics, - body: @expr) - -> @method { - // Create the type of the `other` parameter. - let arg_path_type = create_self_type_with_params(cx, - span, - type_ident, - generics); - let arg_type = ty_rptr( - None, - ast::mt { ty: arg_path_type, mutbl: m_imm } - ); - let arg_type = @ast::Ty { - id: cx.next_id(), - node: arg_type, - span: span, - }; - - // Create the `other` parameter. - let other_ident = cx.ident_of(~"__other"); - 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"); - let output_type = build::mk_raw_path(span, ~[ bool_ident ]); - let output_type = ty_path(output_type, cx.next_id()); - let output_type = @ast::Ty { - id: cx.next_id(), - node: output_type, - span: span, - }; - - // Create the function declaration. - let fn_decl = build::mk_fn_decl(~[ arg ], output_type); - - // Create the body block. - let body_block = build::mk_simple_block(cx, span, body); - - // Create the method. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } -} - -fn create_self_type_with_params(cx: @ext_ctxt, +pub fn create_self_type_with_params(cx: @ext_ctxt, span: span, type_ident: ident, generics: &Generics) @@ -258,7 +150,7 @@ fn create_self_type_with_params(cx: @ext_ctxt, @ast::Ty { id: cx.next_id(), node: self_type, span: span } } -fn create_derived_impl(cx: @ext_ctxt, +pub fn create_derived_impl(cx: @ext_ctxt, span: span, type_ident: ident, generics: &Generics, @@ -320,154 +212,7 @@ fn create_derived_impl(cx: @ext_ctxt, return create_impl_item(cx, span, impl_item); } -fn create_derived_eq_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - 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, generics, methods, trait_path) -} - -fn create_derived_iter_bytes_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - 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, generics, methods, trait_path) -} - -fn create_derived_clone_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - method: @method) - -> @item { - let methods = [ method ]; - let trait_path = [ - cx.ident_of(~"core"), - cx.ident_of(~"clone"), - cx.ident_of(~"Clone"), - ]; - create_derived_impl(cx, span, type_ident, generics, 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 = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; - - // Create the function declaration. - let inputs = ~[ lsb0_arg, f_arg ]; - let fn_decl = build::mk_fn_decl(inputs, output_type); - - // Create the body block. - let body_block = build::mk_block_(cx, span, statements); - - // Create the method. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of(~"iter_bytes"); - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } -} - -// Creates a method from the given expression conforming to the signature of -// the `clone` method. -fn create_clone_method(cx: @ext_ctxt, - span: span, - +type_ident: ast::ident, - generics: &Generics, - expr: @ast::expr) - -> @method { - // Create the type parameters of the return value. - let mut output_ty_params = ~[]; - for generics.ty_params.each |ty_param| { - let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]); - output_ty_params.push(path); - } - - // Create the type of the return value. - let output_type_path = build::mk_raw_path_(span, - ~[ type_ident ], - output_ty_params); - let output_type = ast::ty_path(output_type_path, cx.next_id()); - let output_type = @ast::Ty { - id: cx.next_id(), - node: output_type, - span: span - }; - - // Create the function declaration. - let fn_decl = build::mk_fn_decl(~[], output_type); - - // Create the body block. - let body_block = build::mk_simple_block(cx, span, expr); - - // Create the self type and method identifier. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of(~"clone"); - - // Create the method. - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public, - } -} - -fn create_subpatterns(cx: @ext_ctxt, +pub fn create_subpatterns(cx: @ext_ctxt, span: span, prefix: ~str, n: uint) @@ -487,7 +232,7 @@ fn create_subpatterns(cx: @ext_ctxt, return subpats; } -fn is_struct_tuple(struct_def: &struct_def) -> bool { +pub fn is_struct_tuple(struct_def: &struct_def) -> bool { struct_def.fields.len() > 0 && struct_def.fields.all(|f| { match f.node.kind { named_field(*) => false, @@ -496,7 +241,7 @@ fn is_struct_tuple(struct_def: &struct_def) -> bool { }) } -fn create_enum_variant_pattern(cx: @ext_ctxt, +pub fn create_enum_variant_pattern(cx: @ext_ctxt, span: span, variant: &variant, prefix: ~str) @@ -542,87 +287,7 @@ fn create_enum_variant_pattern(cx: @ext_ctxt, } } -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 call_substructure_clone_method(cx: @ext_ctxt, - span: span, - self_field: @expr) - -> @expr { - // Call the substructure method. - let clone_ident = cx.ident_of(~"clone"); - let self_method = build::mk_access_(cx, span, self_field, clone_ident); - build::mk_call_(cx, span, self_method, ~[]) -} - -fn variant_arg_count(cx: @ext_ctxt, span: span, variant: &variant) -> uint { +pub fn variant_arg_count(cx: @ext_ctxt, span: span, variant: &variant) -> uint { match variant.node.kind { tuple_variant_kind(ref args) => args.len(), struct_variant_kind(ref struct_def) => struct_def.fields.len(), @@ -632,530 +297,7 @@ fn variant_arg_count(cx: @ext_ctxt, span: span, variant: &variant) -> uint { } } -fn expand_deriving_eq_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the methods. - let eq_ident = cx.ident_of(~"eq"); - let ne_ident = cx.ident_of(~"ne"); - - let derive_struct_fn = if is_struct_tuple(struct_def) { - expand_deriving_eq_struct_tuple_method - } else { - expand_deriving_eq_struct_method - }; - - let eq_method = derive_struct_fn(cx, - span, - struct_def, - eq_ident, - type_ident, - generics, - Conjunction); - let ne_method = derive_struct_fn(cx, - span, - struct_def, - ne_ident, - type_ident, - generics, - Disjunction); - - // Create the implementation. - return create_derived_eq_impl(cx, - span, - type_ident, - generics, - eq_method, - ne_method); -} - -fn expand_deriving_eq_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @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, - generics, - Conjunction); - let ne_method = expand_deriving_eq_enum_method(cx, - span, - enum_definition, - ne_ident, - type_ident, - generics, - Disjunction); - - // Create the implementation. - return create_derived_eq_impl(cx, - span, - type_ident, - generics, - eq_method, - ne_method); -} - -fn expand_deriving_iter_bytes_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @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, - generics, - method); -} - -fn expand_deriving_iter_bytes_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @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, - generics, - method); -} - -fn expand_deriving_clone_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = if !is_struct_tuple(struct_def) { - expand_deriving_clone_struct_method(cx, - span, - struct_def, - type_ident, - generics) - } else { - expand_deriving_clone_tuple_struct_method(cx, - span, - struct_def, - type_ident, - generics) - }; - - // Create the implementation. - create_derived_clone_impl(cx, span, type_ident, generics, method) -} - -fn expand_deriving_clone_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = expand_deriving_clone_enum_method(cx, - span, - enum_definition, - type_ident, - generics); - - // Create the implementation. - create_derived_clone_impl(cx, span, type_ident, generics, method) -} - -fn expand_deriving_eq_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_ident = cx.ident_of(~"self"); - let other_ident = cx.ident_of(~"__other"); - - // Create the body of the method. - let mut outer_expr = None; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _, _) => { - // Create the accessor for the other field. - let other_field = build::mk_access(cx, - span, - ~[ other_ident ], - ident); - let other_field_ref = build::mk_addr_of(cx, - span, - other_field); - - // Create the accessor for this field. - let self_field = build::mk_access(cx, - span, - ~[ self_ident ], - ident); - - // Call the substructure method. - 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`"); - } - } - } - - // Create the method itself. - let body = finish_eq_chain_expr(cx, span, outer_expr, junction); - return create_eq_method(cx, - span, - method_ident, - type_ident, - generics, - body); -} - -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 body of the method. - let mut statements = ~[]; - 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. - return create_iter_bytes_method(cx, span, statements); -} - -fn expand_deriving_clone_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @method { - let self_ident = cx.ident_of(~"self"); - - // Create the new fields. - let mut fields = ~[]; - 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 call = call_substructure_clone_method(cx, - span, - self_field); - - let field = build::Field { ident: ident, ex: call }; - fields.push(field); - } - unnamed_field => { - cx.span_bug(span, - ~"unnamed fields in \ - expand_deriving_clone_struct_method"); - } - } - } - - // Create the struct literal. - let struct_literal = build::mk_struct_e(cx, - span, - ~[ type_ident ], - fields); - create_clone_method(cx, span, type_ident, generics, struct_literal) -} - -fn expand_deriving_clone_tuple_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @method { - // Create the pattern for the match. - let matching_path = build::mk_raw_path(span, ~[ type_ident ]); - let field_count = struct_def.fields.len(); - let subpats = create_subpatterns(cx, span, ~"__self", field_count); - let pat = build::mk_pat_enum(cx, span, matching_path, subpats); - - // Create the new fields. - let mut subcalls = ~[]; - for uint::range(0, struct_def.fields.len()) |i| { - // Create the expression for this field. - let field_ident = cx.ident_of(~"__self" + i.to_str()); - let field = build::mk_path(cx, span, ~[ field_ident ]); - - // Call the substructure method. - let subcall = call_substructure_clone_method(cx, span, field); - subcalls.push(subcall); - } - - // Create the call to the struct constructor. - let call = build::mk_call(cx, span, ~[ type_ident ], subcalls); - - // Create the pattern body. - let match_body_block = build::mk_simple_block(cx, span, call); - - // Create the arm. - let arm = ast::arm { - pats: ~[ pat ], - guard: None, - body: match_body_block - }; - - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]); - - // Create the method. - create_clone_method(cx, span, type_ident, generics, self_match_expr) -} - -fn expand_deriving_eq_enum_method(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_ident = cx.ident_of(~"self"); - let other_ident = cx.ident_of(~"__other"); - - let is_eq; - match junction { - Conjunction => is_eq = true, - Disjunction => is_eq = false, - } - - // Create the arms of the self match in the method body. - let mut self_arms = ~[]; - for enum_definition.variants.each |self_variant| { - let mut other_arms = ~[]; - - // Create the matching pattern. - let matching_pat = create_enum_variant_pattern(cx, - span, - self_variant, - ~"__other"); - - // Create the matching pattern body. - 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); - - // Create the matching arm. - let matching_arm = ast::arm { - pats: ~[ matching_pat ], - guard: None, - body: matching_body_block - }; - other_arms.push(matching_arm); - - // Maybe generate a non-matching case. If there is only one - // variant then there will always be a match. - if enum_definition.variants.len() > 1 { - // Create the nonmatching pattern. - let nonmatching_pat = @ast::pat { - id: cx.next_id(), - node: pat_wild, - span: span - }; - - // Create the nonmatching pattern body. - let nonmatching_expr = build::mk_bool(cx, span, !is_eq); - let nonmatching_body_block = - build::mk_simple_block(cx, - span, - nonmatching_expr); - - // Create the nonmatching arm. - let nonmatching_arm = ast::arm { - pats: ~[ nonmatching_pat ], - guard: None, - body: nonmatching_body_block, - }; - other_arms.push(nonmatching_arm); - } - - // Create the self pattern. - 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 ]); - let other_expr = build::mk_unary(cx, span, deref, other_expr); - let other_match_expr = expr_match(other_expr, other_arms); - let other_match_expr = build::mk_expr(cx, - span, - other_match_expr); - let other_match_body_block = build::mk_simple_block(cx, - span, - other_match_expr); - - // Create the self arm. - let self_arm = ast::arm { - pats: ~[ self_pat ], - guard: None, - body: other_match_body_block, - }; - self_arms.push(self_arm); - } - - // Create the method body. - let self_expr = build::mk_path(cx, span, ~[ self_ident ]); - let self_expr = build::mk_unary(cx, span, deref, self_expr); - let self_match_expr = expr_match(self_expr, self_arms); - let self_match_expr = build::mk_expr(cx, span, self_match_expr); - - // Create the method. - return create_eq_method(cx, - span, - method_ident, - type_ident, - generics, - self_match_expr); -} - -fn expand_deriving_eq_struct_tuple_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_str = ~"self"; - let other_str = ~"__other"; - let type_path = build::mk_raw_path(span, ~[type_ident]); - let fields = copy struct_def.fields; - - // Create comparison expression, comparing each of the fields - let mut match_body = None; - for fields.eachi |i, _| { - let other_field_ident = cx.ident_of(other_str + i.to_str()); - let other_field = build::mk_path(cx, span, ~[ other_field_ident ]); - - let self_field_ident = cx.ident_of(self_str + i.to_str()); - let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); - - call_substructure_eq_method(cx, span, self_field, other_field, - method_ident, junction, &mut match_body); - } - let match_body = finish_eq_chain_expr(cx, span, match_body, junction); - - // Create arm for the '__other' match, containing the comparison expr - let other_subpats = create_subpatterns(cx, span, other_str, fields.len()); - let other_arm = ast::arm { - pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ], - guard: None, - body: build::mk_simple_block(cx, span, match_body), - }; - - // Create the match on '__other' - let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]); - let other_expr = build::mk_unary(cx, span, deref, other_expr); - let other_match_expr = expr_match(other_expr, ~[other_arm]); - let other_match_expr = build::mk_expr(cx, span, other_match_expr); - - // Create arm for the 'self' match, which contains the '__other' match - let self_subpats = create_subpatterns(cx, span, self_str, fields.len()); - let self_arm = ast::arm { - pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)], - guard: None, - body: build::mk_simple_block(cx, span, other_match_expr), - }; - - // Create the match on 'self' - let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]); - let self_expr = build::mk_unary(cx, span, deref, self_expr); - let self_match_expr = expr_match(self_expr, ~[self_arm]); - let self_match_expr = build::mk_expr(cx, span, self_match_expr); - - create_eq_method(cx, span, method_ident, - type_ident, generics, self_match_expr) -} - -fn expand_enum_or_struct_match(cx: @ext_ctxt, +pub fn expand_enum_or_struct_match(cx: @ext_ctxt, span: span, arms: ~[ ast::arm ]) -> @expr { @@ -1165,103 +307,3 @@ fn expand_enum_or_struct_match(cx: @ext_ctxt, let self_match_expr = expr_match(self_expr, arms); build::mk_expr(cx, span, 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 = do enum_definition.variants.mapi |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 mut stmts = ~[]; - 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 match_body_block = build::mk_block_(cx, span, stmts); - - // Create the arm. - ast::arm { - pats: ~[ pat ], - guard: None, - body: match_body_block, - } - }; - - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, arms); - let self_match_stmt = build::mk_stmt(cx, span, self_match_expr); - - // Create the method. - create_iter_bytes_method(cx, span, ~[ self_match_stmt ]) -} - -fn expand_deriving_clone_enum_method(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @method { - // Create the arms of the match in the method body. - let arms = do enum_definition.variants.map |variant| { - // Create the matching pattern. - let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); - - // Iterate over the variant arguments, creating the subcalls. - let mut subcalls = ~[]; - 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 subcall = call_substructure_clone_method(cx, span, field); - subcalls.push(subcall); - } - - // Create the call to the enum variant (if necessary). - let call = if subcalls.len() > 0 { - build::mk_call(cx, span, ~[ variant.node.name ], subcalls) - } else { - build::mk_path(cx, span, ~[ variant.node.name ]) - }; - - // Create the pattern body. - let match_body_block = build::mk_simple_block(cx, span, call); - - // Create the arm. - ast::arm { pats: ~[ pat ], guard: None, body: match_body_block } - }; - - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, arms); - - // Create the method. - create_clone_method(cx, span, type_ident, generics, self_match_expr) -} -