diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 390b72da3314b..0c62566702d90 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -8,29 +8,35 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use ast; -use ast::*; +use ast::{meta_item, item, expr}; +use codemap::span; use ext::base::ext_ctxt; use ext::build; -use ext::deriving::*; -use codemap::{span, spanned}; -use ast_util; -use opt_vec; +use ext::deriving::generic::*; +use core::option::{None,Some}; -use core::uint; pub fn expand_deriving_clone(cx: @ext_ctxt, span: span, - _: @meta_item, + mitem: @meta_item, in_items: ~[@item]) -> ~[@item] { - expand_deriving(cx, - span, - in_items, - expand_deriving_clone_struct_def, - expand_deriving_clone_enum_def) + let trait_def = TraitDef { + path: ~[~"core", ~"clone", ~"Clone"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"clone", + nargs: 0, + output_type: None, // return Self + combine_substructure: cs_clone + } + ] + }; + + expand_deriving_generic(cx, span, + mitem, in_items, + &trait_def) } pub fn expand_deriving_obsolete(cx: @ext_ctxt, @@ -42,252 +48,52 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt, in_items } -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"), - ]; - let trait_path = build::mk_raw_path_global(span, trait_path); - create_derived_impl(cx, span, type_ident, generics, methods, trait_path, - opt_vec::Empty, opt_vec::Empty) -} -// 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 cs_clone(cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let clone_ident = substr.method_ident; + let ctor_ident; + let all_fields; + let subcall = |field| + build::mk_method_call(cx, span, field, clone_ident, ~[]); + + match *substr.fields { + Struct(af) => { + ctor_ident = ~[ substr.type_ident ]; + all_fields = af; + } + EnumMatching(_, variant, af) => { + ctor_ident = ~[ variant.node.name ]; + all_fields = af; + }, + EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`") } -} - -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"); - build::mk_method_call(cx, span, - self_field, clone_ident, - ~[]) -} - -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 `deriving(Clone)`"); + match all_fields { + [(None, _, _), .. _] => { + // enum-like + let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f)); + build::mk_call(cx, span, ctor_ident, subcalls) + }, + _ => { + // struct-like + let fields = do all_fields.map |&(o_id, self_f, _)| { + let ident = match o_id { + Some(i) => i, + None => cx.span_bug(span, + ~"unnamed field in normal struct \ + in `deriving(Clone)`") + }; + build::Field { ident: ident, ex: subcall(self_f) } + }; + + if fields.is_empty() { + // no fields, so construct like `None` + build::mk_path(cx, span, ctor_ident) + } else { + build::mk_struct_e(cx, span, + ctor_ident, + fields) } } } - - // 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/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs new file mode 100644 index 0000000000000..142f0565e149e --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -0,0 +1,65 @@ +// Copyright 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 ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +use core::option::Some; + +pub fn expand_deriving_eq(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + // structures are equal if all fields are equal, and non equal, if + // any fields are not equal or if the enum variants are different + fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cx, span, substr) + } + fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_or(|cx, span, _| build::mk_bool(cx, span, true), + cx, span, substr) + } + + + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"Eq"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"ne", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: cs_ne + }, + MethodDef { + name: ~"eq", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: cs_eq + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} + +pub fn expand_deriving_obsolete(cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead"); + in_items +} diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs new file mode 100644 index 0000000000000..7f7babab45cc4 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -0,0 +1,142 @@ +// Copyright 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 ast::{meta_item, item, expr_if, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; +use core::option::Some; + +macro_rules! mk_cso { + ($less:expr, $equal:expr) => { + |cx, span, substr| + cs_ord($less, $equal, cx, span, substr) + } +} + +pub fn expand_deriving_ord(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"Ord"], + // XXX: Ord doesn't imply Eq yet + additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]], + methods: ~[ + MethodDef { + name: ~"lt", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: mk_cso!(true, false) + }, + MethodDef { + name: ~"le", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: mk_cso!(true, true) + }, + MethodDef { + name: ~"gt", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: mk_cso!(false, false) + }, + MethodDef { + name: ~"ge", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: mk_cso!(false, true) + }, + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} + +/// `less`: is this `lt` or `le`? `equal`: is this `le` or `ge`? +fn cs_ord(less: bool, equal: bool, + cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let binop = if less { + cx.ident_of(~"lt") + } else { + cx.ident_of(~"gt") + }; + let false_blk_expr = build::mk_block(cx, span, + ~[], ~[], + Some(build::mk_bool(cx, span, false))); + let true_blk = build::mk_simple_block(cx, span, + build::mk_bool(cx, span, true)); + let base = build::mk_bool(cx, span, equal); + + cs_fold( + false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + /* + + build up a series of nested ifs from the inside out to get + lexical ordering (hence foldr), i.e. + + ``` + if self.f1 `binop` other.f1 { + true + } else if self.f1 == other.f1 { + if self.f2 `binop` other.f2 { + true + } else if self.f2 == other.f2 { + `equal` + } else { + false + } + } else { + false + } + ``` + + The inner "`equal`" case is only reached if the two + items have all fields equal. + */ + if other_fs.len() != 1 { + cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`"); + } + + let cmp = build::mk_method_call(cx, span, + self_f, cx.ident_of(~"eq"), other_fs); + let subexpr = build::mk_simple_block(cx, span, subexpr); + let elseif = expr_if(cmp, subexpr, Some(false_blk_expr)); + let elseif = build::mk_expr(cx, span, elseif); + + let cmp = build::mk_method_call(cx, span, + self_f, binop, other_fs); + let if_ = expr_if(cmp, true_blk, Some(elseif)); + + build::mk_expr(cx, span, if_) + }, + base, + |cx, span, args| { + // nonmatching enums, order by the order the variants are + // written + match args { + [(self_var, _, _), + (other_var, _, _)] => + build::mk_bool(cx, span, + if less { + self_var < other_var + } else { + self_var > other_var + }), + _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`") + } + }, + cx, span, substr) +} diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs new file mode 100644 index 0000000000000..d71db22591dd6 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -0,0 +1,45 @@ +// Copyright 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 ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +use core::option::Some; + +pub fn expand_deriving_totaleq(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + + fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cx, span, substr) + } + + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"TotalEq"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"equals", + output_type: Some(~[~"bool"]), + nargs: 1, + combine_substructure: cs_equals + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs new file mode 100644 index 0000000000000..d82c63e9dd343 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -0,0 +1,77 @@ +// Copyright 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 ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; +use core::cmp::{Ordering, Equal, Less, Greater}; +use core::option::Some; + +pub fn expand_deriving_totalord(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"TotalOrd"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"cmp", + output_type: Some(~[~"core", ~"cmp", ~"Ordering"]), + nargs: 1, + combine_substructure: cs_cmp + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} + + +pub fn ordering_const(cx: @ext_ctxt, span: span, cnst: Ordering) -> @expr { + let cnst = match cnst { + Less => ~"Less", + Equal => ~"Equal", + Greater => ~"Greater" + }; + build::mk_path(cx, span, + ~[cx.ident_of(~"core"), + cx.ident_of(~"cmp"), + cx.ident_of(cnst)]) +} + +pub fn cs_cmp(cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let lexical_ord = ~[cx.ident_of(~"core"), + cx.ident_of(~"cmp"), + cx.ident_of(~"lexical_ordering")]; + + cs_same_method_fold( + // foldr (possibly) nests the matches in lexical_ordering better + false, + |cx, span, old, new| { + build::mk_call(cx, span, lexical_ord, ~[old, new]) + }, + ordering_const(cx, span, Equal), + |cx, span, list| { + match list { + // an earlier nonmatching variant is Less than a + // later one + [(self_var, _, _), + (other_var, _, _)] => ordering_const(cx, span, + self_var.cmp(&other_var)), + _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`") + } + }, + cx, span, substr) +} diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs deleted file mode 100644 index 0afb667c69ab9..0000000000000 --- a/src/libsyntax/ext/deriving/eq.rs +++ /dev/null @@ -1,500 +0,0 @@ -// 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::*; -use ext::base::ext_ctxt; -use ext::build; -use ext::deriving::*; -use codemap::{span, spanned}; -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 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_obsolete(cx: @ext_ctxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead"); - in_items -} - -/// 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") - ]; - let trait_path = build::mk_raw_path_global(span, trait_path); - create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty, []) -} - -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_call = build::mk_method_call(cx, span, - self_field, method_ident, - ~[ 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(fmt!("%s_%u", other_str, i)); - let other_field = build::mk_path(cx, span, ~[ other_field_ident ]); - - let self_field_ident = cx.ident_of(fmt!("%s_%u", self_str, i)); - 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/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 1241d4fa71139..78faf5556b2ce 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -30,12 +30,21 @@ use opt_vec; use core::uint; -pub mod eq; pub mod clone; pub mod iter_bytes; pub mod encodable; pub mod decodable; +#[path="cmp/eq.rs"] +pub mod eq; +#[path="cmp/totaleq.rs"] +pub mod totaleq; +#[path="cmp/ord.rs"] +pub mod ord; +#[path="cmp/totalord.rs"] +pub mod totalord; + + pub mod generic; pub type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt, @@ -74,8 +83,6 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, meta_list(tname, _) | meta_word(tname) => { match *tname { - ~"Eq" => eq::expand_deriving_eq(cx, titem.span, - titem, in_items), ~"Clone" => clone::expand_deriving_clone(cx, titem.span, titem, in_items), ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx, @@ -84,6 +91,14 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, titem.span, titem, in_items), ~"Decodable" => decodable::expand_deriving_decodable(cx, titem.span, titem, in_items), + ~"Eq" => eq::expand_deriving_eq(cx, titem.span, + titem, in_items), + ~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span, + titem, in_items), + ~"Ord" => ord::expand_deriving_ord(cx, titem.span, + titem, in_items), + ~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span, + titem, in_items), tname => { cx.span_err(titem.span, fmt!("unknown \ `deriving` trait: `%s`", tname));