From bfb020fbb9e1f81c4459851194e5fc5e1df91156 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Sun, 19 Jan 2020 15:13:32 +0100 Subject: clang-parser: add support for enum --- src/parser/clang/entities.rs | 84 +++++++++++++++++++++++++++++++++++++++++++ src/parser/clang/parsing.rs | 86 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 168 insertions(+), 2 deletions(-) diff --git a/src/parser/clang/entities.rs b/src/parser/clang/entities.rs index 8da85d9..0e9305b 100644 --- a/src/parser/clang/entities.rs +++ b/src/parser/clang/entities.rs @@ -16,6 +16,8 @@ pub(super) enum ClangEntityKind { Struct(StructKind), Function(FunctionKind), Typedef, + Enum, + EnumConstant, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -47,6 +49,8 @@ impl ClangEntityKind { ClangEntityKind::Function(FunctionKind::Function) => "function", ClangEntityKind::Function(FunctionKind::Method) => "method", ClangEntityKind::Typedef => "typedef", + ClangEntityKind::Enum => "enum", + ClangEntityKind::EnumConstant => "enum-constant", } } @@ -60,6 +64,8 @@ impl ClangEntityKind { ClangEntityKind::Function(FunctionKind::Function) => "functions", ClangEntityKind::Function(FunctionKind::Method) => "methods", ClangEntityKind::Typedef => "typedefs", + ClangEntityKind::Enum => "enums", + ClangEntityKind::EnumConstant => "enum-constants", } } } @@ -89,6 +95,8 @@ impl TryFrom for ClangEntityKind { EntityKind::TypedefDecl | EntityKind::TypeAliasDecl | EntityKind::TypeAliasTemplateDecl => ClangEntityKind::Typedef, + EntityKind::EnumDecl => ClangEntityKind::Enum, + EntityKind::EnumConstantDecl => ClangEntityKind::EnumConstant, kind => return Err(TryFromEntityKindError(format!("{:?}", kind))), }) } @@ -118,6 +126,9 @@ pub(super) trait ClangEntity { fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap>> { None } + fn get_member_enums(&mut self) -> Option<&mut BTreeMap>> { + None + } } /* @@ -178,6 +189,15 @@ where } } +impl NamespaceParentManipulation for U +where + U: ClangEntity, +{ + fn get_members_mut(&mut self) -> Option<&mut BTreeMap>> { + self.get_member_enums() + } +} + fn entity_id(usr: Usr) -> EntityId { // This is a somewhat ugly workaround, because Pandoc parses markdown identifiers as alphanum // or one of "-_:.", which means Pandoc can't parse libclang's USRs in title ids and related. @@ -236,6 +256,7 @@ pub(super) struct Namespace { pub(super) member_structs: BTreeMap>, pub(super) member_functions: BTreeMap>, pub(super) member_typedefs: BTreeMap>, + pub(super) member_enums: BTreeMap>, } impl ClangEntity for Namespace { @@ -258,6 +279,9 @@ impl ClangEntity for Namespace { fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_typedefs) } + fn get_member_enums(&mut self) -> Option<&mut BTreeMap>> { + Some(&mut self.member_enums) + } } /* @@ -279,6 +303,8 @@ impl From for PartialEntity { append_children(&mut children, entity.member_structs); append_children(&mut children, entity.member_functions); append_children(&mut children, entity.member_typedefs); + append_children(&mut children, entity.member_enums); + PartialEntity { properties: Default::default(), children, @@ -328,6 +354,7 @@ pub(super) struct Struct { pub(super) member_structs: BTreeMap>, pub(super) member_functions: BTreeMap>, pub(super) member_typedefs: BTreeMap>, + pub(super) member_enums: BTreeMap>, } impl ClangEntity for Struct { @@ -347,6 +374,9 @@ impl ClangEntity for Struct { fn get_member_typedefs(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_typedefs) } + fn get_member_enums(&mut self) -> Option<&mut BTreeMap>> { + Some(&mut self.member_enums) + } } impl From for PartialEntity { @@ -356,6 +386,7 @@ impl From for PartialEntity { append_children(&mut children, entity.member_structs); append_children(&mut children, entity.member_functions); append_children(&mut children, entity.member_typedefs); + append_children(&mut children, entity.member_enums); PartialEntity { properties: Default::default(), @@ -455,3 +486,56 @@ impl From for PartialEntity { } } } + +#[derive(Debug, Clone)] +pub(super) struct Enum { + pub(super) underlying_type: String, + pub(super) constants: BTreeMap>, +} + +impl ClangEntity for Enum { + fn kind(&self) -> ClangEntityKind { + ClangEntityKind::Enum + } +} + +impl From for PartialEntity { + fn from(entity: Enum) -> Self { + let mut properties = Map::with_capacity(1); + properties.insert( + String::from("underlying-type"), + JSONValue::String(entity.underlying_type), + ); + + let mut children = Default::default(); + append_children(&mut children, entity.constants); + + PartialEntity { + properties, + children, + } + } +} + +#[derive(Debug, Clone)] +pub(super) struct EnumConstant { + pub(super) value: String, +} + +impl ClangEntity for EnumConstant { + fn kind(&self) -> ClangEntityKind { + ClangEntityKind::EnumConstant + } +} + +impl From for PartialEntity { + fn from(entity: EnumConstant) -> Self { + let mut properties = Map::with_capacity(1); + properties.insert(String::from("value"), JSONValue::String(entity.value)); + + PartialEntity { + properties, + children: Default::default(), + } + } +} diff --git a/src/parser/clang/parsing.rs b/src/parser/clang/parsing.rs index 1f1691f..251aefa 100644 --- a/src/parser/clang/parsing.rs +++ b/src/parser/clang/parsing.rs @@ -20,6 +20,7 @@ struct TopLevel { structs: BTreeMap>, functions: BTreeMap>, typedefs: BTreeMap>, + enums: BTreeMap>, } /* @@ -88,6 +89,10 @@ impl TopLevel { ClangEntityKind::Typedef => { &mut parent.get_member_typedefs()?.get_mut(&usr)?.entity } + ClangEntityKind::Enum => &mut parent.get_member_enums()?.get_mut(&usr)?.entity, + ClangEntityKind::EnumConstant => { + panic!("enum variant getting"); + } }) } else { Some(match path.get_kind().try_into().ok()? { @@ -96,6 +101,8 @@ impl TopLevel { ClangEntityKind::Struct(_) => &mut self.structs.get_mut(&usr)?.entity, ClangEntityKind::Function(_) => &mut self.functions.get_mut(&usr)?.entity, ClangEntityKind::Typedef => &mut self.typedefs.get_mut(&usr)?.entity, + ClangEntityKind::Enum => &mut self.enums.get_mut(&usr)?.entity, + ClangEntityKind::EnumConstant => panic!("enum variant getting"), }) } } @@ -191,6 +198,12 @@ impl TopLevelManipulation for TopLevel { } } +impl TopLevelManipulation for TopLevel { + fn insert_toplevel(&mut self, usr: Usr, entity: Described) { + self.enums.insert(usr, entity); + } +} + /* trait FromTopLevel: ClangEntity + Sized { fn from_toplevel<'a>(toplevel: &'a mut TopLevel, usr: &Usr) -> Option<&'a mut Described>; @@ -526,7 +539,10 @@ fn add_entity( ClangEntityKind::Function(_) => Described::::try_from(libclang_entity) .and_then(|function| toplevel.insert(libclang_entity, function)), ClangEntityKind::Typedef => Described::::try_from(libclang_entity) - .and_then(|function| toplevel.insert(libclang_entity, function)), + .and_then(|typedef| toplevel.insert(libclang_entity, typedef)), + ClangEntityKind::Enum => Described::::try_from(libclang_entity) + .and_then(|r#enum| toplevel.insert(libclang_entity, r#enum)), + ClangEntityKind::EnumConstant => panic!("Enum variant encountered not within an enum"), }; // TODO: check result @@ -611,6 +627,7 @@ impl<'a> TryFrom> for Namespace { member_structs: Default::default(), member_functions: Default::default(), member_typedefs: Default::default(), + member_enums: Default::default(), }) } } @@ -655,6 +672,7 @@ impl<'a> TryFrom> for Struct { let mut member_structs = BTreeMap::new(); let mut member_functions = BTreeMap::new(); let mut member_typedefs = BTreeMap::new(); + let mut member_enums = BTreeMap::new(); for child in entity.get_children() { trace!("Struct has child: {:?}", child); @@ -694,6 +712,12 @@ impl<'a> TryFrom> for Struct { .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; member_typedefs.insert(child_usr, Described::::try_from(child)?); } + Ok(ClangEntityKind::Enum) => { + let child_usr = child + .get_usr() + .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; + member_enums.insert(child_usr, Described::::try_from(child)?); + } Ok(other) => warn!("Unsupported child of struct {:?}: {:?}", other, child), Err(err) => info!("Error while parsing entity {:?}: {}", child, err), } @@ -715,6 +739,7 @@ impl<'a> TryFrom> for Struct { member_structs, member_variables, member_typedefs, + member_enums, }) } } @@ -768,7 +793,6 @@ impl<'a> TryFrom> for Typedef { } debug!("Parsing typedef: {:?}", entity); - // TODO: unwrap (and unwrap in other similar places too) let referee = entity .get_typedef_underlying_type() .ok_or_else(|| anyhow!("No underlying type"))? @@ -778,6 +802,64 @@ impl<'a> TryFrom> for Typedef { } } +impl<'a> TryFrom> for Enum { + type Error = Error; + + fn try_from(entity: clang::Entity) -> Result { + match entity.get_kind().try_into() { + Ok(ClangEntityKind::Enum) => {} + _ => panic!("Trying to parse a non-enum into a enum"), + } + debug!("Parsing enum: {:?}", entity); + + let underlying_type = entity + .get_enum_underlying_type() + .ok_or_else(|| anyhow!("No enum underlying type"))? + .get_display_name(); + + let mut constants = BTreeMap::new(); + for child in entity.get_children() { + trace!("Enum has child: {:?}", child); + match child.get_kind().try_into() { + Ok(ClangEntityKind::EnumConstant) => { + let child_usr = child + .get_usr() + .ok_or_else(|| anyhow!("no usr for: {:?}", child))?; + constants.insert(child_usr, Described::::try_from(child)?); + } + Ok(other) => warn!("Unsupported child of enum {:?}: {:?}", other, child), + Err(err) => info!("Error while parsing entity {:?}: {}", child, err), + } + } + + Ok(Enum { + underlying_type, + constants, + }) + } +} + +impl<'a> TryFrom> for EnumConstant { + type Error = Error; + + fn try_from(entity: clang::Entity) -> Result { + match entity.get_kind().try_into() { + Ok(ClangEntityKind::EnumConstant) => {} + _ => panic!("Trying to parse a non-enum constant into a enum constant"), + } + debug!("Parsing enum: {:?}", entity); + + let value = entity + .get_enum_constant_value() + .ok_or_else(|| anyhow!("No enum constant value"))?; + dbg!(value); + + Ok(EnumConstant { + value: String::from(""), + }) + } +} + fn get_description(entity: clang::Entity) -> Result { let name = entity .get_display_name() -- cgit v1.2.3