diff --git a/src/libstd/enums.rs b/src/libstd/enums.rs new file mode 100644 index 0000000000000..b911a1b095c73 --- /dev/null +++ b/src/libstd/enums.rs @@ -0,0 +1,19 @@ +// 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. + +//! Functions for enum types. + +use vec; + +/// Trait for enumerating all possible values in an enum +pub trait Enumerable { + /// Function to get all possible values of an enum + fn values() -> vec::Vec; +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 841a73fa01fcb..7ccac07f1d3c6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -176,6 +176,7 @@ pub mod unit; pub mod bool; pub mod char; pub mod tuple; +pub mod enums; pub mod slice; pub mod vec; diff --git a/src/libsyntax/ext/deriving/enumerable.rs b/src/libsyntax/ext/deriving/enumerable.rs new file mode 100644 index 0000000000000..872f9242aaa37 --- /dev/null +++ b/src/libsyntax/ext/deriving/enumerable.rs @@ -0,0 +1,99 @@ +// 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 ast::{MetaItem, Item, Expr}; +use codemap::Span; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use ext::deriving::generic::*; +use parse::token::InternedString; + +pub fn expand_deriving_enumerable(cx: &mut ExtCtxt, + span: Span, + mitem: @MetaItem, + item: @Item, + push: |@Item|) { + let self_vec_path = Path::new_(vec!("std", "vec", "Vec"), None, vec!(~Self), true); + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: Path::new(vec!("std", "enums", "Enumerable")), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: vec!( + MethodDef { + name: "values", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: Vec::new(), + ret_ty: Literal(self_vec_path), + attributes: attrs, + const_nonmatching: false, + combine_substructure: combine_substructure(|a, b, c| { + values_substructure(a, b, c) + }) + }) + }; + trait_def.expand(cx, mitem, item, push) +} + +fn values_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { + let vec_new_ident = vec!( + cx.ident_of("std"), + cx.ident_of("vec"), + cx.ident_of("Vec"), + cx.ident_of("new") + ); + + let mk_vec_new_expr = |span| cx.expr_call_global(span, vec_new_ident.clone(), vec!()); + let mk_vec_push_expr = |span, id, e| cx.expr_method_call(span, cx.expr_ident(span, id), cx.ident_of("push"), vec!(e)); + + return match *substr.fields { + StaticEnum(_, ref variants) => { + let ret_ident = cx.ident_of("ret"); + let mut stmts = vec!(cx.stmt_let(trait_span, true, ret_ident, mk_vec_new_expr(trait_span))); + let mut pushes = vec!(); + let mut clike = true; + + for &(ref ident, ref span, ref flds) in variants.iter() { + match *flds { + Unnamed(ref flds) => { + if flds.len() > 0 { + clike = false; + } else { + pushes.push(cx.stmt_expr(mk_vec_push_expr(*span, ret_ident, cx.expr_ident(*span, *ident)))); + } + } + Named(_) => { + clike = false; + } + } + } + + if !clike { + cx.span_err(trait_span, "`Enumerable` can only be derived for C-like enums"); + } else { + stmts.extend(pushes.move_iter()); + } + + let block = cx.block(trait_span, stmts, Some(cx.expr_ident(trait_span, ret_ident))); + + cx.expr_block(block) + } + StaticStruct(..) => { + cx.span_err(trait_span, "`Enumerable` can only be derived for enums, not structs"); + // let compilation continue + cx.expr_uint(trait_span, 0) + } + _ => cx.span_bug(trait_span, "Non-static method in `deriving(Enumerable)`") + }; +} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 5a980cb9de90b..c76c85d44666f 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -31,6 +31,7 @@ pub mod show; pub mod zero; pub mod default; pub mod primitive; +pub mod enumerable; #[path="cmp/eq.rs"] pub mod eq; @@ -88,6 +89,8 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt, "Zero" => expand!(zero::expand_deriving_zero), "Default" => expand!(default::expand_deriving_default), + "Enumerable" => expand!(enumerable::expand_deriving_enumerable), + "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive), ref tname => {