-// 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.
//
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",
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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)
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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)
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 ])
+}
-// 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.
//
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,
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 \
}
}
-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,
}
}
-/// 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)
@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,
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)
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,
})
}
-fn create_enum_variant_pattern(cx: @ext_ctxt,
+pub fn create_enum_variant_pattern(cx: @ext_ctxt,
span: span,
variant: &variant,
prefix: ~str)
}
}
-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(),
}
}
-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 {
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)
-}
-