Extract variant info from ast dump

This commit is contained in:
David Tolnay 2021-04-22 13:20:48 -07:00
parent cacfa023a4
commit 8a893c79ed
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
2 changed files with 106 additions and 4 deletions

View File

@ -1,5 +1,8 @@
use crate::syntax::attrs::OtherAttrs;
use crate::syntax::namespace::Namespace;
use crate::syntax::report::Errors;
use crate::syntax::Api;
use crate::syntax::{Api, Doc, Enum, ForeignName, Pair, Variant};
use proc_macro2::Ident;
use serde::Deserialize;
use std::env;
use std::fs;
@ -11,11 +14,29 @@ type Node = clang_ast::Node<Clang>;
#[derive(Deserialize)]
enum Clang {
NamespaceDecl(NamespaceDecl),
EnumDecl(EnumDecl),
EnumConstantDecl(EnumConstantDecl),
Unknown,
}
#[derive(Deserialize)]
struct NamespaceDecl {
name: Option<String>,
}
#[derive(Deserialize)]
struct EnumDecl {
name: Option<String>,
}
#[derive(Deserialize)]
struct EnumConstantDecl {
name: String,
}
pub fn load(cx: &mut Errors, apis: &mut [Api]) {
let mut variants_from_header = Vec::new();
let ref mut variants_from_header = Vec::new();
for api in apis {
if let Api::Enum(enm) = api {
if enm.variants_from_header {
@ -48,7 +69,7 @@ pub fn load(cx: &mut Errors, apis: &mut [Api]) {
}
};
let root: Node = match serde_json::from_slice(&ast_dump_bytes) {
let ref root: Node = match serde_json::from_slice(&ast_dump_bytes) {
Ok(root) => root,
Err(error) => {
let msg = format!("failed to read {}: {}", ast_dump_path.display(), error);
@ -56,5 +77,80 @@ pub fn load(cx: &mut Errors, apis: &mut [Api]) {
}
};
unimplemented!()
let ref mut namespace = Vec::new();
traverse(root, namespace, variants_from_header, None);
}
fn traverse<'a>(
node: &'a Node,
namespace: &mut Vec<&'a str>,
variants_from_header: &mut [&mut Enum],
mut idx: Option<usize>,
) {
match &node.kind {
Clang::NamespaceDecl(decl) => {
let name = match &decl.name {
Some(name) => name,
// Can ignore enums inside an anonymous namespace.
None => return,
};
namespace.push(name);
idx = None;
}
Clang::EnumDecl(decl) => {
let name = match &decl.name {
Some(name) => name,
None => return,
};
idx = None;
for (i, enm) in variants_from_header.iter().enumerate() {
if enm.name.cxx == **name && enm.name.namespace.iter().eq(&*namespace) {
idx = Some(i);
break;
}
}
if idx.is_none() {
return;
}
}
Clang::EnumConstantDecl(decl) => {
if let Some(idx) = idx {
let enm = &mut *variants_from_header[idx];
let span = enm
.variants_from_header_attr
.as_ref()
.unwrap()
.path
.get_ident()
.unwrap()
.span();
let cxx_name = match ForeignName::parse(&decl.name, span) {
Ok(foreign_name) => foreign_name,
Err(_) => return,
};
let rust_name: Ident = match syn::parse_str(&decl.name) {
Ok(ident) => ident,
Err(_) => return,
};
enm.variants.push(Variant {
doc: Doc::new(),
attrs: OtherAttrs::none(),
name: Pair {
namespace: Namespace::ROOT,
cxx: cxx_name,
rust: rust_name,
},
discriminant: unimplemented!(),
expr: None,
});
}
}
_ => {}
}
for inner in &node.inner {
traverse(inner, namespace, variants_from_header, idx);
}
if let Clang::NamespaceDecl(_) = &node.kind {
let _ = namespace.pop().unwrap();
}
}

View File

@ -68,3 +68,9 @@ impl Display for ForeignName {
formatter.write_str(&self.text)
}
}
impl PartialEq<str> for ForeignName {
fn eq(&self, rhs: &str) -> bool {
self.text == rhs
}
}