use std::collections::BTreeMap;
use std::error::Error;
use crate::clang::{self, *};
use crate::Generator;
#[derive(Clone, Debug)]
pub struct Namespace {
pub children: BTreeMap<String, Namespace>,
pub typedefs: Vec<Typedef>,
pub records: Vec<Record>,
pub extern_records: Vec<ExternRecord>,
pub constants: Vec<Constant>,
}
impl Namespace {
pub fn new() -> Namespace {
Namespace {
children: BTreeMap::new(),
typedefs: Vec::new(),
records: Vec::new(),
extern_records: Vec::new(),
constants: Vec::new(),
}
}
fn sort(&mut self) {
self.typedefs.sort_by(|a, b| a.name.cmp(&b.name));
self.records.sort_by(|a, b| a.name.cmp(&b.name));
self.extern_records.sort_by(|a, b| a.name.cmp(&b.name));
self.constants.sort_by(|a, b| a.name.cmp(&b.name));
for typedef in &mut self.typedefs {
typedef.inner.sort();
}
for records in &mut self.records {
records.inner.sort();
}
for child in self.children.values_mut() {
child.sort();
}
}
pub fn parse(cursor: &Cursor, options: &Generator) -> Result<Namespace, Box<dyn Error>> {
let mut parser = Parser::new(options);
let mut namespace = Namespace::new();
cursor.visit_children(|cursor| parser.visit(&mut namespace, cursor))?;
namespace.sort();
Ok(namespace)
}
pub fn is_empty(&self) -> bool {
self.typedefs.is_empty()
&& self.records.is_empty()
&& self.constants.is_empty()
&& self.children.values().all(|child| child.is_empty())
}
}
#[derive(Clone, Debug)]
pub struct Typedef {
pub name: String,
pub type_: Type,
pub inner: Namespace,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum RecordKind {
Struct,
Union,
}
#[derive(Clone, Debug)]
pub struct Record {
pub name: String,
pub kind: RecordKind,
pub fields: Vec<Field>,
pub bases: Vec<Base>,
pub virtual_methods: Vec<Method>,
pub emit_interface_trait: bool,
pub inner: Namespace,
}
#[derive(Clone, Debug)]
pub struct ExternRecord {
pub name: String,
}
#[derive(Clone, Debug)]
pub struct Base {
pub name: String,
pub bases: Vec<Base>,
pub emit_interface_trait: bool,
}
#[derive(Clone, Debug)]
pub struct Field {
pub name: Option<String>,
pub type_: Type,
}
#[derive(Clone, Debug)]
pub struct Method {
pub name: String,
pub arguments: Vec<Argument>,
pub result_type: Type,
}
#[derive(Clone, Debug)]
pub struct Argument {
pub name: String,
pub type_: Type,
}
#[derive(Clone, Debug)]
pub struct Constant {
pub name: String,
pub type_: Type,
pub value: Value,
}
#[derive(Clone, Debug)]
pub enum Type {
Void,
Bool,
Char,
UChar,
UShort,
UInt,
ULong,
ULongLong,
SChar,
Short,
Int,
Long,
LongLong,
Unsigned(usize),
#[allow(unused)]
Signed(usize),
Float,
Double,
Pointer {
is_const: bool,
pointee: Box<Type>,
},
Reference {
is_const: bool,
pointee: Box<Type>,
},
Record(String),
UnnamedRecord(Record),
Typedef(String),
Array(usize, Box<Type>),
}
#[derive(Clone, Debug)]
pub enum Value {
Signed(i64),
Unsigned(u64),
Float(f64),
Str(String),
Other(String),
}
struct Parser<'a> {
options: &'a Generator,
}
impl<'a> Parser<'a> {
fn new(options: &'a Generator) -> Parser<'a> {
Parser { options }
}
fn visit(&mut self, namespace: &mut Namespace, cursor: &Cursor) -> Result<(), Box<dyn Error>> {
if cursor.is_in_system_header() {
return Ok(());
}
match cursor.kind() {
CursorKind::Namespace => {
if cursor.is_anonymous() {
return Ok(());
}
let name = cursor.name();
let name_str = name.to_str().unwrap();
if !namespace.children.contains_key(name_str) {
namespace
.children
.insert(name_str.to_string(), Namespace::new());
}
let child_namespace = namespace.children.get_mut(name_str).unwrap();
cursor.visit_children(|cursor| self.visit(child_namespace, cursor))?;
}
CursorKind::TypedefDecl | CursorKind::TypeAliasDecl => {
let typedef = cursor.type_().unwrap();
let name = typedef.typedef_name().unwrap();
let name_str = name.to_str().unwrap();
let canonical_name = self.canonical_name(cursor);
if self.options.skip_types.contains(&canonical_name) {
return Ok(());
}
let override_type = self.options.override_typedef_types.get(&canonical_name);
let type_ = if let Some(override_type) = override_type {
Type::Typedef(override_type.to_string())
} else {
self.parse_type(cursor.typedef_underlying_type().unwrap(), cursor.location())?
};
namespace.typedefs.push(Typedef {
name: name_str.to_string(),
type_,
inner: Namespace::new(),
});
}
CursorKind::EnumDecl => {
let name = cursor.name();
let name_str = name.to_str().unwrap();
let canonical_name = self.canonical_name(cursor);
if self.options.skip_types.contains(&canonical_name) {
return Ok(());
}
let int_type =
self.parse_type(cursor.enum_integer_type().unwrap(), cursor.location())?;
let constant_type = if cursor.is_anonymous() {
int_type.clone()
} else {
self.parse_type(cursor.type_().unwrap(), cursor.location())?
};
let canonical_type = cursor.enum_integer_type().unwrap().canonical_type();
let signed = match canonical_type.kind() {
TypeKind::Char_U
| TypeKind::UChar
| TypeKind::UShort
| TypeKind::UInt
| TypeKind::ULong
| TypeKind::ULongLong => false,
TypeKind::Char_S
| TypeKind::SChar
| TypeKind::Short
| TypeKind::Int
| TypeKind::Long
| TypeKind::LongLong => true,
_ => return Err(format!("unhandled enum type {:?}", int_type).into()),
};
let mut constants = Vec::new();
cursor.visit_children(|cursor| -> Result<(), Box<dyn Error>> {
match cursor.kind() {
CursorKind::EnumConstantDecl => {
let canonical_name = self.canonical_name(cursor);
let override_value =
self.options.override_constant_values.get(&canonical_name);
let value = if let Some(override_value) = override_value {
Value::Other(override_value.to_string())
} else if signed {
Value::Signed(cursor.enum_constant_value().unwrap())
} else {
Value::Unsigned(cursor.enum_constant_value_unsigned().unwrap())
};
let override_type =
self.options.override_constant_types.get(&canonical_name);
let type_ = if let Some(override_type) = override_type {
Type::Typedef(override_type.to_string())
} else {
constant_type.clone()
};
constants.push(Constant {
name: cursor.name().to_str().unwrap().to_string(),
type_,
value,
});
}
_ => {}
}
Ok(())
})?;
if cursor.is_anonymous() {
namespace.constants.extend(constants);
} else {
let mut inner = Namespace::new();
inner.constants.extend(constants);
let override_type = self.options.override_typedef_types.get(&canonical_name);
let type_ = if let Some(override_type) = override_type {
Type::Typedef(override_type.to_string())
} else {
int_type.clone()
};
namespace.typedefs.push(Typedef {
name: name_str.to_string(),
type_,
inner,
});
}
}
CursorKind::VarDecl => {
let type_ = cursor.type_().unwrap();
if type_.is_const() {
let canonical_name = self.canonical_name(cursor);
let override_value = self.options.override_constant_values.get(&canonical_name);
let value = if let Some(override_value) = override_value {
Some(Value::Other(override_value.to_string()))
} else {
let eval_result = cursor.evaluate();
match eval_result.kind() {
EvalResultKind::Int => {
if eval_result.is_unsigned_int() {
Some(Value::Unsigned(eval_result.as_unsigned()))
} else {
Some(Value::Signed(eval_result.as_long_long()))
}
}
EvalResultKind::Float => Some(Value::Float(eval_result.as_double())),
EvalResultKind::StrLiteral => Some(Value::Str(
eval_result.as_str().unwrap().to_str().unwrap().to_string(),
)),
EvalResultKind::Other => {
if let Some(parser) = &self.options.constant_parser {
let tokens = cursor.tokens();
let token_string_refs: Vec<StringRef> = (0..tokens.len())
.map(|i| tokens.get(i).unwrap().spelling())
.collect();
let token_strings: Vec<&str> = token_string_refs
.iter()
.map(|t| t.to_str().unwrap())
.collect();
parser(&token_strings).map(Value::Other)
} else {
None
}
}
}
};
if let Some(value) = value {
let override_type =
self.options.override_constant_types.get(&canonical_name);
let type_ = if let Some(override_type) = override_type {
Type::Typedef(override_type.to_string())
} else {
self.parse_type(type_, cursor.location())?
};
namespace.constants.push(Constant {
name: cursor.name().to_str().unwrap().to_string(),
type_,
value,
});
}
}
}
CursorKind::StructDecl | CursorKind::UnionDecl | CursorKind::ClassDecl => {
let name = cursor.name();
let name_str = name.to_str().unwrap();
let canonical_name = self.canonical_name(cursor);
if self.options.skip_types.contains(&canonical_name) {
return Ok(());
}
if cursor.is_definition() {
if !cursor.is_anonymous() {
let record = self.parse_record(cursor.type_().unwrap())?;
namespace.records.push(record);
}
} else if !cursor.has_definition() {
namespace.extern_records.push(ExternRecord {
name: name_str.to_string(),
});
}
}
_ => {}
}
Ok(())
}
fn parse_record(&mut self, record: clang::Type) -> Result<Record, Box<dyn Error>> {
let decl = record.declaration();
let name = decl.name().to_str().unwrap().to_string();
let kind = match decl.kind() {
CursorKind::StructDecl | CursorKind::ClassDecl => RecordKind::Struct,
CursorKind::UnionDecl => RecordKind::Union,
_ => unreachable!(),
};
let mut fields = Vec::new();
let mut virtual_methods = Vec::new();
decl.visit_children(|cursor| -> Result<(), Box<dyn Error>> {
match cursor.kind() {
CursorKind::FieldDecl | CursorKind::UnionDecl => {
let name = if cursor.is_anonymous() {
None
} else {
Some(cursor.name().to_str().unwrap().to_string())
};
let type_ = self.parse_type(cursor.type_().unwrap(), cursor.location())?;
fields.push(Field { name, type_ });
}
CursorKind::CxxMethod => {
if cursor.is_virtual() {
let mut arguments = Vec::new();
for i in 0..cursor.num_arguments().unwrap() {
let arg = cursor.argument(i).unwrap();
let arg_type = arg.type_().unwrap();
let canonical_type = arg_type.canonical_type();
let type_ = if canonical_type.kind() == TypeKind::ConstantArray {
let is_const = canonical_type.is_const();
let array_type = self.parse_type(arg_type, arg.location())?;
Type::Pointer {
is_const,
pointee: Box::new(array_type),
}
} else {
self.parse_type(arg_type, arg.location())?
};
arguments.push(Argument {
name: arg.name().to_str().unwrap().to_string(),
type_,
});
}
let result_type = self
.parse_type(cursor.result_type().unwrap(), cursor.location())
.unwrap();
virtual_methods.push(Method {
name: cursor.name().to_str().unwrap().to_string(),
arguments,
result_type,
});
}
}
_ => {}
}
Ok(())
})?;
let bases = self.collect_bases(&decl)?;
let canonical_name = self.canonical_name(&decl);
let emit_interface_trait = !self.options.skip_interface_traits.contains(&canonical_name);
let mut inner = Namespace::new();
decl.visit_children(|cursor| self.visit(&mut inner, cursor))?;
Ok(Record {
name,
kind,
fields,
bases,
virtual_methods,
emit_interface_trait,
inner,
})
}
fn collect_bases(&self, decl: &Cursor) -> Result<Vec<Base>, Box<dyn Error>> {
let mut bases = Vec::new();
decl.visit_children(|cursor| -> Result<(), Box<dyn Error>> {
if cursor.kind() == CursorKind::CxxBaseSpecifier {
let decl = cursor.type_().unwrap().declaration();
let name = decl.name();
let transitive_bases = self.collect_bases(&decl)?;
let canonical_name = self.canonical_name(&decl);
let emit_interface_trait =
!self.options.skip_interface_traits.contains(&canonical_name);
bases.push(Base {
name: name.to_str().unwrap().to_string(),
bases: transitive_bases,
emit_interface_trait,
});
}
Ok(())
})?;
Ok(bases)
}
fn parse_type(
&mut self,
type_: clang::Type,
location: Location,
) -> Result<Type, Box<dyn Error>> {
match type_.kind() {
TypeKind::Void => Ok(Type::Void),
TypeKind::Bool => Ok(Type::Bool),
TypeKind::Char_U | TypeKind::Char_S => Ok(Type::Char),
TypeKind::UChar => Ok(Type::UChar),
TypeKind::UShort => Ok(Type::UShort),
TypeKind::UInt => Ok(Type::UInt),
TypeKind::SChar => Ok(Type::SChar),
TypeKind::Char16 => Ok(Type::Unsigned(2)),
TypeKind::WChar => Ok(Type::Unsigned(type_.size())),
TypeKind::ULong => Ok(Type::ULong),
TypeKind::ULongLong => Ok(Type::ULongLong),
TypeKind::Short => Ok(Type::Short),
TypeKind::Int => Ok(Type::Int),
TypeKind::Long => Ok(Type::Long),
TypeKind::LongLong => Ok(Type::LongLong),
TypeKind::Float => Ok(Type::Float),
TypeKind::Double => Ok(Type::Double),
TypeKind::Pointer => {
let pointee = type_.pointee().unwrap();
Ok(Type::Pointer {
is_const: pointee.is_const(),
pointee: Box::new(self.parse_type(pointee, location)?),
})
}
TypeKind::LValueReference => {
let pointee = type_.pointee().unwrap();
Ok(Type::Reference {
is_const: pointee.is_const(),
pointee: Box::new(self.parse_type(pointee, location)?),
})
}
TypeKind::Record => {
let decl = type_.declaration();
if decl.is_anonymous() {
Ok(Type::UnnamedRecord(self.parse_record(type_)?))
} else {
let name = decl.name().to_str().unwrap().to_string();
Ok(Type::Record(name))
}
}
TypeKind::Enum => {
let decl = type_.declaration();
Ok(Type::Typedef(decl.name().to_str().unwrap().to_string()))
}
TypeKind::Typedef => {
let declaration = type_.declaration();
if declaration.is_in_system_header() {
match type_.typedef_name().unwrap().to_str().unwrap() {
"int8_t" => return Ok(Type::Signed(1)),
"int16_t" => return Ok(Type::Signed(2)),
"int32_t" => return Ok(Type::Signed(4)),
"int64_t" => return Ok(Type::Signed(8)),
"uint8_t" => return Ok(Type::Unsigned(1)),
"uint16_t" => return Ok(Type::Unsigned(2)),
"uint32_t" => return Ok(Type::Unsigned(4)),
"uint64_t" => return Ok(Type::Unsigned(8)),
_ => {}
}
}
let name = type_.typedef_name().unwrap().to_str().unwrap().to_string();
Ok(Type::Typedef(name))
}
TypeKind::ConstantArray => {
let size = type_.array_size().unwrap();
let element_type =
self.parse_type(type_.array_element_type().unwrap(), location)?;
Ok(Type::Array(size, Box::new(element_type)))
}
TypeKind::Elaborated => self.parse_type(type_.named_type().unwrap(), location),
_ => Err(format!(
"error at {location}: unhandled type kind {:?}",
type_.kind()
)
.into()),
}
}
fn canonical_name(&self, decl: &Cursor) -> String {
let mut components = Vec::new();
let mut parent = decl.semantic_parent();
while let Some(cursor) = parent.take() {
if cursor.is_translation_unit() {
break;
}
parent = cursor.semantic_parent();
components.push(cursor);
}
let mut result = String::new();
for cursor in components.into_iter().rev() {
if !cursor.is_anonymous() {
result.push_str(cursor.name().to_str().unwrap());
result.push_str("::");
}
}
result.push_str(decl.name().to_str().unwrap());
result
}
}