2013-03-19 12:52:10 +00:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-04 00:48:01 +00:00
|
|
|
// 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.
|
|
|
|
|
2013-05-15 22:55:57 +00:00
|
|
|
/*!
|
|
|
|
The compiler code necessary to implement the #[deriving] extensions.
|
|
|
|
|
|
|
|
|
|
|
|
FIXME (#2810)--Hygiene. Search for "__" strings (in other files too).
|
|
|
|
We also assume "std" is the standard library, and "core" is the core
|
|
|
|
library.
|
|
|
|
|
|
|
|
*/
|
2012-11-20 02:05:50 +00:00
|
|
|
|
2013-01-13 18:48:09 +00:00
|
|
|
use ast;
|
2013-05-06 15:23:51 +00:00
|
|
|
use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def};
|
2012-12-13 21:05:22 +00:00
|
|
|
use ext::base::ext_ctxt;
|
2012-12-23 22:41:37 +00:00
|
|
|
use ext::build;
|
2013-03-28 10:50:10 +00:00
|
|
|
use codemap::{span, respan};
|
2012-11-20 02:05:50 +00:00
|
|
|
use parse::token::special_idents::clownshoes_extensions;
|
2013-02-15 05:50:03 +00:00
|
|
|
use opt_vec;
|
2012-11-20 02:05:50 +00:00
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
pub mod clone;
|
2013-03-19 12:52:10 +00:00
|
|
|
pub mod iter_bytes;
|
2013-04-10 23:31:51 +00:00
|
|
|
pub mod encodable;
|
2013-04-09 01:53:39 +00:00
|
|
|
pub mod decodable;
|
2013-05-06 15:30:42 +00:00
|
|
|
pub mod rand;
|
|
|
|
pub mod to_str;
|
2012-11-20 02:05:50 +00:00
|
|
|
|
2013-03-30 14:58:05 +00:00
|
|
|
#[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;
|
|
|
|
|
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
pub mod generic;
|
|
|
|
|
|
|
|
pub type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt,
|
|
|
|
span,
|
|
|
|
x: &struct_def,
|
|
|
|
ident,
|
|
|
|
y: &Generics)
|
|
|
|
-> @item;
|
|
|
|
pub type ExpandDerivingEnumDefFn<'self> = &'self fn(@ext_ctxt,
|
|
|
|
span,
|
|
|
|
x: &enum_def,
|
|
|
|
ident,
|
|
|
|
y: &Generics)
|
|
|
|
-> @item;
|
2012-11-21 02:27:13 +00:00
|
|
|
|
2013-03-12 20:00:50 +00:00
|
|
|
pub fn expand_meta_deriving(cx: @ext_ctxt,
|
2013-03-11 20:47:23 +00:00
|
|
|
_span: span,
|
|
|
|
mitem: @meta_item,
|
|
|
|
in_items: ~[@item])
|
|
|
|
-> ~[@item] {
|
|
|
|
use ast::{meta_list, meta_name_value, meta_word};
|
|
|
|
|
|
|
|
match mitem.node {
|
2013-05-12 04:25:31 +00:00
|
|
|
meta_name_value(_, ref l) => {
|
2013-05-19 05:07:44 +00:00
|
|
|
cx.span_err(l.span, "unexpected value in `deriving`");
|
2013-03-11 20:47:23 +00:00
|
|
|
in_items
|
|
|
|
}
|
|
|
|
meta_word(_) | meta_list(_, []) => {
|
2013-05-19 05:07:44 +00:00
|
|
|
cx.span_warn(mitem.span, "empty trait list in `deriving`");
|
2013-03-11 20:47:23 +00:00
|
|
|
in_items
|
|
|
|
}
|
2013-05-12 04:25:31 +00:00
|
|
|
meta_list(_, ref titems) => {
|
2013-03-11 20:47:23 +00:00
|
|
|
do titems.foldr(in_items) |&titem, in_items| {
|
|
|
|
match titem.node {
|
|
|
|
meta_name_value(tname, _) |
|
|
|
|
meta_list(tname, _) |
|
|
|
|
meta_word(tname) => {
|
2013-05-06 15:23:51 +00:00
|
|
|
macro_rules! expand(($func:path) => ($func(cx, titem.span,
|
|
|
|
titem, in_items)));
|
2013-03-11 20:47:23 +00:00
|
|
|
match *tname {
|
2013-05-06 15:23:51 +00:00
|
|
|
~"Clone" => expand!(clone::expand_deriving_clone),
|
2013-05-16 04:15:37 +00:00
|
|
|
~"DeepClone" => expand!(clone::expand_deriving_deep_clone),
|
2013-05-06 15:23:51 +00:00
|
|
|
|
|
|
|
~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),
|
|
|
|
|
|
|
|
~"Encodable" => expand!(encodable::expand_deriving_encodable),
|
|
|
|
~"Decodable" => expand!(decodable::expand_deriving_decodable),
|
|
|
|
|
|
|
|
~"Eq" => expand!(eq::expand_deriving_eq),
|
|
|
|
~"TotalEq" => expand!(totaleq::expand_deriving_totaleq),
|
|
|
|
~"Ord" => expand!(ord::expand_deriving_ord),
|
|
|
|
~"TotalOrd" => expand!(totalord::expand_deriving_totalord),
|
|
|
|
|
2013-05-06 15:30:42 +00:00
|
|
|
~"Rand" => expand!(rand::expand_deriving_rand),
|
|
|
|
|
|
|
|
~"ToStr" => expand!(to_str::expand_deriving_to_str),
|
|
|
|
|
2013-05-12 04:25:31 +00:00
|
|
|
ref tname => {
|
2013-03-11 20:47:23 +00:00
|
|
|
cx.span_err(titem.span, fmt!("unknown \
|
2013-05-12 04:25:31 +00:00
|
|
|
`deriving` trait: `%s`", *tname));
|
2013-03-11 20:47:23 +00:00
|
|
|
in_items
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn expand_deriving(cx: @ext_ctxt,
|
2012-11-21 02:27:13 +00:00
|
|
|
span: span,
|
|
|
|
in_items: ~[@item],
|
|
|
|
expand_deriving_struct_def: ExpandDerivingStructDefFn,
|
|
|
|
expand_deriving_enum_def: ExpandDerivingEnumDefFn)
|
|
|
|
-> ~[@item] {
|
2013-03-07 23:37:22 +00:00
|
|
|
let mut result = ~[];
|
2012-11-20 02:05:50 +00:00
|
|
|
for in_items.each |item| {
|
|
|
|
result.push(copy *item);
|
|
|
|
match item.node {
|
2013-05-06 15:23:51 +00:00
|
|
|
ast::item_struct(struct_def, ref generics) => {
|
2012-11-20 02:05:50 +00:00
|
|
|
result.push(expand_deriving_struct_def(cx,
|
|
|
|
span,
|
|
|
|
struct_def,
|
2012-11-21 03:20:55 +00:00
|
|
|
item.ident,
|
2013-02-15 05:50:03 +00:00
|
|
|
generics));
|
2012-11-20 02:05:50 +00:00
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
ast::item_enum(ref enum_definition, ref generics) => {
|
2012-11-20 02:05:50 +00:00
|
|
|
result.push(expand_deriving_enum_def(cx,
|
|
|
|
span,
|
|
|
|
enum_definition,
|
2012-11-21 03:20:55 +00:00
|
|
|
item.ident,
|
2013-02-15 05:50:03 +00:00
|
|
|
generics));
|
2012-11-20 02:05:50 +00:00
|
|
|
}
|
2012-11-20 21:01:02 +00:00
|
|
|
_ => ()
|
2012-11-20 02:05:50 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-07 23:37:22 +00:00
|
|
|
result
|
2012-11-20 02:05:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
fn create_impl_item(cx: @ext_ctxt, span: span, item: ast::item_) -> @item {
|
2013-03-28 10:50:10 +00:00
|
|
|
let doc_attr = respan(span,
|
|
|
|
ast::lit_str(@~"Automatically derived."));
|
|
|
|
let doc_attr = respan(span, ast::meta_name_value(@~"doc", doc_attr));
|
|
|
|
let doc_attr = ast::attribute_ {
|
|
|
|
style: ast::attr_outer,
|
|
|
|
value: @doc_attr,
|
|
|
|
is_sugared_doc: false
|
|
|
|
};
|
|
|
|
let doc_attr = respan(span, doc_attr);
|
|
|
|
|
2013-01-13 21:13:41 +00:00
|
|
|
@ast::item {
|
2012-11-20 02:05:50 +00:00
|
|
|
ident: clownshoes_extensions,
|
2013-03-28 10:50:10 +00:00
|
|
|
attrs: ~[doc_attr],
|
2012-11-20 02:05:50 +00:00
|
|
|
id: cx.next_id(),
|
2013-02-15 09:15:53 +00:00
|
|
|
node: item,
|
2013-05-06 15:23:51 +00:00
|
|
|
vis: ast::public,
|
2012-11-20 02:05:50 +00:00
|
|
|
span: span,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn create_self_type_with_params(cx: @ext_ctxt,
|
2012-11-21 03:20:55 +00:00
|
|
|
span: span,
|
|
|
|
type_ident: ident,
|
2013-02-15 05:50:03 +00:00
|
|
|
generics: &Generics)
|
2012-11-21 03:20:55 +00:00
|
|
|
-> @Ty {
|
|
|
|
// Create the type parameters on the `self` path.
|
2013-03-07 23:37:22 +00:00
|
|
|
let mut self_ty_params = ~[];
|
2013-02-15 05:50:03 +00:00
|
|
|
for generics.ty_params.each |ty_param| {
|
2012-11-21 03:20:55 +00:00
|
|
|
let self_ty_param = build::mk_simple_ty_path(cx,
|
|
|
|
span,
|
|
|
|
ty_param.ident);
|
2013-02-15 09:15:53 +00:00
|
|
|
self_ty_params.push(self_ty_param);
|
2012-11-21 03:20:55 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
let lifetime = if generics.lifetimes.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(@*generics.lifetimes.get(0))
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-11-21 03:20:55 +00:00
|
|
|
// Create the type of `self`.
|
|
|
|
let self_type = build::mk_raw_path_(span,
|
|
|
|
~[ type_ident ],
|
2013-05-06 15:23:51 +00:00
|
|
|
lifetime,
|
2013-02-15 09:15:53 +00:00
|
|
|
self_ty_params);
|
2013-05-06 15:23:51 +00:00
|
|
|
build::mk_ty_path_path(cx, span, self_type)
|
2012-11-21 03:20:55 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn create_derived_impl(cx: @ext_ctxt,
|
2013-04-08 16:02:36 +00:00
|
|
|
span: span,
|
|
|
|
type_ident: ident,
|
|
|
|
generics: &Generics,
|
2013-05-06 15:23:51 +00:00
|
|
|
methods: &[@ast::method],
|
2013-04-08 16:02:36 +00:00
|
|
|
trait_path: @ast::Path,
|
2013-05-06 15:23:51 +00:00
|
|
|
mut impl_generics: Generics,
|
|
|
|
bounds_paths: opt_vec::OptVec<@ast::Path>)
|
2013-04-08 16:02:36 +00:00
|
|
|
-> @item {
|
2013-02-15 05:50:03 +00:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Given that we are deriving a trait `Tr` for a type `T<'a, ...,
|
|
|
|
* 'z, A, ..., Z>`, creates an impl like:
|
|
|
|
*
|
2013-03-28 10:50:10 +00:00
|
|
|
* impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
|
|
|
|
*
|
|
|
|
* where B1, B2, ... are the bounds given by `bounds_paths`.
|
2013-02-15 05:50:03 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Copy the lifetimes
|
2013-05-06 15:23:51 +00:00
|
|
|
for generics.lifetimes.each |l| {
|
|
|
|
impl_generics.lifetimes.push(copy *l)
|
|
|
|
};
|
2013-02-15 05:50:03 +00:00
|
|
|
|
2013-04-08 16:02:36 +00:00
|
|
|
// Create the type parameters.
|
|
|
|
for generics.ty_params.each |ty_param| {
|
2013-05-06 15:23:51 +00:00
|
|
|
// extra restrictions on the generics parameters to the type being derived upon
|
2013-03-28 10:50:10 +00:00
|
|
|
let mut bounds = do bounds_paths.map |&bound_path| {
|
2013-05-06 15:23:51 +00:00
|
|
|
build::mk_trait_ty_param_bound_(cx, bound_path)
|
2013-03-28 10:50:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let this_trait_bound =
|
|
|
|
build::mk_trait_ty_param_bound_(cx, trait_path);
|
|
|
|
bounds.push(this_trait_bound);
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
impl_generics.ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds));
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the reference to the trait.
|
|
|
|
let trait_ref = build::mk_trait_ref_(cx, trait_path);
|
2012-11-20 02:05:50 +00:00
|
|
|
|
|
|
|
// Create the type of `self`.
|
2012-11-21 03:20:55 +00:00
|
|
|
let self_type = create_self_type_with_params(cx,
|
|
|
|
span,
|
|
|
|
type_ident,
|
2013-02-15 05:50:03 +00:00
|
|
|
generics);
|
2012-11-20 02:05:50 +00:00
|
|
|
|
|
|
|
// Create the impl item.
|
2013-05-06 15:23:51 +00:00
|
|
|
let impl_item = ast::item_impl(impl_generics,
|
2012-11-20 02:05:50 +00:00
|
|
|
Some(trait_ref),
|
|
|
|
self_type,
|
2012-11-21 02:27:13 +00:00
|
|
|
methods.map(|x| *x));
|
2013-02-15 09:15:53 +00:00
|
|
|
return create_impl_item(cx, span, impl_item);
|
2012-11-20 02:05:50 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn create_subpatterns(cx: @ext_ctxt,
|
2013-05-06 15:23:51 +00:00
|
|
|
span: span,
|
|
|
|
field_paths: ~[@ast::Path],
|
|
|
|
mutbl: ast::mutability)
|
|
|
|
-> ~[@ast::pat] {
|
|
|
|
do field_paths.map |&path| {
|
|
|
|
build::mk_pat(cx, span,
|
|
|
|
ast::pat_ident(ast::bind_by_ref(mutbl), path, None))
|
2012-12-10 21:04:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
#[deriving(Eq)] // dogfooding!
|
|
|
|
enum StructType {
|
|
|
|
Unknown, Record, Tuple
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_struct_pattern(cx: @ext_ctxt,
|
|
|
|
span: span,
|
|
|
|
struct_ident: ident,
|
|
|
|
struct_def: &struct_def,
|
2013-05-02 08:16:07 +00:00
|
|
|
prefix: &str,
|
2013-05-06 15:23:51 +00:00
|
|
|
mutbl: ast::mutability)
|
|
|
|
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
|
|
|
|
if struct_def.fields.is_empty() {
|
|
|
|
return (
|
|
|
|
build::mk_pat_ident_with_binding_mode(
|
|
|
|
cx, span, struct_ident, ast::bind_infer),
|
|
|
|
~[]);
|
|
|
|
}
|
|
|
|
|
|
|
|
let matching_path = build::mk_raw_path(span, ~[ struct_ident ]);
|
|
|
|
|
|
|
|
let mut paths = ~[], ident_expr = ~[];
|
|
|
|
|
|
|
|
let mut struct_type = Unknown;
|
|
|
|
|
|
|
|
for struct_def.fields.eachi |i, struct_field| {
|
|
|
|
let opt_id = match struct_field.node.kind {
|
2013-05-08 16:03:31 +00:00
|
|
|
ast::named_field(ident, _) if (struct_type == Unknown ||
|
|
|
|
struct_type == Record) => {
|
2013-05-06 15:23:51 +00:00
|
|
|
struct_type = Record;
|
|
|
|
Some(ident)
|
|
|
|
}
|
|
|
|
ast::unnamed_field if (struct_type == Unknown ||
|
|
|
|
struct_type == Tuple) => {
|
|
|
|
struct_type = Tuple;
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let path = build::mk_raw_path(span,
|
|
|
|
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
|
|
|
|
paths.push(path);
|
|
|
|
ident_expr.push((opt_id, build::mk_path_raw(cx, span, path)));
|
|
|
|
}
|
|
|
|
|
|
|
|
let subpats = create_subpatterns(cx, span, paths, mutbl);
|
|
|
|
|
|
|
|
// struct_type is definitely not Unknown, since struct_def.fields
|
|
|
|
// must be nonempty to reach here
|
|
|
|
let pattern = if struct_type == Record {
|
|
|
|
let field_pats = do vec::build |push| {
|
|
|
|
for vec::each2(subpats, ident_expr) |&pat, &(id, _)| {
|
|
|
|
// id is guaranteed to be Some
|
|
|
|
push(ast::field_pat { ident: id.get(), pat: pat })
|
|
|
|
}
|
|
|
|
};
|
|
|
|
build::mk_pat_struct(cx, span, matching_path, field_pats)
|
|
|
|
} else {
|
|
|
|
build::mk_pat_enum(cx, span, matching_path, subpats)
|
|
|
|
};
|
|
|
|
|
|
|
|
(pattern, ident_expr)
|
2013-03-04 23:33:05 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn create_enum_variant_pattern(cx: @ext_ctxt,
|
2013-05-06 15:23:51 +00:00
|
|
|
span: span,
|
|
|
|
variant: &ast::variant,
|
2013-05-02 08:16:07 +00:00
|
|
|
prefix: &str,
|
2013-05-06 15:23:51 +00:00
|
|
|
mutbl: ast::mutability)
|
|
|
|
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
|
|
|
|
|
2012-11-20 20:59:37 +00:00
|
|
|
let variant_ident = variant.node.name;
|
|
|
|
match variant.node.kind {
|
2013-05-06 15:23:51 +00:00
|
|
|
ast::tuple_variant_kind(ref variant_args) => {
|
|
|
|
if variant_args.is_empty() {
|
|
|
|
return (build::mk_pat_ident_with_binding_mode(
|
|
|
|
cx, span, variant_ident, ast::bind_infer), ~[]);
|
2012-11-20 20:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
|
2012-12-10 21:04:04 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
let mut paths = ~[], ident_expr = ~[];
|
|
|
|
for uint::range(0, variant_args.len()) |i| {
|
|
|
|
let path = build::mk_raw_path(span,
|
|
|
|
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
|
2012-12-10 21:04:04 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
paths.push(path);
|
|
|
|
ident_expr.push((None, build::mk_path_raw(cx, span, path)));
|
|
|
|
}
|
2012-11-20 20:59:37 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
let subpats = create_subpatterns(cx, span, paths, mutbl);
|
2012-11-20 20:59:37 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
(build::mk_pat_enum(cx, span, matching_path, subpats),
|
|
|
|
ident_expr)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
ast::struct_variant_kind(struct_def) => {
|
|
|
|
create_struct_pattern(cx, span,
|
|
|
|
variant_ident, struct_def,
|
|
|
|
prefix,
|
|
|
|
mutbl)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &ast::variant) -> uint {
|
|
|
|
match variant.node.kind {
|
|
|
|
ast::tuple_variant_kind(ref args) => args.len(),
|
|
|
|
ast::struct_variant_kind(ref struct_def) => struct_def.fields.len(),
|
|
|
|
}
|
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2013-03-19 12:52:10 +00:00
|
|
|
pub fn expand_enum_or_struct_match(cx: @ext_ctxt,
|
2013-03-04 23:33:05 +00:00
|
|
|
span: span,
|
|
|
|
arms: ~[ ast::arm ])
|
|
|
|
-> @expr {
|
2013-05-10 22:15:06 +00:00
|
|
|
let self_expr = build::make_self(cx, span);
|
2013-05-06 15:23:51 +00:00
|
|
|
let self_expr = build::mk_unary(cx, span, ast::deref, self_expr);
|
|
|
|
let self_match_expr = ast::expr_match(self_expr, arms);
|
2013-03-04 23:33:05 +00:00
|
|
|
build::mk_expr(cx, span, self_match_expr)
|
|
|
|
}
|