use std::vec;
use std::collections::{HashSet};
use std::str::{FromStr};
use super::{Entity, EntityKind, Type, TypeKind};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DefinitionValue {
Integer(bool, u64),
Real(f64),
}
impl DefinitionValue {
fn from_entity(entity: Entity) -> Option<DefinitionValue> {
let mut tokens = entity.get_range().unwrap().tokenize();
if tokens.last().map_or(false, |t| t.get_spelling() == "#") {
tokens.pop();
}
let (negated, number) = if tokens.len() == 2 {
(false, tokens[1].get_spelling())
} else if tokens.len() == 3 && tokens[1].get_spelling() == "-" {
(true, tokens[2].get_spelling())
} else {
return None;
};
if let Ok(integer) = u64::from_str(&number) {
Some(DefinitionValue::Integer(negated, integer))
} else if let Ok(real) = f64::from_str(&number) {
if negated {
Some(DefinitionValue::Real(-real))
} else {
Some(DefinitionValue::Real(real))
}
} else {
None
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Declaration<'tu> {
pub name: String,
pub entity: Entity<'tu>,
pub source: Option<Entity<'tu>>,
}
impl<'tu> Declaration<'tu> {
fn new(name: String, entity: Entity<'tu>, source: Option<Entity<'tu>>) -> Declaration<'tu> {
Declaration { name, entity, source }
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Definition<'tu> {
pub name: String,
pub value: DefinitionValue,
pub entity: Entity<'tu>,
}
impl<'tu> Definition<'tu> {
fn new(name: String, value: DefinitionValue, entity: Entity<'tu>) -> Definition<'tu> {
Definition { name, value, entity }
}
}
#[allow(missing_debug_implementations)]
pub struct Definitions<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Definitions<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Definitions<'tu> {
Definitions { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Definitions<'tu> {
type Item = Definition<'tu>;
fn next(&mut self) -> Option<Definition<'tu>> {
for entity in &mut self.entities {
if entity.get_kind() == EntityKind::MacroDefinition {
let name = entity.get_name().unwrap();
if !self.seen.contains(&name) {
if let Some(value) = DefinitionValue::from_entity(entity) {
self.seen.insert(name.clone());
return Some(Definition::new(name, value, entity));
}
}
}
}
None
}
}
#[allow(missing_debug_implementations)]
pub struct Enums<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Enums<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Enums<'tu> {
Enums { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Enums<'tu> {
type Item = Declaration<'tu>;
fn next(&mut self) -> Option<Declaration<'tu>> {
next(&mut self.entities, &mut self.seen, EntityKind::EnumDecl, "enum ")
}
}
#[allow(missing_debug_implementations)]
pub struct Functions<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Functions<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Functions<'tu> {
Functions { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Functions<'tu> {
type Item = Declaration<'tu>;
fn next(&mut self) -> Option<Declaration<'tu>> {
for entity in &mut self.entities {
if entity.get_kind() == EntityKind::FunctionDecl {
let name = entity.get_name().unwrap();
if !self.seen.contains(&name) {
self.seen.insert(name.clone());
return Some(Declaration::new(name, entity, None));
}
}
}
None
}
}
#[allow(missing_debug_implementations)]
pub struct Structs<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Structs<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Structs<'tu> {
Structs { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Structs<'tu> {
type Item = Declaration<'tu>;
fn next(&mut self) -> Option<Declaration<'tu>> {
next(&mut self.entities, &mut self.seen, EntityKind::StructDecl, "struct ")
}
}
#[allow(missing_debug_implementations)]
pub struct Typedefs<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Typedefs<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Typedefs<'tu> {
Typedefs { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Typedefs<'tu> {
type Item = Declaration<'tu>;
fn next(&mut self) -> Option<Declaration<'tu>> {
for entity in &mut self.entities {
if entity.get_kind() == EntityKind::TypedefDecl {
let name = entity.get_name().unwrap();
if !self.seen.contains(&name) {
let underlying = entity.get_typedef_underlying_type().unwrap();
let display = entity.get_type().unwrap().get_display_name();
let typedef = !is_elaborated(underlying) ||
underlying.get_result_type().is_some() ||
is_alias(underlying, &display);
if typedef {
self.seen.insert(name.clone());
return Some(Declaration::new(name, entity, None));
}
}
}
}
None
}
}
#[allow(missing_debug_implementations)]
pub struct Unions<'tu> {
entities: vec::IntoIter<Entity<'tu>>,
seen: HashSet<String>,
}
impl<'tu> Unions<'tu> {
fn new(entities: vec::IntoIter<Entity<'tu>>) -> Unions<'tu> {
Unions { entities, seen: HashSet::new() }
}
}
impl<'tu> Iterator for Unions<'tu> {
type Item = Declaration<'tu>;
fn next(&mut self) -> Option<Declaration<'tu>> {
next(&mut self.entities, &mut self.seen, EntityKind::UnionDecl, "union ")
}
}
fn is(type_: Type, prefix: &str) -> bool {
is_elaborated(type_) && type_.get_display_name().starts_with(prefix)
}
fn is_alias(type_: Type, name: &str) -> bool {
for prefix in &["enum ", "struct ", "union "] {
let display = type_.get_display_name();
if display.starts_with(prefix) && &display[prefix.len()..] != name {
return true;
}
}
false
}
fn is_elaborated(type_: Type) -> bool {
type_.is_elaborated().unwrap_or(type_.get_kind() == TypeKind::Unexposed)
}
fn next<'tu>(
entities: &mut vec::IntoIter<Entity<'tu>>,
seen: &mut HashSet<String>,
kind: EntityKind,
prefix: &str,
) -> Option<Declaration<'tu>> {
for entity in entities {
if entity.get_kind() == kind {
if let Some(name) = entity.get_name() {
if !seen.contains(&name) {
seen.insert(name);
if entity.get_child(0).is_some() {
return Some(Declaration::new(entity.get_name().unwrap(), entity, None));
}
}
}
} else if entity.get_kind() == EntityKind::TypedefDecl {
let underlying = entity.get_typedef_underlying_type().unwrap();
let name = entity.get_name().unwrap();
if is(underlying, prefix) && !seen.contains(&name) {
let declaration = underlying.get_declaration().unwrap();
let complete = declaration.get_type().map_or(false, |t| t.get_sizeof().is_ok());
let anonymous = declaration.get_display_name().is_none();
let same = entity.get_display_name() == declaration.get_display_name();
seen.insert(name);
if complete && (anonymous || same) {
let name = entity.get_name().unwrap();
return Some(Declaration::new(name, declaration, Some(entity)));
}
}
}
}
None
}
pub fn find_definitions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Definitions<'tu> {
Definitions::new(entities.into().into_iter())
}
pub fn find_enums<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Enums<'tu> {
Enums::new(entities.into().into_iter())
}
pub fn find_functions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Functions<'tu> {
Functions::new(entities.into().into_iter())
}
pub fn find_structs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Structs<'tu> {
Structs::new(entities.into().into_iter())
}
pub fn find_typedefs<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Typedefs<'tu> {
Typedefs::new(entities.into().into_iter())
}
pub fn find_unions<'tu, E: Into<Vec<Entity<'tu>>>>(entities: E) -> Unions<'tu> {
Unions::new(entities.into().into_iter())
}