diff options
author | Jyun-Yan You <jyyou.tw@gmail.com> | 2016-01-13 19:02:07 +0800 |
---|---|---|
committer | Jyun-Yan You <jyyou.tw@gmail.com> | 2016-01-13 19:02:07 +0800 |
commit | b40786aadd73b291a059a77dbcd11f075eef91c0 (patch) | |
tree | 6914302a29d79532978006e0d3c67565820ffc2c | |
parent | 6e33fbe74de0c38c68658cc51c6d8fe584691367 (diff) | |
parent | 8bf4a40b4805a4743233855bad1d6506ce7d5492 (diff) |
Merge pull request #247 from nox/proper-enum
Translate C enums to Rust enums
-rw-r--r-- | src/gen.rs | 106 | ||||
-rw-r--r-- | tests/headers/enum.h | 9 | ||||
-rw-r--r-- | tests/headers/enum_dupe.h | 4 | ||||
-rw-r--r-- | tests/headers/enum_explicit_type.hpp | 14 | ||||
-rw-r--r-- | tests/headers/enum_negative.h | 4 | ||||
-rw-r--r-- | tests/headers/enum_packed.h | 14 | ||||
-rw-r--r-- | tests/support.rs | 3 | ||||
-rw-r--r-- | tests/test_enum.rs | 53 | ||||
-rw-r--r-- | tests/tests.rs | 1 |
9 files changed, 188 insertions, 20 deletions
@@ -14,6 +14,7 @@ use syntax::ext::quote::rt::ToTokens; use syntax::feature_gate::Features; use syntax::owned_slice::OwnedSlice; use syntax::parse; +use syntax::parse::token::InternedString; use syntax::attr::mk_attr_id; use syntax::ptr::P; use syntax::print::pprust::tts_to_string; @@ -211,8 +212,8 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) -> let mut e = ei.borrow_mut(); e.name = unnamed_name(&mut ctx, e.name.clone()); } - let e = ei.borrow().clone(); - defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, e.items).into_iter()) + let e = ei.borrow(); + defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, &e.items).into_iter()) }, GVar(vi) => { let v = vi.borrow(); @@ -476,8 +477,8 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, ty: &Type) -> Vec<P<ast::Item> let is_empty = ei.borrow().name.is_empty(); if is_empty { ei.borrow_mut().name = name.clone(); - let e = ei.borrow().clone(); - cenum_to_rs(ctx, name, e.kind, e.items) + let e = ei.borrow(); + cenum_to_rs(ctx, name, e.kind, &e.items) } else { vec!(mk_item(ctx, name, ty)) } @@ -555,7 +556,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, let id = rust_type_id(ctx, name.clone()); let struct_def = P(ast::Item { ident: ctx.ext_cx.ident_of(&id[..]), - attrs: vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx)), + attrs: vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false)), id: ast::DUMMY_NODE_ID, node: def, vis: ast::Public, @@ -637,7 +638,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com empty_generics() ); let union_id = rust_type_id(ctx, name.clone()); - let union_attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx)); + let union_attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false)); let union_def = mk_item(ctx, union_id, def, ast::Public, union_attrs); let union_impl = ast::ItemImpl( @@ -682,18 +683,80 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a }) } -fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, items: Vec<EnumItem>) -> Vec<P<ast::Item>> { - let ty = TInt(kind, Layout::zero()); - let ty_id = rust_type_id(ctx, name); - let ty_def = ctypedef_to_rs(ctx, ty_id, &ty); - let val_ty = cty_to_rs(ctx, &ty); - let mut def = ty_def; +fn enum_kind_to_rust_type_name(kind: IKind) -> &'static str { + match kind { + ISChar => "i8", + IUChar => "u8", + IShort => "i16", + IUShort => "u16", + IInt => "i32", + IUInt => "u32", + ILong => "i64", + IULong => "u64", + _ => unreachable!(), + } +} + +fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, enum_items: &[EnumItem]) + -> Vec<P<ast::Item>> { + let enum_name = ctx.ext_cx.ident_of(&name); + let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name); + + let mut variants = vec![]; + let mut found_values = HashMap::new(); + let mut items = vec![]; + + for item in enum_items { + let name = ctx.ext_cx.ident_of(&item.name); + + if let Some(orig) = found_values.get(&item.val) { + let value = ctx.ext_cx.expr_path( + ctx.ext_cx.path(ctx.span, vec![enum_name, *orig])); + items.push(P(ast::Item { + ident: name, + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemConst(enum_ty.clone(), value), + vis: ast::Public, + span: ctx.span, + })); + continue; + } + + found_values.insert(item.val, name); + + let sign = ast::UnsuffixedIntLit(if item.val < 0 { ast::Minus } else { ast::Plus }); + let value = ctx.ext_cx.expr_lit(ctx.span, ast::LitInt(item.val.abs() as u64, sign)); - for it in items.iter() { - def.push(const_to_rs(ctx, it.name.clone(), it.val, val_ty.clone())); + variants.push(P(respan(ctx.span, ast::Variant_ { + name: name, + attrs: vec![], + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), + disr_expr: Some(value), + }))); } - return def; + let enum_repr = InternedString::new(enum_kind_to_rust_type_name(kind)); + + let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr); + let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]); + let repr_attr = respan(ctx.span, ast::Attribute_ { + id: mk_attr_id(), + style: ast::AttrStyle::Outer, + value: repr_list, + is_sugared_doc: false, + }); + + items.push(P(ast::Item { + ident: enum_name, + attrs: vec![mk_deriving_copy_attr(ctx, true), repr_attr], + id: ast::DUMMY_NODE_ID, + node: ast::ItemEnum(ast::EnumDef { variants: variants }, empty_generics()), + vis: ast::Public, + span: ctx.span, + })); + + items } /// Generates accessors for fields in nested structs and unions which must be @@ -848,11 +911,14 @@ fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute { }) } -fn mk_deriving_copy_attr(ctx: &mut GenCtx) -> ast::Attribute { - let attr_val = P(respan(ctx.span, ast::MetaList( - to_intern_str(ctx, "derive".to_string()), - vec!(P(respan(ctx.span, ast::MetaWord(to_intern_str(ctx, "Copy".to_string()))))) - ))); +fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute { + let mut words = vec!(); + if clone { + words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Clone"))); + } + words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Copy"))); + + let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words); respan(ctx.span, ast::Attribute_ { id: mk_attr_id(), diff --git a/tests/headers/enum.h b/tests/headers/enum.h new file mode 100644 index 00000000..f2d301e7 --- /dev/null +++ b/tests/headers/enum.h @@ -0,0 +1,9 @@ +enum Foo { + Bar = 0, + Qux +}; + +enum Neg { + MinusOne = -1, + One = 1, +}; diff --git a/tests/headers/enum_dupe.h b/tests/headers/enum_dupe.h new file mode 100644 index 00000000..6d3591d5 --- /dev/null +++ b/tests/headers/enum_dupe.h @@ -0,0 +1,4 @@ +enum Foo { + Bar = 1, + Dupe = 1 +}; diff --git a/tests/headers/enum_explicit_type.hpp b/tests/headers/enum_explicit_type.hpp new file mode 100644 index 00000000..6aa5103d --- /dev/null +++ b/tests/headers/enum_explicit_type.hpp @@ -0,0 +1,14 @@ +enum Foo: unsigned char { + Bar = 0, + Qux +}; + +enum Neg: char { + MinusOne = -1, + One = 1, +}; + +enum Bigger: unsigned short { + Much = 255, + Larger +}; diff --git a/tests/headers/enum_negative.h b/tests/headers/enum_negative.h new file mode 100644 index 00000000..6cbdfe04 --- /dev/null +++ b/tests/headers/enum_negative.h @@ -0,0 +1,4 @@ +enum Foo { + Bar = -2, + Qux = 1, +}; diff --git a/tests/headers/enum_packed.h b/tests/headers/enum_packed.h new file mode 100644 index 00000000..8654d110 --- /dev/null +++ b/tests/headers/enum_packed.h @@ -0,0 +1,14 @@ +enum __attribute__((packed)) Foo { + Bar = 0, + Qux +}; + +enum __attribute__((packed)) Neg { + MinusOne = -1, + One = 1, +}; + +enum __attribute__((packed)) Bigger { + Much = 255, + Larger +}; diff --git a/tests/support.rs b/tests/support.rs index dd414649..94cdf952 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -25,6 +25,9 @@ impl Logger for TestLogger { pub fn generate_bindings(filename: &str) -> Result<Vec<P<ast::Item>>, ()> { let mut options:BindgenOptions = Default::default(); + if filename.ends_with("hpp") { + options.clang_args.push("-std=c++11".to_string()); + } options.clang_args.push(filename.to_string()); let logger = TestLogger; diff --git a/tests/test_enum.rs b/tests/test_enum.rs new file mode 100644 index 00000000..2b94f3b4 --- /dev/null +++ b/tests/test_enum.rs @@ -0,0 +1,53 @@ +use support::assert_bind_eq; + +#[test] +fn with_simple_enum() { + assert_bind_eq("headers/enum.h", " + #[derive(Clone, Copy)] + #[repr(u32)] + pub enum Enum_Foo { Bar = 0, Qux = 1, } + #[derive(Clone, Copy)] + #[repr(i32)] + pub enum Enum_Neg { MinusOne = -1, One = 1, } + "); +} + +#[test] +fn with_packed_enums() { + assert_bind_eq("headers/enum_packed.h", " + #[derive(Clone, Copy)] + #[repr(u8)] + pub enum Enum_Foo { Bar = 0, Qux = 1, } + #[derive(Clone, Copy)] + #[repr(i8)] + pub enum Enum_Neg { MinusOne = -1, One = 1, } + #[derive(Clone, Copy)] + #[repr(u16)] + pub enum Enum_Bigger { Much = 255, Larger = 256, } + "); +} + +#[test] +fn with_duplicate_enum_value() { + assert_bind_eq("headers/enum_dupe.h", " + pub const Dupe: Enum_Foo = Enum_Foo::Bar; + #[derive(Clone, Copy)] + #[repr(u32)] + pub enum Enum_Foo { Bar = 1, } + "); +} + +#[test] +fn with_explicitly_typed_cxx_enum() { + assert_bind_eq("headers/enum_explicit_type.hpp", " + #[derive(Clone, Copy)] + #[repr(u8)] + pub enum Enum_Foo { Bar = 0, Qux = 1, } + #[derive(Clone, Copy)] + #[repr(i8)] + pub enum Enum_Neg { MinusOne = -1, One = 1, } + #[derive(Clone, Copy)] + #[repr(u16)] + pub enum Enum_Bigger { Much = 255, Larger = 256, } + "); +} diff --git a/tests/tests.rs b/tests/tests.rs index b9a4f61c..ea9350f9 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -8,6 +8,7 @@ mod support; // Unused until we can generate code for tests //mod test_cmath; +mod test_enum; mod test_decl; mod test_func; mod test_struct; |